diff --git a/.github/workflows/parse_api.yml b/.github/workflows/parse_api.yml
index e095e4a55..e25cde18b 100644
--- a/.github/workflows/parse_api.yml
+++ b/.github/workflows/parse_api.yml
@@ -22,7 +22,7 @@ jobs:
- name: Diff parse files
id: diff
run: |
- git add -N tools/rlparser
+ git add -N tools/rlparser/output
git diff --name-only --exit-code
continue-on-error: true
@@ -32,6 +32,6 @@ jobs:
set -x
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- git add tools/rlparser
+ git add tools/rlparser/output
git commit -m "rlparser: update raylib_api.* by CI"
git push
diff --git a/.gitignore b/.gitignore
index c92865956..67afa01ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,10 +62,15 @@ packages/
emsdk
# Ignore wasm data in examples/
+examples/**/*
+!examples/**/*.*
+!examples/**/*/
+examples/**/*.exe
examples/**/*.wasm
examples/**/*.data
examples/**/*.js
examples/**/*.html
+examples/**/logs/*
# Ignore files build by xcode
*.mode*v*
@@ -115,7 +120,8 @@ build-*/
docgen_tmp/
# Tools stuff
-tools/parser/raylib_parser
+tools/parser/rlparser.exe
+tools/parser/rlparser
tools/rexm/rexm.exe
tools/rexm/rexm
diff --git a/BINDINGS.md b/BINDINGS.md
index 7770f41c2..07f590d7d 100644
--- a/BINDINGS.md
+++ b/BINDINGS.md
@@ -29,8 +29,10 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [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 |
| [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 |
| [raylib-freebasic](https://github.com/WIITD/raylib-freebasic) | **5.0** | [FreeBASIC](https://www.freebasic.net) | MIT |
+| [raylib.f](https://github.com/cthulhuology/raylib.f) | **5.5** | [Forth](https://forth.com) | Zlib |
| [fortran-raylib](https://github.com/interkosmos/fortran-raylib) | **5.5** | [Fortran](https://fortran-lang.org) | ISC |
| [raylib-go](https://github.com/gen2brain/raylib-go) | **5.5** | [Go](https://golang.org) | Zlib |
| [raylib-guile](https://github.com/petelliott/raylib-guile) | **auto** | [Guile](https://www.gnu.org/software/guile) | Zlib |
diff --git a/CONVENTIONS.md b/CONVENTIONS.md
index 58cfa6270..86044193c 100644
--- a/CONVENTIONS.md
+++ b/CONVENTIONS.md
@@ -41,6 +41,7 @@ while (!WindowShouldClose())
}
+// Always use accumulators as `x++` instead of `++x`
for (int i = 0; i < NUM_VALUES; i++) printf("%i", i);
// Be careful with the switch formatting!
diff --git a/examples/Makefile b/examples/Makefile
index ef7cb5948..72df8571a 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -77,7 +77,7 @@ RAYLIB_SRC_PATH ?= ../src
# Locations of raylib.h and libraylib.a/libraylib.so
# NOTE: Those variables are only used for PLATFORM_OS: LINUX, BSD
-DESTDIR ?= /usr/local
+DESTDIR ?= /usr/local
RAYLIB_INCLUDE_PATH ?= $(DESTDIR)/include
RAYLIB_LIB_PATH ?= $(DESTDIR)/lib
@@ -231,7 +231,7 @@ endif
# -Wno-missing-braces ignore invalid warning (GCC bug 53119)
# -Wno-unused-value ignore unused return values of some functions (i.e. fread())
# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec
-CFLAGS = -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces -Wunused-result
+CFLAGS = -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces -Wno-unused-result
ifeq ($(BUILD_MODE),DEBUG)
CFLAGS += -g -D_DEBUG
@@ -486,7 +486,19 @@ endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
# Libraries for DRM compiling
# NOTE: Required packages: libasound2-dev (ALSA)
- LDLIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lgbm -ldrm -ldl -latomic
+ LDLIBS = -lraylib -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl -latomic
+ # TODO: Examples compilation does not define GRAPHICS, is it required?
+ #ifeq ($(GRAPHICS),GRAPHICS_API_OPENGL_ES2)
+ # LDLIBS += -lGLESv2 -lEGL
+ #endif
+endif
+ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32)
+ # Libraries for Windows desktop compilation
+ LDFLAGS += -L..\src
+ LDLIBS = -lraylib -lgdi32 -lwinmm -lshcore
+ ifneq ($(GRAPHICS),GRAPHICS_API_OPENGL_11_SOFTWARE)
+ LDLIBS += -lopengl32
+ endif
endif
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
# Libraries for web (HTML5) compiling
@@ -513,6 +525,7 @@ CORE = \
core/core_basic_screen_manager \
core/core_basic_window \
core/core_clipboard_text \
+ core/core_compute_hash \
core/core_custom_frame_control \
core/core_custom_logging \
core/core_delta_time \
@@ -539,6 +552,7 @@ CORE = \
core/core_storage_values \
core/core_text_file_loading \
core/core_undo_redo \
+ core/core_viewport_scaling \
core/core_vr_simulator \
core/core_window_flags \
core/core_window_letterbox \
@@ -562,14 +576,19 @@ SHAPES = \
shapes/shapes_following_eyes \
shapes/shapes_kaleidoscope \
shapes/shapes_lines_bezier \
+ shapes/shapes_lines_drawing \
shapes/shapes_logo_raylib \
shapes/shapes_logo_raylib_anim \
+ shapes/shapes_math_angle_rotation \
+ shapes/shapes_math_sine_cosine \
shapes/shapes_mouse_trail \
shapes/shapes_pie_chart \
shapes/shapes_rectangle_advanced \
shapes/shapes_rectangle_scaling \
shapes/shapes_recursive_tree \
shapes/shapes_ring_drawing \
+ shapes/shapes_rlgl_color_wheel \
+ shapes/shapes_rlgl_triangle \
shapes/shapes_rounded_rectangle_drawing \
shapes/shapes_simple_particles \
shapes/shapes_splines_drawing \
@@ -598,9 +617,11 @@ TEXTURES = \
textures/textures_particles_blending \
textures/textures_polygon_drawing \
textures/textures_raw_data \
+ textures/textures_screen_buffer \
textures/textures_sprite_animation \
textures/textures_sprite_button \
textures/textures_sprite_explosion \
+ textures/textures_sprite_stacking \
textures/textures_srcrec_dstrec \
textures/textures_textured_curve \
textures/textures_tiled_drawing \
@@ -631,6 +652,8 @@ MODELS = \
models/models_bone_socket \
models/models_box_collisions \
models/models_cubicmap_rendering \
+ models/models_decals \
+ models/models_directional_billboard \
models/models_first_person_maze \
models/models_geometric_shapes \
models/models_heightmap_rendering \
@@ -654,6 +677,7 @@ SHADERS = \
shaders/shaders_ascii_rendering \
shaders/shaders_basic_lighting \
shaders/shaders_basic_pbr \
+ shaders/shaders_color_correction \
shaders/shaders_custom_uniform \
shaders/shaders_deferred_rendering \
shaders/shaders_depth_rendering \
@@ -691,6 +715,7 @@ AUDIO = \
audio/audio_sound_loading \
audio/audio_sound_multi \
audio/audio_sound_positioning \
+ audio/audio_spectrum_visualizer \
audio/audio_stream_effects
OTHERS = \
diff --git a/examples/Makefile.Web b/examples/Makefile.Web
index 5d4f3ffab..431b2cad9 100644
--- a/examples/Makefile.Web
+++ b/examples/Makefile.Web
@@ -513,6 +513,7 @@ CORE = \
core/core_basic_screen_manager \
core/core_basic_window \
core/core_clipboard_text \
+ core/core_compute_hash \
core/core_custom_frame_control \
core/core_custom_logging \
core/core_delta_time \
@@ -539,6 +540,7 @@ CORE = \
core/core_storage_values \
core/core_text_file_loading \
core/core_undo_redo \
+ core/core_viewport_scaling \
core/core_vr_simulator \
core/core_window_flags \
core/core_window_letterbox \
@@ -562,14 +564,19 @@ SHAPES = \
shapes/shapes_following_eyes \
shapes/shapes_kaleidoscope \
shapes/shapes_lines_bezier \
+ shapes/shapes_lines_drawing \
shapes/shapes_logo_raylib \
shapes/shapes_logo_raylib_anim \
+ shapes/shapes_math_angle_rotation \
+ shapes/shapes_math_sine_cosine \
shapes/shapes_mouse_trail \
shapes/shapes_pie_chart \
shapes/shapes_rectangle_advanced \
shapes/shapes_rectangle_scaling \
shapes/shapes_recursive_tree \
shapes/shapes_ring_drawing \
+ shapes/shapes_rlgl_color_wheel \
+ shapes/shapes_rlgl_triangle \
shapes/shapes_rounded_rectangle_drawing \
shapes/shapes_simple_particles \
shapes/shapes_splines_drawing \
@@ -598,9 +605,11 @@ TEXTURES = \
textures/textures_particles_blending \
textures/textures_polygon_drawing \
textures/textures_raw_data \
+ textures/textures_screen_buffer \
textures/textures_sprite_animation \
textures/textures_sprite_button \
textures/textures_sprite_explosion \
+ textures/textures_sprite_stacking \
textures/textures_srcrec_dstrec \
textures/textures_textured_curve \
textures/textures_tiled_drawing \
@@ -631,6 +640,8 @@ MODELS = \
models/models_bone_socket \
models/models_box_collisions \
models/models_cubicmap_rendering \
+ models/models_decals \
+ models/models_directional_billboard \
models/models_first_person_maze \
models/models_geometric_shapes \
models/models_heightmap_rendering \
@@ -654,6 +665,7 @@ SHADERS = \
shaders/shaders_ascii_rendering \
shaders/shaders_basic_lighting \
shaders/shaders_basic_pbr \
+ shaders/shaders_color_correction \
shaders/shaders_custom_uniform \
shaders/shaders_deferred_rendering \
shaders/shaders_depth_rendering \
@@ -691,6 +703,7 @@ AUDIO = \
audio/audio_sound_loading \
audio/audio_sound_multi \
audio/audio_sound_positioning \
+ audio/audio_spectrum_visualizer \
audio/audio_stream_effects
# Default target entry
@@ -747,6 +760,9 @@ core/core_basic_window: core/core_basic_window.c
core/core_clipboard_text: core/core_clipboard_text.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+core/core_compute_hash: core/core_compute_hash.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
core/core_custom_frame_control: core/core_custom_frame_control.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@@ -828,6 +844,9 @@ core/core_text_file_loading: core/core_text_file_loading.c
core/core_undo_redo: core/core_undo_redo.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+core/core_viewport_scaling: core/core_viewport_scaling.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
core/core_vr_simulator: core/core_vr_simulator.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file core/resources/shaders/glsl100/distortion.fs@resources/shaders/glsl100/distortion.fs
@@ -893,12 +912,21 @@ shapes/shapes_kaleidoscope: shapes/shapes_kaleidoscope.c
shapes/shapes_lines_bezier: shapes/shapes_lines_bezier.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+shapes/shapes_lines_drawing: shapes/shapes_lines_drawing.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
shapes/shapes_logo_raylib: shapes/shapes_logo_raylib.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
shapes/shapes_logo_raylib_anim: shapes/shapes_logo_raylib_anim.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+shapes/shapes_math_angle_rotation: shapes/shapes_math_angle_rotation.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
+shapes/shapes_math_sine_cosine: shapes/shapes_math_sine_cosine.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
shapes/shapes_mouse_trail: shapes/shapes_mouse_trail.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@@ -917,6 +945,12 @@ shapes/shapes_recursive_tree: shapes/shapes_recursive_tree.c
shapes/shapes_ring_drawing: shapes/shapes_ring_drawing.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+shapes/shapes_rlgl_color_wheel: shapes/shapes_rlgl_color_wheel.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
+shapes/shapes_rlgl_triangle: shapes/shapes_rlgl_triangle.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
shapes/shapes_rounded_rectangle_drawing: shapes/shapes_rounded_rectangle_drawing.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@@ -952,7 +986,7 @@ textures/textures_blend_modes: textures/textures_blend_modes.c
textures/textures_bunnymark: textures/textures_bunnymark.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
- --preload-file textures/resources/wabbit_alpha.png@resources/wabbit_alpha.png
+ --preload-file textures/resources/raybunny.png@resources/raybunny.png
textures/textures_fog_of_war: textures/textures_fog_of_war.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@@ -1018,6 +1052,9 @@ textures/textures_raw_data: textures/textures_raw_data.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/fudesumi.raw@resources/fudesumi.raw
+textures/textures_screen_buffer: textures/textures_screen_buffer.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
textures/textures_sprite_animation: textures/textures_sprite_animation.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/scarfy.png@resources/scarfy.png
@@ -1032,6 +1069,10 @@ textures/textures_sprite_explosion: textures/textures_sprite_explosion.c
--preload-file textures/resources/boom.wav@resources/boom.wav \
--preload-file textures/resources/explosion.png@resources/explosion.png
+textures/textures_sprite_stacking: textures/textures_sprite_stacking.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
+ --preload-file textures/resources/booth.png@resources/booth.png
+
textures/textures_srcrec_dstrec: textures/textures_srcrec_dstrec.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/scarfy.png@resources/scarfy.png
@@ -1152,6 +1193,16 @@ models/models_cubicmap_rendering: models/models_cubicmap_rendering.c
--preload-file models/resources/cubicmap.png@resources/cubicmap.png \
--preload-file models/resources/cubicmap_atlas.png@resources/cubicmap_atlas.png
+models/models_decals: models/models_decals.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
+ --preload-file models/resources/models/obj/character.obj@resources/models/obj/character.obj \
+ --preload-file models/resources/models/obj/character_diffuse.png@resources/models/obj/character_diffuse.png \
+ --preload-file models/resources/raylib_logo.png@resources/raylib_logo.png
+
+models/models_directional_billboard: models/models_directional_billboard.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
+ --preload-file models/resources/skillbot.png@resources/skillbot.png
+
models/models_first_person_maze: models/models_first_person_maze.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file models/resources/cubicmap.png@resources/cubicmap.png \
@@ -1257,6 +1308,14 @@ shaders/shaders_basic_pbr: shaders/shaders_basic_pbr.c
--preload-file shaders/resources/road_mra.png@resources/road_mra.png \
--preload-file shaders/resources/road_n.png@resources/road_n.png
+shaders/shaders_color_correction: shaders/shaders_color_correction.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
+ --preload-file shaders/resources/parrots.png@resources/parrots.png \
+ --preload-file shaders/resources/cat.png@resources/cat.png \
+ --preload-file shaders/resources/mandrill.png@resources/mandrill.png \
+ --preload-file shaders/resources/fudesumi.png@resources/fudesumi.png \
+ --preload-file shaders/resources/shaders/glsl100/color_correction.fs@resources/shaders/glsl100/color_correction.fs
+
shaders/shaders_custom_uniform: shaders/shaders_custom_uniform.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file shaders/resources/models/barracks.obj@resources/models/barracks.obj \
@@ -1440,6 +1499,11 @@ audio/audio_sound_positioning: audio/audio_sound_positioning.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file audio/resources/coin.wav@resources/coin.wav
+audio/audio_spectrum_visualizer: audio/audio_spectrum_visualizer.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
+ --preload-file audio/resources/shaders/glsl100/fft.fs@resources/shaders/glsl100/fft.fs \
+ --preload-file audio/resources/country.mp3@resources/country.mp3
+
audio/audio_stream_effects: audio/audio_stream_effects.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file audio/resources/country.mp3@resources/country.mp3
diff --git a/examples/README.md b/examples/README.md
index 19d110344..77b6ff37e 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -17,11 +17,11 @@ 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: 187]
+## EXAMPLES COLLECTION [TOTAL: 200]
-### category: core [45]
+### category: core [47]
-Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality.
+Examples using raylib [core](../src/rcore.c) module platform functionality: window creation, inputs, drawing modes and system functionality.
| example | image | difficulty
level | version
created | last version
updated | original
developer |
|-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
@@ -43,7 +43,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c
| [core_3d_camera_free](core/core_3d_camera_free.c) |
| ⭐☆☆☆ | 1.3 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_3d_camera_first_person](core/core_3d_camera_first_person.c) |
| ⭐⭐☆☆ | 1.3 | 1.3 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_3d_camera_split_screen](core/core_3d_camera_split_screen.c) |
| ⭐⭐⭐☆ | 3.7 | 4.0 | [Jeffery Myers](https://github.com/JeffM2501) |
-| [core_3d_camera_fps](core/core_3d_camera_fps.c) |
| ⭐⭐⭐☆ | 5.5 | 5.5 | [Agnis Aldins](https://github.com/nezvers) |
+| [core_3d_camera_fps](core/core_3d_camera_fps.c) |
| ⭐⭐⭐☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) |
| [core_3d_picking](core/core_3d_picking.c) |
| ⭐⭐☆☆ | 1.3 | 4.0 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_world_screen](core/core_world_screen.c) |
| ⭐⭐☆☆ | 1.3 | 1.4 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_window_flags](core/core_window_flags.c) |
| ⭐⭐⭐☆ | 3.5 | 3.5 | [Ramon Santamaria](https://github.com/raysan5) |
@@ -64,14 +64,16 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c
| [core_high_dpi](core/core_high_dpi.c) |
| ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) |
| [core_render_texture](core/core_render_texture.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_undo_redo](core/core_undo_redo.c) |
| ⭐⭐⭐☆ | 5.5 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) |
+| [core_viewport_scaling](core/core_viewport_scaling.c) |
| ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) |
| [core_input_actions](core/core_input_actions.c) |
| ⭐⭐☆☆ | 5.5 | 5.6 | [Jett](https://github.com/JettMonstersGoBoom) |
| [core_directory_files](core/core_directory_files.c) |
| ⭐☆☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) |
| [core_highdpi_testbed](core/core_highdpi_testbed.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
-| [core_screen_recording](core/core_screen_recording.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
-| [core_clipboard_text](core/core_clipboard_text.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) |
+| [core_screen_recording](core/core_screen_recording.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
+| [core_clipboard_text](core/core_clipboard_text.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ananth S](https://github.com/Ananth1839) |
| [core_text_file_loading](core/core_text_file_loading.c) |
| ⭐☆☆☆ | 5.5 | 5.6 | [Aanjishnu Bhattacharyya](https://github.com/NimComPoo-04) |
+| [core_compute_hash](core/core_compute_hash.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
-### category: shapes [31]
+### category: shapes [36]
Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module.
@@ -105,11 +107,16 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes](
| [shapes_pie_chart](shapes/shapes_pie_chart.c) |
| ⭐⭐⭐☆ | 5.5 | 5.6 | [Gideon Serfontein](https://github.com/GideonSerf) |
| [shapes_kaleidoscope](shapes/shapes_kaleidoscope.c) |
| ⭐⭐☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) |
| [shapes_clock_of_clocks](shapes/shapes_clock_of_clocks.c) |
| ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
+| [shapes_math_sine_cosine](shapes/shapes_math_sine_cosine.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) |
| [shapes_mouse_trail](shapes/shapes_mouse_trail.c) |
| ⭐☆☆☆ | 5.6 | 5.6-dev | [Balamurugan R](https://github.com/Bala050814) |
| [shapes_simple_particles](shapes/shapes_simple_particles.c) |
| ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
| [shapes_starfield_effect](shapes/shapes_starfield_effect.c) |
| ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
+| [shapes_lines_drawing](shapes/shapes_lines_drawing.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6 | [Robin](https://github.com/RobinsAviary) |
+| [shapes_math_angle_rotation](shapes/shapes_math_angle_rotation.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6 | [Kris](https://github.com/krispy-snacc) |
+| [shapes_rlgl_color_wheel](shapes/shapes_rlgl_color_wheel.c) |
| ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) |
+| [shapes_rlgl_triangle](shapes/shapes_rlgl_triangle.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) |
-### category: textures [26]
+### category: textures [28]
Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/rtextures.c) module.
@@ -140,7 +147,9 @@ Examples using raylib textures functionality, including image/textures loading/g
| [textures_image_kernel](textures/textures_image_kernel.c) |
| ⭐⭐⭐⭐️ | 1.3 | 1.3 | [Karim Salem](https://github.com/kimo-s) |
| [textures_image_channel](textures/textures_image_channel.c) |
| ⭐⭐☆☆ | 5.5 | 5.5 | [Bruno Cabral](https://github.com/brccabral) |
| [textures_image_rotate](textures/textures_image_rotate.c) |
| ⭐⭐☆☆ | 1.0 | 1.0 | [Ramon Santamaria](https://github.com/raysan5) |
+| [textures_screen_buffer](textures/textures_screen_buffer.c) |
| ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) |
| [textures_textured_curve](textures/textures_textured_curve.c) |
| ⭐⭐⭐☆ | 4.5 | 4.5 | [Jeffery Myers](https://github.com/JeffM2501) |
+| [textures_sprite_stacking](textures/textures_sprite_stacking.c) |
| ⭐⭐☆☆ | 5.6-dev | 6.0 | [Robin](https://github.com/RobinsAviary) |
### category: text [15]
@@ -164,7 +173,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat
| [text_inline_styling](text/text_inline_styling.c) |
| ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Wagner Barongello](https://github.com/SultansOfCode) |
| [text_words_alignment](text/text_words_alignment.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
-### category: models [25]
+### category: models [27]
Examples using raylib models functionality, including models loading/generation and drawing, provided by raylib [models](../src/rmodels.c) module.
@@ -195,8 +204,10 @@ Examples using raylib models functionality, including models loading/generation
| [models_tesseract_view](models/models_tesseract_view.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Timothy van der Valk](https://github.com/arceryz) |
| [models_basic_voxel](models/models_basic_voxel.c) |
| ⭐⭐☆☆ | 5.5 | 5.5 | [Tim Little](https://github.com/timlittle) |
| [models_rotating_cube](models/models_rotating_cube.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) |
+| [models_decals](models/models_decals.c) |
| ⭐⭐⭐⭐️ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
+| [models_directional_billboard](models/models_directional_billboard.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6 | [Robin](https://github.com/RobinsAviary) |
-### category: shaders [31]
+### category: shaders [32]
Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.c) module.
@@ -214,6 +225,8 @@ Examples using raylib shaders functionality, including shaders loading, paramete
| [shaders_texture_outline](shaders/shaders_texture_outline.c) |
| ⭐⭐⭐☆ | 4.0 | 4.0 | [Serenity Skiff](https://github.com/GoldenThumbs) |
| [shaders_texture_waves](shaders/shaders_texture_waves.c) |
| ⭐⭐☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) |
| [shaders_julia_set](shaders/shaders_julia_set.c) |
| ⭐⭐⭐☆ | 2.5 | 4.0 | [Josh Colclough](https://github.com/joshcol9232) |
+| [shaders_mandelbrot_set](shaders/shaders_mandelbrot_set.c) |
| ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
+| [shaders_color_correction](shaders/shaders_color_correction.c) |
| ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
| [shaders_eratosthenes_sieve](shaders/shaders_eratosthenes_sieve.c) |
| ⭐⭐⭐☆ | 2.5 | 4.0 | [ProfJski](https://github.com/ProfJski) |
| [shaders_fog_rendering](shaders/shaders_fog_rendering.c) |
| ⭐⭐⭐☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
| [shaders_simple_mask](shaders/shaders_simple_mask.c) |
| ⭐⭐☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
@@ -232,9 +245,8 @@ Examples using raylib shaders functionality, including shaders loading, paramete
| [shaders_lightmap_rendering](shaders/shaders_lightmap_rendering.c) |
| ⭐⭐⭐☆ | 4.5 | 4.5 | [Jussi Viitala](https://github.com/nullstare) |
| [shaders_rounded_rectangle](shaders/shaders_rounded_rectangle.c) |
| ⭐⭐⭐☆ | 5.5 | 5.5 | [Anstro Pleuton](https://github.com/anstropleuton) |
| [shaders_depth_rendering](shaders/shaders_depth_rendering.c) |
| ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Luís Almeida](https://github.com/luis605) |
-| [shaders_mandelbrot_set](shaders/shaders_mandelbrot_set.c) |
| ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
-### category: audio [8]
+### category: audio [9]
Examples using raylib audio functionality, including sound/music loading and playing. This functionality is provided by raylib [raudio](../src/raudio.c) module. Note this module can be used standalone independently of raylib.
@@ -248,6 +260,7 @@ Examples using raylib audio functionality, including sound/music loading and pla
| [audio_stream_effects](audio/audio_stream_effects.c) |
| ⭐⭐⭐⭐️ | 4.2 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) |
| [audio_sound_multi](audio/audio_sound_multi.c) |
| ⭐⭐☆☆ | 5.0 | 5.0 | [Jeffery Myers](https://github.com/JeffM2501) |
| [audio_sound_positioning](audio/audio_sound_positioning.c) |
| ⭐⭐☆☆ | 5.5 | 5.5 | [Le Juez Victor](https://github.com/Bigfoot71) |
+| [audio_spectrum_visualizer](audio/audio_spectrum_visualizer.c) |
| ⭐⭐⭐☆ | 6.0 | 5.6-dev | [IANN](https://github.com/meisei4) |
### category: others [6]
@@ -263,4 +276,4 @@ Examples showing raylib misc functionality that does not fit in other categories
| [web_basic_window](others/web_basic_window.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
Some example missing? As always, contributions are welcome, feel free to send new examples!
-Here is an[examples template](examples_template.c) with instructions to start with!
+Here is an [examples template](examples_template.c) with instructions to start with!
diff --git a/examples/audio/audio_music_stream.c b/examples/audio/audio_music_stream.c
index 48be49e42..05ec1c2d6 100644
--- a/examples/audio/audio_music_stream.c
+++ b/examples/audio/audio_music_stream.c
@@ -36,6 +36,12 @@ int main(void)
float timePlayed = 0.0f; // Time played normalized [0.0f..1.0f]
bool pause = false; // Music playing paused
+ float pan = 0.0f; // Default audio pan center [-1.0f..1.0f]
+ SetMusicPan(music, pan);
+
+ float volume = 0.8f; // Default audio volume [0.0f..1.0f]
+ SetMusicVolume(music, volume);
+
SetTargetFPS(30); // Set our game to run at 30 frames-per-second
//--------------------------------------------------------------------------------------
@@ -62,6 +68,34 @@ int main(void)
else ResumeMusicStream(music);
}
+ // Set audio pan
+ if (IsKeyDown(KEY_LEFT))
+ {
+ pan -= 0.05f;
+ if (pan < -1.0f) pan = -1.0f;
+ SetMusicPan(music, pan);
+ }
+ else if (IsKeyDown(KEY_RIGHT))
+ {
+ pan += 0.05f;
+ if (pan > 1.0f) pan = 1.0f;
+ SetMusicPan(music, pan);
+ }
+
+ // Set audio volume
+ if (IsKeyDown(KEY_DOWN))
+ {
+ volume -= 0.05f;
+ if (volume < 0.0f) volume = 0.0f;
+ SetMusicVolume(music, volume);
+ }
+ else if (IsKeyDown(KEY_UP))
+ {
+ volume += 0.05f;
+ if (volume > 1.0f) volume = 1.0f;
+ SetMusicVolume(music, volume);
+ }
+
// Get normalized time played for current music stream
timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music);
@@ -76,6 +110,11 @@ int main(void)
DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, LIGHTGRAY);
+ 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(200, 200, 400, 12, LIGHTGRAY);
DrawRectangle(200, 200, (int)(timePlayed*400.0f), 12, MAROON);
DrawRectangleLines(200, 200, 400, 12, GRAY);
@@ -83,6 +122,11 @@ int main(void)
DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, LIGHTGRAY);
DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, LIGHTGRAY);
+ 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);
+
EndDrawing();
//----------------------------------------------------------------------------------
}
diff --git a/examples/audio/audio_raw_stream.c b/examples/audio/audio_raw_stream.c
index 4deae2090..b327e92af 100644
--- a/examples/audio/audio_raw_stream.c
+++ b/examples/audio/audio_raw_stream.c
@@ -166,7 +166,7 @@ int main(void)
memcpy(writeBuf + writeCursor, data + readCursor, writeLength*sizeof(short));
// Update cursors and loop audio
- readCursor = (readCursor + writeLength) % waveLength;
+ readCursor = (readCursor + writeLength)%waveLength;
writeCursor += writeLength;
}
diff --git a/examples/audio/audio_sound_positioning.c b/examples/audio/audio_sound_positioning.c
index 4d29954f6..34b15c07b 100644
--- a/examples/audio/audio_sound_positioning.c
+++ b/examples/audio/audio_sound_positioning.c
@@ -69,6 +69,7 @@ int main(void)
};
SetSoundPosition(camera, sound, spherePos, 20.0f);
+
if (!IsSoundPlaying(sound)) PlaySound(sound);
//----------------------------------------------------------------------------------
@@ -94,6 +95,8 @@ int main(void)
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
+
+ return 0;
}
//------------------------------------------------------------------------------------
diff --git a/examples/audio/audio_spectrum_visualizer.c b/examples/audio/audio_spectrum_visualizer.c
new file mode 100644
index 000000000..f5334c9cc
--- /dev/null
+++ b/examples/audio/audio_spectrum_visualizer.c
@@ -0,0 +1,285 @@
+/*******************************************************************************************
+*
+* raylib [audio] example - spectrum visualizer
+*
+* Example complexity rating: [★★★☆] 3/4
+*
+* Example originally created with raylib 6.0, last time updated with raylib 5.6-dev
+*
+* Inspired by Inigo Quilez's https://www.shadertoy.com/
+* Resources/specification: https://gist.github.com/soulthreads/2efe50da4be1fb5f7ab60ff14ca434b8
+*
+* Example created by created by IANN (@meisei4) 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 IANN (@meisei4)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+
+#include
+#include
+#include
+
+#if defined(PLATFORM_DESKTOP)
+ #define GLSL_VERSION 330
+#else // PLATFORM_ANDROID, PLATFORM_WEB
+ #define GLSL_VERSION 100
+#endif
+
+#define MONO 1
+#define SAMPLE_RATE 44100
+#define SAMPLE_RATE_F 44100.0f
+#define FFT_WINDOW_SIZE 1024
+#define BUFFER_SIZE 512
+#define PER_SAMPLE_BIT_DEPTH 16
+#define AUDIO_STREAM_RING_BUFFER_SIZE (FFT_WINDOW_SIZE*2)
+#define EFFECTIVE_SAMPLE_RATE (SAMPLE_RATE_F*0.5f)
+#define WINDOW_TIME ((double)FFT_WINDOW_SIZE/(double)EFFECTIVE_SAMPLE_RATE)
+#define FFT_HISTORICAL_SMOOTHING_DUR 2.0f
+#define MIN_DECIBELS (-100.0f) // https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/minDecibels
+#define MAX_DECIBELS (-30.0f) // https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/maxDecibels
+#define INVERSE_DECIBEL_RANGE (1.0f/(MAX_DECIBELS - MIN_DECIBELS))
+#define DB_TO_LINEAR_SCALE (20.0f/2.302585092994046f)
+#define SMOOTHING_TIME_CONSTANT 0.8f // https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/smoothingTimeConstant
+#define TEXTURE_HEIGHT 1
+#define FFT_ROW 0
+#define UNUSED_CHANNEL 0.0f
+
+typedef struct FFTComplex { float real, imaginary; } FFTComplex;
+
+typedef struct FFTData {
+ FFTComplex *spectrum;
+ FFTComplex *workBuffer;
+ float *prevMagnitudes;
+ float (*fftHistory)[BUFFER_SIZE];
+ int fftHistoryLen;
+ int historyPos;
+ double lastFftTime;
+ float tapbackPos;
+} FFTData;
+
+static void CaptureFrame(FFTData *fftData, const float *audioSamples);
+static void RenderFrame(const FFTData *fftData, Image *fftImage);
+static void CooleyTukeyFFTSlow(FFTComplex *spectrum, int n);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //----------------------------------------------------------------------------------- ---
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [audio] example - spectrum visualizer");
+
+ Image fftImage = GenImageColor(BUFFER_SIZE, TEXTURE_HEIGHT, WHITE);
+ Texture2D fftTexture = LoadTextureFromImage(fftImage);
+ RenderTexture2D bufferA = LoadRenderTexture(screenWidth, screenHeight);
+ Vector2 iResolution = { (float)screenWidth, (float)screenHeight };
+
+ Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/fft.fs", GLSL_VERSION));
+
+ int iResolutionLocation = GetShaderLocation(shader, "iResolution");
+ int iChannel0Location = GetShaderLocation(shader, "iChannel0");
+ SetShaderValue(shader, iResolutionLocation, &iResolution, SHADER_UNIFORM_VEC2);
+ SetShaderValueTexture(shader, iChannel0Location, fftTexture);
+
+ InitAudioDevice();
+ SetAudioStreamBufferSizeDefault(AUDIO_STREAM_RING_BUFFER_SIZE);
+
+ // WARNING: Memory out-of-bounds on PLATFORM_WEB
+ Wave wav = LoadWave("resources/country.mp3");
+ WaveFormat(&wav, SAMPLE_RATE, PER_SAMPLE_BIT_DEPTH, MONO);
+
+ AudioStream audioStream = LoadAudioStream(SAMPLE_RATE, PER_SAMPLE_BIT_DEPTH, MONO);
+ PlayAudioStream(audioStream);
+
+ int fftHistoryLen = (int)ceilf(FFT_HISTORICAL_SMOOTHING_DUR/WINDOW_TIME) + 1;
+
+ FFTData fft = {
+ .spectrum = RL_CALLOC(sizeof(FFTComplex), FFT_WINDOW_SIZE),
+ .workBuffer = RL_CALLOC(sizeof(FFTComplex), FFT_WINDOW_SIZE),
+ .prevMagnitudes = RL_CALLOC(BUFFER_SIZE, sizeof(float)),
+ .fftHistory = RL_CALLOC(fftHistoryLen, sizeof(float[BUFFER_SIZE])),
+ .fftHistoryLen = fftHistoryLen,
+ .historyPos = 0,
+ .lastFftTime = 0.0,
+ .tapbackPos = 0.01f
+ };
+
+ size_t wavCursor = 0;
+ const short *wavPCM16 = wav.data;
+
+ short chunkSamples[AUDIO_STREAM_RING_BUFFER_SIZE] = { 0 };
+ float audioSamples[FFT_WINDOW_SIZE] = { 0 };
+
+ SetTargetFPS(60);
+ //----------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ while (IsAudioStreamProcessed(audioStream))
+ {
+ for (int i = 0; i < AUDIO_STREAM_RING_BUFFER_SIZE; i++)
+ {
+ int left = (wav.channels == 2)? wavPCM16[wavCursor*2 + 0] : wavPCM16[wavCursor];
+ int right = (wav.channels == 2)? wavPCM16[wavCursor*2 + 1] : left;
+ chunkSamples[i] = (short)((left + right)/2);
+
+ if (++wavCursor >= wav.frameCount) wavCursor = 0;
+ }
+
+ UpdateAudioStream(audioStream, chunkSamples, AUDIO_STREAM_RING_BUFFER_SIZE);
+
+ for (int i = 0; i < FFT_WINDOW_SIZE; i++) audioSamples[i] = (chunkSamples[i*2] + chunkSamples[i*2 + 1])*0.5f/32767.0f;
+ }
+
+ CaptureFrame(&fft, audioSamples);
+ RenderFrame(&fft, &fftImage);
+ UpdateTexture(fftTexture, fftImage.data);
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ BeginShaderMode(shader);
+ SetShaderValueTexture(shader, iChannel0Location, fftTexture);
+ DrawTextureRec(bufferA.texture,
+ (Rectangle){ 0, 0, (float)screenWidth, (float)-screenHeight },
+ (Vector2){ 0, 0 }, WHITE);
+ EndShaderMode();
+
+ EndDrawing();
+ //------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadShader(shader);
+ UnloadRenderTexture(bufferA);
+ UnloadTexture(fftTexture);
+ UnloadImage(fftImage);
+ UnloadAudioStream(audioStream);
+ UnloadWave(wav);
+ CloseAudioDevice();
+
+ RL_FREE(fft.spectrum);
+ RL_FREE(fft.workBuffer);
+ RL_FREE(fft.prevMagnitudes);
+ RL_FREE(fft.fftHistory);
+
+ CloseWindow(); // Close window and OpenGL context
+ //----------------------------------------------------------------------------------
+
+ return 0;
+}
+
+// Cooley–Tukey FFT https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm#Data_reordering,_bit_reversal,_and_in-place_algorithms
+static void CooleyTukeyFFTSlow(FFTComplex *spectrum, int n)
+{
+ int j = 0;
+ for (int i = 1; i < n - 1; i++)
+ {
+ int bit = n >> 1;
+ while (j >= bit)
+ {
+ j -= bit;
+ bit >>= 1;
+ }
+ j += bit;
+ if (i < j)
+ {
+ FFTComplex temp = spectrum[i];
+ spectrum[i] = spectrum[j];
+ spectrum[j] = temp;
+ }
+ }
+
+ for (int len = 2; len <= n; len <<= 1)
+ {
+ float angle = -2.0f*PI/len;
+ FFTComplex twiddleUnit = { cosf(angle), sinf(angle) };
+ for (int i = 0; i < n; i += len)
+ {
+ FFTComplex twiddleCurrent = { 1.0f, 0.0f };
+ for (int j = 0; j < len/2; j++)
+ {
+ FFTComplex even = spectrum[i + j];
+ FFTComplex odd = spectrum[i + j + len/2];
+ FFTComplex twiddledOdd = {
+ odd.real*twiddleCurrent.real - odd.imaginary*twiddleCurrent.imaginary,
+ odd.real*twiddleCurrent.imaginary + odd.imaginary*twiddleCurrent.real
+ };
+
+ spectrum[i + j].real = even.real + twiddledOdd.real;
+ spectrum[i + j].imaginary = even.imaginary + twiddledOdd.imaginary;
+ spectrum[i + j + len/2].real = even.real - twiddledOdd.real;
+ spectrum[i + j + len/2].imaginary = even.imaginary - twiddledOdd.imaginary;
+
+ float twiddleRealNext = twiddleCurrent.real*twiddleUnit.real - twiddleCurrent.imaginary*twiddleUnit.imaginary;
+ twiddleCurrent.imaginary = twiddleCurrent.real*twiddleUnit.imaginary + twiddleCurrent.imaginary*twiddleUnit.real;
+ twiddleCurrent.real = twiddleRealNext;
+ }
+ }
+ }
+}
+
+static void CaptureFrame(FFTData *fftData, const float *audioSamples)
+{
+ for (int i = 0; i < FFT_WINDOW_SIZE; i++)
+ {
+ float x = (2.0f*PI*i)/(FFT_WINDOW_SIZE - 1.0f);
+ float blackmanWeight = 0.42f - 0.5f*cosf(x) + 0.08f*cosf(2.0f*x); // https://en.wikipedia.org/wiki/Window_function#Blackman_window
+ fftData->workBuffer[i].real = audioSamples[i]*blackmanWeight;
+ fftData->workBuffer[i].imaginary = 0.0f;
+ }
+
+ CooleyTukeyFFTSlow(fftData->workBuffer, FFT_WINDOW_SIZE);
+ memcpy(fftData->spectrum, fftData->workBuffer, sizeof(FFTComplex)*FFT_WINDOW_SIZE);
+
+ float smoothedSpectrum[BUFFER_SIZE];
+
+ for (int bin = 0; bin < BUFFER_SIZE; bin++)
+ {
+ float re = fftData->workBuffer[bin].real;
+ float im = fftData->workBuffer[bin].imaginary;
+ float linearMagnitude = sqrtf(re*re + im*im)/FFT_WINDOW_SIZE;
+
+ float smoothedMagnitude = SMOOTHING_TIME_CONSTANT*fftData->prevMagnitudes[bin] + (1.0f - SMOOTHING_TIME_CONSTANT)*linearMagnitude;
+ fftData->prevMagnitudes[bin] = smoothedMagnitude;
+
+ float db = logf(fmaxf(smoothedMagnitude, 1e-40f))*DB_TO_LINEAR_SCALE;
+ float normalized = (db - MIN_DECIBELS)*INVERSE_DECIBEL_RANGE;
+ smoothedSpectrum[bin] = Clamp(normalized, 0.0f, 1.0f);
+ }
+
+ fftData->lastFftTime = GetTime();
+ memcpy(fftData->fftHistory[fftData->historyPos], smoothedSpectrum, sizeof(smoothedSpectrum));
+ fftData->historyPos = (fftData->historyPos + 1)%fftData->fftHistoryLen;
+}
+
+static void RenderFrame(const FFTData *fftData, Image *fftImage)
+{
+ double framesSinceTapback = floor(fftData->tapbackPos/WINDOW_TIME);
+ framesSinceTapback = Clamp(framesSinceTapback, 0.0, fftData->fftHistoryLen - 1);
+
+ int historyPosition = (fftData->historyPos - 1 - (int)framesSinceTapback)%fftData->fftHistoryLen;
+ if (historyPosition < 0) historyPosition += fftData->fftHistoryLen;
+
+ const float *amplitude = fftData->fftHistory[historyPosition];
+ for (int bin = 0; bin < BUFFER_SIZE; bin++) ImageDrawPixel(fftImage, bin, FFT_ROW, ColorFromNormalized((Vector4){ amplitude[bin], UNUSED_CHANNEL, UNUSED_CHANNEL, UNUSED_CHANNEL }));
+}
\ No newline at end of file
diff --git a/examples/audio/audio_spectrum_visualizer.png b/examples/audio/audio_spectrum_visualizer.png
new file mode 100644
index 000000000..c3f1bc8b0
Binary files /dev/null and b/examples/audio/audio_spectrum_visualizer.png differ
diff --git a/examples/audio/resources/shaders/glsl100/fft.fs b/examples/audio/resources/shaders/glsl100/fft.fs
new file mode 100644
index 000000000..a97bf336b
--- /dev/null
+++ b/examples/audio/resources/shaders/glsl100/fft.fs
@@ -0,0 +1,37 @@
+#version 100
+
+precision mediump float;
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform vec2 iResolution;
+uniform sampler2D iChannel0;
+
+const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0);
+const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0);
+const float FFT_ROW = 0.0;
+const float NUM_OF_BINS = 512.0;
+
+void main()
+{
+ vec2 fragCoord = fragTexCoord*iResolution;
+ float cellWidth = iResolution.x/NUM_OF_BINS;
+ float binIndex = floor(fragCoord.x/cellWidth);
+ float localX = mod(fragCoord.x, cellWidth);
+ float barWidth = cellWidth - 1.0;
+ vec4 color = WHITE;
+
+ if (localX <= barWidth)
+ {
+ float sampleX = (binIndex + 0.5)/NUM_OF_BINS;
+ vec2 sampleCoord = vec2(sampleX, FFT_ROW);
+ float amplitude = texture2D(iChannel0, sampleCoord).r; // Only filled the red channel, all channels left open for alternative use
+
+ if (fragTexCoord.y < amplitude) color = BLACK;
+ }
+
+ gl_FragColor = color;
+}
diff --git a/examples/audio/resources/shaders/glsl120/fft.fs b/examples/audio/resources/shaders/glsl120/fft.fs
new file mode 100644
index 000000000..bab5d533b
--- /dev/null
+++ b/examples/audio/resources/shaders/glsl120/fft.fs
@@ -0,0 +1,35 @@
+#version 120
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform vec2 iResolution;
+uniform sampler2D iChannel0;
+
+const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0);
+const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0);
+const float FFT_ROW = 0.0;
+const float NUM_OF_BINS = 512.0;
+
+void main()
+{
+ vec2 fragCoord = fragTexCoord*iResolution;
+ float cellWidth = iResolution.x/NUM_OF_BINS;
+ float binIndex = floor(fragCoord.x/cellWidth);
+ float localX = mod(fragCoord.x, cellWidth);
+ float barWidth = cellWidth - 1.0;
+ vec4 color = WHITE;
+
+ if (localX <= barWidth)
+ {
+ float sampleX = (binIndex + 0.5)/NUM_OF_BINS;
+ vec2 sampleCoord = vec2(sampleX, FFT_ROW);
+ float amplitude = texture2D(iChannel0, sampleCoord).r; // Only filled the red channel, all channels left open for alternative use
+
+ if (fragTexCoord.y < amplitude) color = BLACK;
+ }
+
+ gl_FragColor = color;
+}
diff --git a/examples/audio/resources/shaders/glsl330/fft.fs b/examples/audio/resources/shaders/glsl330/fft.fs
new file mode 100644
index 000000000..20b2e9dfa
--- /dev/null
+++ b/examples/audio/resources/shaders/glsl330/fft.fs
@@ -0,0 +1,35 @@
+#version 330
+
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+out vec4 finalColor;
+
+uniform vec2 iResolution;
+uniform sampler2D iChannel0;
+
+const vec4 BLACK = vec4(0.0, 0.0, 0.0, 1.0);
+const vec4 WHITE = vec4(1.0, 1.0, 1.0, 1.0);
+const float FFT_ROW = 0.0;
+const float NUM_OF_BINS = 512.0;
+
+void main()
+{
+ vec2 fragCoord = fragTexCoord*iResolution;
+ float cellWidth = iResolution.x/NUM_OF_BINS;
+ float binIndex = floor(fragCoord.x/cellWidth);
+ float localX = mod(fragCoord.x, cellWidth);
+ float barWidth = cellWidth - 1.0;
+ vec4 color = WHITE;
+
+ if (localX <= barWidth)
+ {
+ float sampleX = (binIndex + 0.5)/NUM_OF_BINS;
+ vec2 sampleCoord = vec2(sampleX, FFT_ROW);
+ float amplitude = texture(iChannel0, sampleCoord).r; // Only filled the red channel, all channels left open for alternative use
+
+ if (fragTexCoord.y < amplitude) color = BLACK;
+ }
+
+ finalColor = color;
+}
diff --git a/examples/core/core_2d_camera_mouse_zoom.c b/examples/core/core_2d_camera_mouse_zoom.c
index 6cb6dcfa2..9006afbe1 100644
--- a/examples/core/core_2d_camera_mouse_zoom.c
+++ b/examples/core/core_2d_camera_mouse_zoom.c
@@ -23,7 +23,7 @@
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
-int main ()
+int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
@@ -35,9 +35,9 @@ int main ()
Camera2D camera = { 0 };
camera.zoom = 1.0f;
- int zoomMode = 0; // 0-Mouse Wheel, 1-Mouse Move
+ int zoomMode = 0; // 0-Mouse Wheel, 1-Mouse Move
- SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
@@ -93,6 +93,7 @@ int main ()
// under the cursor to the screen space point under the cursor at any zoom
camera.target = mouseWorldPos;
}
+
if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
{
// Zoom increment
@@ -110,7 +111,6 @@ int main ()
ClearBackground(RAYWHITE);
BeginMode2D(camera);
-
// Draw the 3d grid, rotated 90 degrees and centered around 0,0
// just so we have something in the XY plane
rlPushMatrix();
@@ -121,7 +121,6 @@ int main ()
// Draw a reference circle
DrawCircle(GetScreenWidth()/2, GetScreenHeight()/2, 50, MAROON);
-
EndMode2D();
// Draw mouse reference
@@ -142,5 +141,6 @@ int main ()
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
+
return 0;
}
diff --git a/examples/core/core_3d_camera_fps.c b/examples/core/core_3d_camera_fps.c
index 7aa79c174..ef36e912f 100644
--- a/examples/core/core_3d_camera_fps.c
+++ b/examples/core/core_3d_camera_fps.c
@@ -6,12 +6,12 @@
*
* Example originally created with raylib 5.5, last time updated with raylib 5.5
*
-* Example contributed by Agnis Aldins (@nezvers) and reviewed by Ramon Santamaria (@raysan5)
+* Example contributed by Agnis Aldiņš (@nezvers) 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 Agnis Aldins (@nezvers)
+* Copyright (c) 2025 Agnis Aldiņš (@nezvers)
*
********************************************************************************************/
diff --git a/examples/core/core_clipboard_text.c b/examples/core/core_clipboard_text.c
index 2be64154b..2f8e5712b 100644
--- a/examples/core/core_clipboard_text.c
+++ b/examples/core/core_clipboard_text.c
@@ -2,22 +2,23 @@
*
* raylib [core] example - clipboard text
*
-* Example complexity rating: [★☆☆☆] 1/4
-*
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
*
-* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
+* Example contributed by Ananth S (@Ananth1839) 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 Robin (@RobinsAviary)
+* Copyright (c) 2025 Ananth S (@Ananth1839)
*
********************************************************************************************/
#include "raylib.h"
-#include
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"
+
+#define MAX_TEXT_SAMPLES 5
//------------------------------------------------------------------------------------
// Program main entry point
@@ -31,28 +32,32 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [core] example - clipboard text");
- const char* clipboardText = NULL;
+ // Define some sample texts
+ const char *sampleTexts[MAX_TEXT_SAMPLES] = {
+ "Hello from raylib!",
+ "The quick brown fox jumps over the lazy dog",
+ "Clipboard operations are useful!",
+ "raylib is a simple and easy-to-use library",
+ "Copy and paste me!"
+ };
- // List of text the user can switch through and copy
- const char* copyableText[] = {"raylib is fun", "hello, clipboard!", "potato chips"};
+ const char *clipboardText = NULL;
+ char inputBuffer[256] = "Hello from raylib!"; // Random initial string
- unsigned int textIndex = 0;
+ // UI required variables
+ bool textBoxEditMode = false;
- const char* popupText = NULL;
+ bool btnCutPressed = false;
+ bool btnCopyPressed = false;
+ bool btnPastePressed = false;
+ bool btnClearPressed = false;
+ bool btnRandomPressed = false;
- // Initialize timers
- // The amount of time the pop-up text is on screen, before fading
- const float maxTime = 3.0f;
- float textTimer = 0.0f;
- // The length of time text is offset
- const float animMaxTime = 0.1f;
- float pasteAnim = 0.0f;
- float copyAnim = 0.0f;
- int copyAnimMult = 1;
- float textAnim = 0.0f;
- float textAlpha = 0.0f;
- // Offset amount for animations
- const int offsetAmount = -4;
+ // Set UI style
+ GuiSetStyle(DEFAULT, TEXT_SIZE, 20);
+ GuiSetIconScale(2);
+
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
@@ -60,95 +65,55 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
- // Check if the user has pressed the copy/paste key combinations
- bool pastePressed = (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V));
- bool copyPressed = (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_C));
-
- // Update animation timers
- if (textTimer > 0) textTimer -= GetFrameTime();
- if (pasteAnim > 0) pasteAnim -= GetFrameTime();
- if (copyAnim > 0) copyAnim -= GetFrameTime();
- if (textAnim > 0) textAnim -= GetFrameTime();
-
- // React to the user pressing paste
- if (pastePressed)
+ // Handle button interactions
+ if (btnCutPressed)
{
- // Most operating systems hide this information until the user presses Ctrl-V on the window.
+ SetClipboardText(inputBuffer);
+ clipboardText = GetClipboardText();
+ inputBuffer[0] = '\0'; // Quick solution to clear text
+ //memset(inputBuffer, 0, 256); // Clear full buffer properly
+ }
- // Check to see if the clipboard contains an image
- // This function does nothing outside of Windows, as it directly calls the Windows API
- Image image = GetClipboardImage();
-
- if (IsImageValid(image))
+ if (btnCopyPressed)
+ {
+ SetClipboardText(inputBuffer); // Copy text to clipboard
+ clipboardText = GetClipboardText(); // Get text from clipboard
+ }
+
+ if (btnPastePressed)
+ {
+ // Paste text from clipboard
+ clipboardText = GetClipboardText();
+ if (clipboardText != NULL) TextCopy(inputBuffer, clipboardText);
+ }
+
+ if (btnClearPressed)
+ {
+ inputBuffer[0] = '\0'; // Quick solution to clear text
+ //memset(inputBuffer, 0, 256); // Clear full buffer properly
+ }
+
+ if (btnRandomPressed)
+ {
+ // Get random text from sample list
+ TextCopy(inputBuffer, sampleTexts[GetRandomValue(0, MAX_TEXT_SAMPLES - 1)]);
+ }
+
+ // Quick cut/copy/paste with keyboard shortcuts
+ if (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))
+ {
+ if (IsKeyPressed(KEY_X))
{
- // Unload the image
- UnloadImage(image);
- // Update visuals
- popupText = "clipboard contains image";
+ SetClipboardText(inputBuffer);
+ inputBuffer[0] = '\0'; // Quick solution to clear text
}
- else
+
+ if (IsKeyPressed(KEY_C)) SetClipboardText(inputBuffer);
+
+ if (IsKeyPressed(KEY_V))
{
- // Get text from the user's clipboard
clipboardText = GetClipboardText();
-
- // Update visuals
- popupText = "text pasted";
- pasteAnim = animMaxTime;
- }
-
- // Reset animation values
- textTimer = maxTime;
- textAnim = animMaxTime;
- textAlpha = 1;
- }
-
- // React to the user pressing copy
- if (copyPressed)
- {
- // Set the text on the user's clipboard
- SetClipboardText(copyableText[textIndex]);
-
- // Reset values
- textTimer = maxTime;
- textAnim = animMaxTime;
- copyAnim = animMaxTime;
- copyAnimMult = 1;
- textAlpha = 1;
- // Update the text that pops up at the bottom of the screen
- popupText = "text copied";
- }
-
- // Switch to the next item in the list when the user presses up
- if (IsKeyPressed(KEY_UP))
- {
- // Reset animation
- copyAnim = animMaxTime;
- copyAnimMult = 1;
-
- textIndex += 1;
-
- if (textIndex >= sizeof(copyableText) / sizeof(const char*)) // Length of array
- {
- // Loop back to the other end
- textIndex = 0;
- }
- }
-
- // Switch to the previous item in the list when the user presses down
- if (IsKeyPressed(KEY_DOWN))
- {
- // Reset animation
- copyAnim = animMaxTime;
- copyAnimMult = -1;
-
- if (textIndex == 0)
- {
- // Loop back to the other end
- textIndex = (sizeof(copyableText) / sizeof(const char*)) - 1; // Length of array minus one
- }
- else
- {
- textIndex -= 1;
+ if (clipboardText != NULL) TextCopy(inputBuffer, clipboardText);
}
}
//----------------------------------------------------------------------------------
@@ -157,43 +122,32 @@ int main(void)
//----------------------------------------------------------------------------------
BeginDrawing();
- ClearBackground(RAYWHITE);
+ ClearBackground(RAYWHITE);
- // Draw the user's pasted text, if there is any yet
- if (clipboardText)
- {
- // Offset animation
- int offset = 0;
- if (pasteAnim > 0) offset = offsetAmount;
+ // Draw instructions
+ GuiLabel((Rectangle){ 50, 20, 700, 36 }, "Use the BUTTONS or KEY SHORTCUTS:");
+ DrawText("[CTRL+X] - CUT | [CTRL+C] COPY | [CTRL+V] | PASTE", 50, 60, 20, MAROON);
- // Draw the pasted text
- DrawText("pasted clipboard:", 10, 10 + offset, 20, DARKGREEN);
- DrawText(clipboardText, 10, 30 + offset, 20, DARKGRAY);
- }
+ // Draw text box
+ if (GuiTextBox((Rectangle){ 50, 120, 652, 40 }, inputBuffer, 256, textBoxEditMode)) textBoxEditMode = !textBoxEditMode;
- // Offset animation
- int textOffset = 0;
- if (copyAnim > 0) textOffset = offsetAmount;
+ // Random text button
+ btnRandomPressed = GuiButton((Rectangle){ 50 + 652 + 8, 120, 40, 40 }, "#77#");
- // Draw copyable text and controls
- DrawText(copyableText[textIndex], 10, 330 + (textOffset * copyAnimMult), 20, MAROON);
- DrawText("up/down to change string, ctrl-c to copy, ctrl-v to paste", 10, 355, 20, DARKGRAY);
+ // Draw buttons
+ btnCutPressed = GuiButton((Rectangle){ 50, 180, 158, 40 }, "#17#CUT");
+ btnCopyPressed = GuiButton((Rectangle){ 50 + 165, 180, 158, 40 }, "#16#COPY");
+ btnPastePressed = GuiButton((Rectangle){ 50 + 165*2, 180, 158, 40 }, "#18#PASTE");
+ btnClearPressed = GuiButton((Rectangle){ 50 + 165*3, 180, 158, 40 }, "#143#CLEAR");
- // Alpha / Offset animation
- if (textAlpha > 0)
- {
- // Offset animation
- int offset = 0;
- if (textAnim > 0) offset = offsetAmount;
- // Draw pop up text
- DrawText(popupText, 10, 425 + offset, 20, ColorAlpha(DARKGREEN, textAlpha));
-
- // Fade-out animation
- if (textTimer < 0)
- {
- textAlpha -= GetFrameTime();
- }
- }
+ // Draw clipboard status
+ GuiSetState(STATE_DISABLED);
+ GuiLabel((Rectangle){ 50, 260, 700, 40 }, "Clipboard current text data:");
+ GuiSetStyle(TEXTBOX, TEXT_READONLY, 1);
+ GuiTextBox((Rectangle){ 50, 300, 700, 40 }, (char *)clipboardText, 256, false);
+ GuiSetStyle(TEXTBOX, TEXT_READONLY, 0);
+ GuiLabel((Rectangle){ 50, 360, 700, 40 }, "Try copying text from other applications and pasting here!");
+ GuiSetState(STATE_NORMAL);
EndDrawing();
//----------------------------------------------------------------------------------
@@ -205,4 +159,4 @@ int main(void)
//--------------------------------------------------------------------------------------
return 0;
-}
\ No newline at end of file
+}
diff --git a/examples/core/core_clipboard_text.png b/examples/core/core_clipboard_text.png
index caa9b314a..96a7379c7 100644
Binary files a/examples/core/core_clipboard_text.png and b/examples/core/core_clipboard_text.png differ
diff --git a/examples/core/core_compute_hash.c b/examples/core/core_compute_hash.c
new file mode 100644
index 000000000..505ffea7b
--- /dev/null
+++ b/examples/core/core_compute_hash.c
@@ -0,0 +1,143 @@
+/*******************************************************************************************
+*
+* raylib [core] example - compute hash
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*
+* 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 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+static char *GetDataAsHexText(const unsigned int *data, int dataSize);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [core] example - compute hash");
+
+ // UI controls variables
+ char textInput[96] = "The quick brown fox jumps over the lazy dog.";
+ bool textBoxEditMode = false;
+ bool btnComputeHashes = false;
+
+ // Data hash values
+ unsigned int hashCRC32 = 0;
+ unsigned int *hashMD5 = NULL;
+ unsigned int *hashSHA1 = NULL;
+ unsigned int *hashSHA256 = NULL;
+
+ // Base64 encoded data
+ char *base64Text = NULL;
+ int base64TextSize = 0;
+
+ SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ if (btnComputeHashes)
+ {
+ int textInputLen = strlen(textInput);
+
+ // Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
+ base64Text = EncodeDataBase64((unsigned char *)textInput, textInputLen, &base64TextSize);
+
+ hashCRC32 = ComputeCRC32((unsigned char *)textInput, textInputLen); // Compute CRC32 hash code (4 bytes)
+ hashMD5 = ComputeMD5((unsigned char *)textInput, textInputLen); // Compute MD5 hash code, returns static int[4] (16 bytes)
+ hashSHA1 = ComputeSHA1((unsigned char *)textInput, textInputLen); // Compute SHA1 hash code, returns static int[5] (20 bytes)
+ hashSHA256 = ComputeSHA256((unsigned char *)textInput, textInputLen); // Compute SHA256 hash code, returns static int[8] (32 bytes)
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ GuiSetStyle(DEFAULT, TEXT_SIZE, 20);
+ GuiSetStyle(DEFAULT, TEXT_SPACING, 2);
+ GuiLabel((Rectangle){ 40, 26, 720, 32 }, "INPUT DATA (TEXT):");
+ GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
+ GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
+
+ if (GuiTextBox((Rectangle){ 40, 64, 720, 32 }, textInput, 95, textBoxEditMode)) textBoxEditMode = !textBoxEditMode;
+
+ btnComputeHashes = GuiButton((Rectangle){ 40, 64 + 40, 720, 32 }, "COMPUTE INPUT DATA HASHES");
+
+ GuiSetStyle(DEFAULT, TEXT_SIZE, 20);
+ GuiSetStyle(DEFAULT, TEXT_SPACING, 2);
+ GuiLabel((Rectangle){ 40, 160, 720, 32 }, "INPUT DATA HASH VALUES:");
+ GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
+ GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
+
+ GuiSetStyle(TEXTBOX, TEXT_READONLY, 1);
+ GuiLabel((Rectangle){ 40, 200, 120, 32 }, "CRC32 [32 bit]:");
+ GuiTextBox((Rectangle){ 40 + 120, 200, 720 - 120, 32 }, GetDataAsHexText(&hashCRC32, 1), 120, false);
+ GuiLabel((Rectangle){ 40, 200 + 36, 120, 32 }, "MD5 [128 bit]:");
+ GuiTextBox((Rectangle){ 40 + 120, 200 + 36, 720 - 120, 32 }, GetDataAsHexText(hashMD5, 4), 120, false);
+ GuiLabel((Rectangle){ 40, 200 + 36*2, 120, 32 }, "SHA1 [160 bit]:");
+ GuiTextBox((Rectangle){ 40 + 120, 200 + 36*2, 720 - 120, 32 }, GetDataAsHexText(hashSHA1, 5), 120, false);
+ GuiLabel((Rectangle){ 40, 200 + 36*3, 120, 32 }, "SHA256 [256 bit]:");
+ GuiTextBox((Rectangle){ 40 + 120, 200 + 36*3, 720 - 120, 32 }, GetDataAsHexText(hashSHA256, 8), 120, false);
+
+ GuiSetState(STATE_FOCUSED);
+ GuiLabel((Rectangle){ 40, 200 + 36*5 - 30, 320, 32 }, "BONUS - BAS64 ENCODED STRING:");
+ GuiSetState(STATE_NORMAL);
+ GuiLabel((Rectangle){ 40, 200 + 36*5, 120, 32 }, "BASE64 ENCODING:");
+ GuiTextBox((Rectangle){ 40 + 120, 200 + 36*5, 720 - 120, 32 }, base64Text, 120, false);
+ GuiSetStyle(TEXTBOX, TEXT_READONLY, 0);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ MemFree(base64Text); // Free Base64 text data
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+static char *GetDataAsHexText(const unsigned int *data, int dataSize)
+{
+ static char text[128] = { 0 };
+ memset(text, 0, 128);
+
+ if ((data != NULL) && (dataSize > 0) && (dataSize < ((128/8) - 1)))
+ {
+ for (int i = 0; i < dataSize; i++) TextCopy(text + i*8, TextFormat("%08X", data[i]));
+ }
+ else TextCopy(text, "00000000");
+
+ return text;
+}
diff --git a/examples/core/core_compute_hash.png b/examples/core/core_compute_hash.png
new file mode 100644
index 000000000..19a5d0b1c
Binary files /dev/null and b/examples/core/core_compute_hash.png differ
diff --git a/examples/core/core_custom_logging.c b/examples/core/core_custom_logging.c
index 5ea2a4762..b1e7ee989 100644
--- a/examples/core/core_custom_logging.c
+++ b/examples/core/core_custom_logging.c
@@ -17,11 +17,11 @@
#include "raylib.h"
-#include // Required for: fopen(), fclose(), fputc(), fwrite(), printf(), fprintf(), funopen()
-#include // Required for: time_t, tm, time(), localtime(), strftime()
+#include // Required for: printf(), vprintf(), fprintf()
+#include // Required for: time_t, tm, time(), localtime(), strftime()
// Custom logging function
-void CustomLog(int msgType, const char *text, va_list args)
+void CustomTraceLog(int msgType, const char *text, va_list args)
{
char timeStr[64] = { 0 };
time_t now = time(NULL);
@@ -54,7 +54,7 @@ int main(void)
const int screenHeight = 450;
// Set custom logger
- SetTraceLogCallback(CustomLog);
+ SetTraceLogCallback(CustomTraceLog);
InitWindow(screenWidth, screenHeight, "raylib [core] example - custom logging");
diff --git a/examples/core/core_delta_time.c b/examples/core/core_delta_time.c
index e52c743da..b77957ed6 100644
--- a/examples/core/core_delta_time.c
+++ b/examples/core/core_delta_time.c
@@ -59,7 +59,7 @@ int main(void)
// GetFrameTime() returns the time it took to draw the last frame, in seconds (usually called delta time)
// Uses the delta time to make the circle look like it's moving at a "consistent" speed regardless of FPS
- // Multiply by 6.0 (an arbitrary value) in order to make the speed
+ // Multiply by 6.0 (an arbitrary value) in order to make the speed
// visually closer to the other circle (at 60 fps), for comparison
deltaCircle.x += GetFrameTime()*6.0f*speed;
// This circle can move faster or slower visually depending on the FPS
@@ -68,7 +68,7 @@ int main(void)
// If either circle is off the screen, reset it back to the start
if (deltaCircle.x > screenWidth) deltaCircle.x = 0;
if (frameCircle.x > screenWidth) frameCircle.x = 0;
-
+
// Reset both circles positions
if (IsKeyPressed(KEY_R))
{
diff --git a/examples/core/core_directory_files.c b/examples/core/core_directory_files.c
index b7e11b686..a98c950f6 100644
--- a/examples/core/core_directory_files.c
+++ b/examples/core/core_directory_files.c
@@ -20,9 +20,7 @@
#define RAYGUI_IMPLEMENTATION
#include "raygui.h" // Required for GUI controls
-#include // Required for: strcpy()
-
-#define MAX_FILEPATH_SIZE 2048
+#define MAX_FILEPATH_SIZE 1024
//------------------------------------------------------------------------------------
// Program main entry point
@@ -53,12 +51,10 @@ int main(void)
//----------------------------------------------------------------------------------
if (btnBackPressed)
{
- strcpy(directory, GetPrevDirectoryPath(directory));
+ TextCopy(directory, GetPrevDirectoryPath(directory));
UnloadDirectoryFiles(files);
files = LoadDirectoryFiles(directory);
}
-
-
//----------------------------------------------------------------------------------
// Draw
@@ -68,19 +64,20 @@ int main(void)
DrawText(directory, 100, 40, 20, DARKGRAY);
- btnBackPressed = GuiButton((Rectangle){ 40.0f, 40.0f, 20, 20 }, "<");
-
+ btnBackPressed = GuiButton((Rectangle){ 40.0f, 38.0f, 48, 24 }, "<");
+
for (int i = 0; i < (int)files.count; i++)
{
Color color = Fade(LIGHTGRAY, 0.3f);
- if (!IsPathFile(files.paths[i]))
+ if (!IsPathFile(files.paths[i]) && DirectoryExists(files.paths[i]))
{
if (GuiButton((Rectangle){0.0f, 85.0f + 40.0f*(float)i, screenWidth, 40}, ""))
{
- strcpy(directory, files.paths[i]);
+ TextCopy(directory, files.paths[i]);
UnloadDirectoryFiles(files);
files = LoadDirectoryFiles(directory);
+ continue;
}
}
diff --git a/examples/core/core_highdpi_testbed.c b/examples/core/core_highdpi_testbed.c
index 5cd2a7dc7..a341d081c 100644
--- a/examples/core/core_highdpi_testbed.c
+++ b/examples/core/core_highdpi_testbed.c
@@ -27,9 +27,10 @@ int main(void)
const int screenWidth = 800;
const int screenHeight = 450;
+ SetConfigFlags(FLAG_WINDOW_HIGHDPI | FLAG_WINDOW_RESIZABLE);
InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi testbed");
- // TODO: Load resources / Initialize variables at this point
+ int gridSpacing = 40; // Grid spacing in pixels
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
@@ -48,11 +49,12 @@ int main(void)
ClearBackground(RAYWHITE);
- // TODO: Draw everything that requires to be drawn at this point
+ // 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);
- DrawLineEx((Vector2){ 0, 0 }, (Vector2){ screenWidth, screenHeight }, 2.0f, RED);
- DrawLineEx((Vector2){ 0, screenHeight }, (Vector2){ screenWidth, 0 }, 2.0f, RED);
- DrawText("example base code template", 260, 400, 20, LIGHTGRAY);
+ // Draw UI info
+ DrawText(TextFormat("SCREEN SIZE: %ix%i", GetScreenWidth(), GetScreenHeight()), 10, 10, 20, BLACK);
EndDrawing();
//----------------------------------------------------------------------------------
diff --git a/examples/core/core_input_actions.c b/examples/core/core_input_actions.c
index aff356087..f4b1156d8 100644
--- a/examples/core/core_input_actions.c
+++ b/examples/core/core_input_actions.c
@@ -17,7 +17,7 @@
// Simple example for decoding input as actions, allowing remapping of input to different keys or gamepad buttons
// For example instead of using `IsKeyDown(KEY_LEFT)`, you can use `IsActionDown(ACTION_LEFT)`
-// which can be reassigned to e.g. KEY_A and also assigned to a gamepad button. the action will trigger with either gamepad or keys
+// which can be reassigned to e.g. KEY_A and also assigned to a gamepad button. the action will trigger with either gamepad or keys
#include "raylib.h"
@@ -44,7 +44,7 @@ typedef struct ActionInput {
// Global Variables Definition
//----------------------------------------------------------------------------------
static int gamepadIndex = 0; // Gamepad default index
-static ActionInput actionInputs[MAX_ACTION] = { 0 };
+static ActionInput actionInputs[MAX_ACTION] = { 0 };
//----------------------------------------------------------------------------------
// Module Functions Declaration
@@ -67,14 +67,15 @@ int main(void)
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - input actions");
-
- // Set default actions
+
+ // Set default actions
char actionSet = 0;
SetActionsDefault();
+ bool releaseAction = false;
Vector2 position = (Vector2){ 400.0f, 200.0f };
Vector2 size = (Vector2){ 40.0f, 40.0f };
-
+
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
@@ -83,7 +84,8 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
- gamepadIndex = 0; // set this to gamepad being checked
+ gamepadIndex = 0; // Set gamepad being checked
+
if (IsActionDown(ACTION_UP)) position.y -= 2;
if (IsActionDown(ACTION_DOWN)) position.y += 2;
if (IsActionDown(ACTION_LEFT)) position.x -= 2;
@@ -94,7 +96,11 @@ int main(void)
position.y = (screenHeight-size.y)/2;
}
- // Switch control scheme by pressing TAB
+ // Register release action for one frame
+ releaseAction = false;
+ if (IsActionReleased(ACTION_FIRE)) releaseAction = true;
+
+ // Switch control scheme by pressing TAB
if (IsKeyPressed(KEY_TAB))
{
actionSet = !actionSet;
@@ -109,8 +115,8 @@ int main(void)
ClearBackground(GRAY);
- DrawRectangleV(position, size, RED);
-
+ DrawRectangleV(position, size, releaseAction? BLUE : RED);
+
DrawText((actionSet == 0)? "Current input set: WASD (default)" : "Current input set: Cursor", 10, 10, 20, WHITE);
DrawText("Use TAB key to toggles Actions keyset", 10, 50, 20, GREEN);
@@ -134,9 +140,9 @@ int main(void)
static bool IsActionPressed(int action)
{
bool result = false;
-
+
if (action < MAX_ACTION) result = (IsKeyPressed(actionInputs[action].key) || IsGamepadButtonPressed(gamepadIndex, actionInputs[action].button));
-
+
return result;
}
@@ -145,20 +151,20 @@ static bool IsActionPressed(int action)
static bool IsActionReleased(int action)
{
bool result = false;
-
+
if (action < MAX_ACTION) result = (IsKeyReleased(actionInputs[action].key) || IsGamepadButtonReleased(gamepadIndex, actionInputs[action].button));
-
+
return result;
}
// Check action key/button down
// NOTE: Combines key down and gamepad button down in one action
-static bool IsActionDown(int action)
+static bool IsActionDown(int action)
{
bool result = false;
-
+
if (action < MAX_ACTION) result = (IsKeyDown(actionInputs[action].key) || IsGamepadButtonDown(gamepadIndex, actionInputs[action].button));
-
+
return result;
}
diff --git a/examples/core/core_input_gamepad.c b/examples/core/core_input_gamepad.c
index 1da1c4ce0..3c9454318 100644
--- a/examples/core/core_input_gamepad.c
+++ b/examples/core/core_input_gamepad.c
@@ -51,6 +51,8 @@ int main(void)
const float leftTriggerDeadzone = -0.9f;
const float rightTriggerDeadzone = -0.9f;
+ Rectangle vibrateButton = { 0 };
+
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
@@ -61,7 +63,12 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
- // ...
+ if (IsKeyPressed(KEY_LEFT) && gamepad > 0) gamepad--;
+ if (IsKeyPressed(KEY_RIGHT)) gamepad++;
+ Vector2 mousePosition = GetMousePosition();
+
+ vibrateButton = (Rectangle){ 10, 70 + 20*GetGamepadAxisCount(gamepad) + 20, 75, 24 };
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mousePosition, vibrateButton)) SetGamepadVibration(gamepad, 1.0, 1.0, 1.0);
//----------------------------------------------------------------------------------
// Draw
@@ -70,9 +77,6 @@ int main(void)
ClearBackground(RAYWHITE);
- if (IsKeyPressed(KEY_LEFT) && gamepad > 0) gamepad--;
- if (IsKeyPressed(KEY_RIGHT)) gamepad++;
-
if (IsGamepadAvailable(gamepad))
{
DrawText(TextFormat("GP%d: %s", gamepad, GetGamepadName(gamepad)), 10, 10, 10, BLACK);
@@ -93,7 +97,8 @@ int main(void)
if (leftTrigger < leftTriggerDeadzone) leftTrigger = -1.0f;
if (rightTrigger < rightTriggerDeadzone) rightTrigger = -1.0f;
- if (TextFindIndex(TextToLower(GetGamepadName(gamepad)), XBOX_ALIAS_1) > -1 || TextFindIndex(TextToLower(GetGamepadName(gamepad)), XBOX_ALIAS_2) > -1)
+ if ((TextFindIndex(TextToLower(GetGamepadName(gamepad)), XBOX_ALIAS_1) > -1) ||
+ (TextFindIndex(TextToLower(GetGamepadName(gamepad)), XBOX_ALIAS_2) > -1))
{
DrawTexture(texXboxPad, 0, 0, DARKGRAY);
@@ -125,16 +130,14 @@ int main(void)
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_LEFT_THUMB)) leftGamepadColor = RED;
DrawCircle(259, 152, 39, BLACK);
DrawCircle(259, 152, 34, LIGHTGRAY);
- DrawCircle(259 + (int)(leftStickX*20),
- 152 + (int)(leftStickY*20), 25, leftGamepadColor);
+ DrawCircle(259 + (int)(leftStickX*20), 152 + (int)(leftStickY*20), 25, leftGamepadColor);
// Draw axis: right joystick
Color rightGamepadColor = BLACK;
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_RIGHT_THUMB)) rightGamepadColor = RED;
DrawCircle(461, 237, 38, BLACK);
DrawCircle(461, 237, 33, LIGHTGRAY);
- DrawCircle(461 + (int)(rightStickX*20),
- 237 + (int)(rightStickY*20), 25, rightGamepadColor);
+ DrawCircle(461 + (int)(rightStickX*20), 237 + (int)(rightStickY*20), 25, rightGamepadColor);
// Draw axis: left-right triggers
DrawRectangle(170, 30, 15, 70, GRAY);
@@ -177,16 +180,14 @@ int main(void)
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_LEFT_THUMB)) leftGamepadColor = RED;
DrawCircle(319, 255, 35, BLACK);
DrawCircle(319, 255, 31, LIGHTGRAY);
- DrawCircle(319 + (int)(leftStickX*20),
- 255 + (int)(leftStickY*20), 25, leftGamepadColor);
+ DrawCircle(319 + (int)(leftStickX*20), 255 + (int)(leftStickY*20), 25, leftGamepadColor);
// Draw axis: right joystick
Color rightGamepadColor = BLACK;
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_RIGHT_THUMB)) rightGamepadColor = RED;
DrawCircle(475, 255, 35, BLACK);
DrawCircle(475, 255, 31, LIGHTGRAY);
- DrawCircle(475 + (int)(rightStickX*20),
- 255 + (int)(rightStickY*20), 25, rightGamepadColor);
+ DrawCircle(475 + (int)(rightStickX*20), 255 + (int)(rightStickY*20), 25, rightGamepadColor);
// Draw axis: left-right triggers
DrawRectangle(169, 48, 15, 70, GRAY);
@@ -196,7 +197,6 @@ int main(void)
}
else
{
-
// Draw background: generic
DrawRectangleRounded((Rectangle){ 175, 110, 460, 220}, 0.3f, 16, DARKGRAY);
@@ -237,23 +237,20 @@ int main(void)
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_LEFT_THUMB)) leftGamepadColor = RED;
DrawCircle(345, 260, 40, BLACK);
DrawCircle(345, 260, 35, LIGHTGRAY);
- DrawCircle(345 + (int)(leftStickX*20),
- 260 + (int)(leftStickY*20), 25, leftGamepadColor);
+ DrawCircle(345 + (int)(leftStickX*20), 260 + (int)(leftStickY*20), 25, leftGamepadColor);
// Draw axis: right joystick
Color rightGamepadColor = BLACK;
if (IsGamepadButtonDown(gamepad, GAMEPAD_BUTTON_RIGHT_THUMB)) rightGamepadColor = RED;
DrawCircle(465, 260, 40, BLACK);
DrawCircle(465, 260, 35, LIGHTGRAY);
- DrawCircle(465 + (int)(rightStickX*20),
- 260 + (int)(rightStickY*20), 25, rightGamepadColor);
+ DrawCircle(465 + (int)(rightStickX*20), 260 + (int)(rightStickY*20), 25, rightGamepadColor);
// Draw axis: left-right triggers
DrawRectangle(151, 110, 15, 70, GRAY);
DrawRectangle(644, 110, 15, 70, GRAY);
DrawRectangle(151, 110, 15, (int)(((1 + leftTrigger)/2)*70), RED);
DrawRectangle(644, 110, 15, (int)(((1 + rightTrigger)/2)*70), RED);
-
}
DrawText(TextFormat("DETECTED AXIS [%i]:", GetGamepadAxisCount(gamepad)), 10, 50, 10, MAROON);
@@ -263,13 +260,16 @@ int main(void)
DrawText(TextFormat("AXIS %i: %.02f", i, GetGamepadAxisMovement(gamepad, i)), 20, 70 + 20*i, 10, DARKGRAY);
}
+ // Draw vibrate button
+ DrawRectangleRec(vibrateButton, SKYBLUE);
+ DrawText("VIBRATE", vibrateButton.x + 14, 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);
}
else
{
DrawText(TextFormat("GP%d: NOT DETECTED", gamepad), 10, 10, 10, GRAY);
-
DrawTexture(texXboxPad, 0, 0, LIGHTGRAY);
}
diff --git a/examples/core/core_input_gestures.c b/examples/core/core_input_gestures.c
index fd7250658..e9f43ee3b 100644
--- a/examples/core/core_input_gestures.c
+++ b/examples/core/core_input_gestures.c
@@ -118,4 +118,6 @@ int main(void)
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
+
+ return 0;
}
\ No newline at end of file
diff --git a/examples/core/core_input_gestures_testbed.c b/examples/core/core_input_gestures_testbed.c
index dc47136c2..e0ffeb13f 100644
--- a/examples/core/core_input_gestures_testbed.c
+++ b/examples/core/core_input_gestures_testbed.c
@@ -22,9 +22,9 @@
#define GESTURE_LOG_SIZE 20
#define MAX_TOUCH_COUNT 32
-//----------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
// Module Functions Declaration
-//----------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------
static char const *GetGestureName(int gesture); // Get text string for gesture value
static Color GetGestureColor(int gesture); // Get color for gesture value
@@ -69,7 +69,6 @@ int main(void)
float angleLength = 90.0f;
float currentAngleDegrees = 0.0f;
Vector2 finalVector = { 0.0f, 0.0f };
- char currentAngleStr[7] = "";
Vector2 protractorPosition = { 266.0f, 315.0f };
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
@@ -203,7 +202,7 @@ int main(void)
DrawText("Log", (int)gestureLogPosition.x, (int)gestureLogPosition.y, 20, BLACK);
// Loop in both directions to print the gesture log array in the inverted order (and looping around if the index started somewhere in the middle)
- for (i = 0, ii = gestureLogIndex; i < GESTURE_LOG_SIZE; i++, ii = (ii + 1) % GESTURE_LOG_SIZE) DrawText(gestureLog[ii], (int)gestureLogPosition.x, (int)gestureLogPosition.y + 410 - i*20, 20, (i == 0 ? gestureColor : LIGHTGRAY));
+ for (i = 0, ii = gestureLogIndex; i < GESTURE_LOG_SIZE; i++, ii = (ii + 1)%GESTURE_LOG_SIZE) DrawText(gestureLog[ii], (int)gestureLogPosition.x, (int)gestureLogPosition.y + 410 - i*20, 20, (i == 0 ? gestureColor : LIGHTGRAY));
Color logButton1Color, logButton2Color;
switch (logMode)
{
diff --git a/examples/core/core_input_mouse.c b/examples/core/core_input_mouse.c
index f429018b0..d46106996 100644
--- a/examples/core/core_input_mouse.c
+++ b/examples/core/core_input_mouse.c
@@ -40,14 +40,8 @@ int main(void)
//----------------------------------------------------------------------------------
if (IsKeyPressed(KEY_H))
{
- if (IsCursorHidden())
- {
- ShowCursor();
- }
- else
- {
- HideCursor();
- }
+ if (IsCursorHidden()) ShowCursor();
+ else HideCursor();
}
ballPosition = GetMousePosition();
diff --git a/examples/core/core_input_multitouch.c b/examples/core/core_input_multitouch.c
index 01dd90fae..47ad91d66 100644
--- a/examples/core/core_input_multitouch.c
+++ b/examples/core/core_input_multitouch.c
@@ -46,7 +46,7 @@ int main(void)
// Clamp touch points available ( set the maximum touch points allowed )
if (tCount > MAX_TOUCH_POINTS) tCount = MAX_TOUCH_POINTS;
// Get touch points positions
- for (int i = 0; i < tCount; ++i) touchPositions[i] = GetTouchPosition(i);
+ for (int i = 0; i < tCount; i++) touchPositions[i] = GetTouchPosition(i);
//----------------------------------------------------------------------------------
// Draw
@@ -55,7 +55,7 @@ int main(void)
ClearBackground(RAYWHITE);
- for (int i = 0; i < tCount; ++i)
+ for (int i = 0; i < tCount; i++)
{
// Make sure point is not (0, 0) as this means there is no touch for it
if ((touchPositions[i].x > 0) && (touchPositions[i].y > 0))
diff --git a/examples/core/core_input_virtual_controls.c b/examples/core/core_input_virtual_controls.c
index 6cae4b6c7..db293b993 100644
--- a/examples/core/core_input_virtual_controls.c
+++ b/examples/core/core_input_virtual_controls.c
@@ -6,7 +6,7 @@
*
* Example originally created with raylib 5.0, last time updated with raylib 5.0
*
-* Example contributed by GreenSnakeLinux (@GreenSnakeLinux),
+* Example contributed by GreenSnakeLinux (@GreenSnakeLinux),
* reviewed by Ramon Santamaria (@raysan5), oblerion (@oblerion) and danilwhale (@danilwhale)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
@@ -86,7 +86,7 @@ int main(void)
pressedButton = BUTTON_NONE;
// Make sure user is pressing left mouse button if they're from desktop
- if ((GetTouchPointCount() > 0) ||
+ if ((GetTouchPointCount() > 0) ||
((GetTouchPointCount() == 0) && IsMouseButtonDown(MOUSE_BUTTON_LEFT)))
{
// Find nearest D-Pad button to the input position
@@ -113,7 +113,7 @@ int main(void)
default: break;
};
//--------------------------------------------------------------------------
-
+
// Draw
//--------------------------------------------------------------------------
BeginDrawing();
diff --git a/examples/core/core_monitor_detector.c b/examples/core/core_monitor_detector.c
index 0e94f6895..ab65d8042 100644
--- a/examples/core/core_monitor_detector.c
+++ b/examples/core/core_monitor_detector.c
@@ -40,10 +40,9 @@ int main(void)
const int screenWidth = 800;
const int screenHeight = 450;
- MonitorInfo monitors[MAX_MONITORS] = { 0 };
-
InitWindow(screenWidth, screenHeight, "raylib [core] example - monitor detector");
+ MonitorInfo monitors[MAX_MONITORS] = { 0 };
int currentMonitorIndex = GetCurrentMonitor();
int monitorCount = 0;
@@ -55,7 +54,6 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
-
// Variables to find the max x and Y to calculate the scale
int maxWidth = 1;
int maxHeight = 1;
@@ -68,42 +66,40 @@ int main(void)
for (int i = 0; i < monitorCount; i++)
{
monitors[i] = (MonitorInfo){
- GetMonitorPosition(i),
- GetMonitorName(i),
+ GetMonitorPosition(i),
+ GetMonitorName(i),
GetMonitorWidth(i),
GetMonitorHeight(i),
GetMonitorPhysicalWidth(i),
GetMonitorPhysicalHeight(i),
GetMonitorRefreshRate(i)
};
- if (monitors[i].position.x < monitorOffsetX) monitorOffsetX = (int)monitors[i].position.x*-1;
+
+ if (monitors[i].position.x < monitorOffsetX) monitorOffsetX = -(int)monitors[i].position.x;
const int width = (int)monitors[i].position.x + monitors[i].width;
const int height = (int)monitors[i].position.y + monitors[i].height;
-
+
if (maxWidth < width) maxWidth = width;
if (maxHeight < height) maxHeight = height;
}
- if (IsKeyPressed(KEY_ENTER) && monitorCount > 1)
+ if (IsKeyPressed(KEY_ENTER) && (monitorCount > 1))
{
currentMonitorIndex += 1;
// Set index to 0 if the last one
- if(currentMonitorIndex == monitorCount) currentMonitorIndex = 0;
+ if (currentMonitorIndex == monitorCount) currentMonitorIndex = 0;
SetWindowMonitor(currentMonitorIndex); // Move window to currentMonitorIndex
}
- else
- {
- // Get currentMonitorIndex if manually moved
- currentMonitorIndex = GetCurrentMonitor();
- }
+ else currentMonitorIndex = GetCurrentMonitor(); // Get currentMonitorIndex if manually moved
- float monitorScale = 0.6f;
+ float monitorScale = 0.6f;
- if(maxHeight > maxWidth + monitorOffsetX) monitorScale *= ((float)screenHeight/(float)maxHeight);
+ if (maxHeight > (maxWidth + monitorOffsetX)) monitorScale *= ((float)screenHeight/(float)maxHeight);
else monitorScale *= ((float)screenWidth/(float)(maxWidth + monitorOffsetX));
+ //----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
@@ -120,18 +116,18 @@ int main(void)
{
// Calculate retangle position and size using monitorScale
const Rectangle rec = (Rectangle){
- (monitors[i].position.x + monitorOffsetX) * monitorScale + 140,
- monitors[i].position.y * monitorScale + 80,
- monitors[i].width * monitorScale,
- monitors[i].height * monitorScale
+ (monitors[i].position.x + monitorOffsetX)*monitorScale + 140,
+ monitors[i].position.y*monitorScale + 80,
+ monitors[i].width*monitorScale,
+ monitors[i].height*monitorScale
};
// Draw monitor name and information inside the rectangle
DrawText(TextFormat("[%i] %s", i, monitors[i].name), (int)rec.x + 10, (int)rec.y + (int)(100*monitorScale), (int)(120*monitorScale), BLUE);
DrawText(
- TextFormat("Resolution: [%ipx x %ipx]\nRefreshRate: [%ihz]\nPhysical Size: [%imm x %imm]\nPosition: %3.0f x %3.0f",
- monitors[i].width,
- monitors[i].height,
+ TextFormat("Resolution: [%ipx x %ipx]\nRefreshRate: [%ihz]\nPhysical Size: [%imm x %imm]\nPosition: %3.0f x %3.0f",
+ monitors[i].width,
+ monitors[i].height,
monitors[i].refreshRate,
monitors[i].physicalWidth,
monitors[i].physicalHeight,
@@ -146,16 +142,11 @@ int main(void)
Vector2 windowPosition = (Vector2){ (GetWindowPosition().x + monitorOffsetX)*monitorScale + 140, GetWindowPosition().y*monitorScale + 80 };
// Draw window position based on monitors
- DrawRectangleV(windowPosition, (Vector2){screenWidth * monitorScale, screenHeight * monitorScale}, Fade(GREEN, 0.5));
+ DrawRectangleV(windowPosition, (Vector2){screenWidth*monitorScale, screenHeight*monitorScale}, Fade(GREEN, 0.5));
}
- else
- {
- DrawRectangleLinesEx(rec, 5, GRAY);
- }
-
+ else DrawRectangleLinesEx(rec, 5, GRAY);
}
-
EndDrawing();
//----------------------------------------------------------------------------------
}
diff --git a/examples/core/core_screen_recording.c b/examples/core/core_screen_recording.c
index 43c90eec5..633ddcf81 100644
--- a/examples/core/core_screen_recording.c
+++ b/examples/core/core_screen_recording.c
@@ -2,12 +2,10 @@
*
* raylib [core] example - screen recording
*
-* Example complexity rating: [★☆☆☆] 1/4
+* Example complexity rating: [★★☆☆] 2/4
*
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
*
-* Example contributed by Ramon Santamaria (@raysan5) 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
*
@@ -17,6 +15,16 @@
#include "raylib.h"
+// Using msf_gif library to record frames into GIF
+#define MSF_GIF_IMPL
+#include "msf_gif.h" // GIF recording functionality
+
+#include // Required for: sinf()
+
+#define GIF_RECORD_FRAMERATE 5 // Record framerate, we get a frame every N frames
+
+#define MAX_SINEWAVE_POINTS 256
+
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
@@ -29,7 +37,20 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [core] example - screen recording");
- // TODO: Load resources / Initialize variables at this point
+ bool gifRecording = false; // GIF recording state
+ unsigned int gifFrameCounter = 0; // GIF frames counter
+ MsfGifState gifState = { 0 }; // MSGIF context state
+
+ Vector2 circlePosition = { 0.0f, screenHeight/2.0f };
+ float timeCounter = 0.0f;
+
+ // Get sine wave points for line drawing
+ Vector2 sinePoints[MAX_SINEWAVE_POINTS] = { 0 };
+ for (int i = 0; i < MAX_SINEWAVE_POINTS; i++)
+ {
+ sinePoints[i].x = i*GetScreenWidth()/180.0f;
+ sinePoints[i].y = screenHeight/2.0f + 150*sinf((2*PI/1.5f)*(1.0f/60.0f)*(float)i); // Calculate for 60 fps
+ }
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
@@ -39,7 +60,59 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
- // TODO: Update variables / Implement example logic at this point
+ // Update circle sinusoidal movement
+ timeCounter += GetFrameTime();
+ circlePosition.x += GetScreenWidth()/180.0f;
+ circlePosition.y = screenHeight/2.0f + 150*sinf((2*PI/1.5f)*timeCounter);
+ if (circlePosition.x > screenWidth)
+ {
+ circlePosition.x = 0.0f;
+ circlePosition.y = screenHeight/2.0f;
+ timeCounter = 0.0f;
+ }
+
+ // Start-Stop GIF recording on CTRL+R
+ if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_R))
+ {
+ if (gifRecording)
+ {
+ // Stop current recording and save file
+ gifRecording = false;
+ MsfGifResult result = msf_gif_end(&gifState);
+ SaveFileData(TextFormat("%s/screenrecording.gif", GetApplicationDirectory()), result.data, (unsigned int)result.dataSize);
+ msf_gif_free(result);
+
+ TraceLog(LOG_INFO, "Finish animated GIF recording");
+ }
+ else
+ {
+ // Start a new recording
+ gifRecording = true;
+ gifFrameCounter = 0;
+ msf_gif_begin(&gifState, GetRenderWidth(), GetRenderHeight());
+
+ TraceLog(LOG_INFO, "Start animated GIF recording");
+ }
+ }
+
+ if (gifRecording)
+ {
+ gifFrameCounter++;
+
+ // NOTE: We record one gif frame depending on the desired gif framerate
+ if (gifFrameCounter > GIF_RECORD_FRAMERATE)
+ {
+ // Get image data for the current frame (from backbuffer)
+ // WARNING: This process is quite slow, it can generate stuttering
+ Image imScreen = LoadImageFromScreen();
+
+ // Add the frame to the gif recording, providing and "estimated" time for display in centiseconds
+ msf_gif_frame(&gifState, imScreen.data, (int)((1.0f/60.0f)*GIF_RECORD_FRAMERATE)/10, 16, imScreen.width*4);
+ gifFrameCounter = 0;
+
+ UnloadImage(imScreen); // Free image data
+ }
+ }
//----------------------------------------------------------------------------------
// Draw
@@ -48,20 +121,43 @@ int main(void)
ClearBackground(RAYWHITE);
- // TODO: Draw everything that requires to be drawn at this point
+ for (int i = 0; i < (MAX_SINEWAVE_POINTS - 1); i++)
+ {
+ DrawLineV(sinePoints[i], sinePoints[i + 1], MAROON);
+ DrawCircleV(sinePoints[i], 3, MAROON);
+ }
- DrawLineEx((Vector2){ 0, 0 }, (Vector2){ screenWidth, screenHeight }, 2.0f, RED);
- DrawLineEx((Vector2){ 0, screenHeight }, (Vector2){ screenWidth, 0 }, 2.0f, RED);
- DrawText("example base code template", 260, 400, 20, LIGHTGRAY);
+ DrawCircleV(circlePosition, 30, RED);
+ DrawFPS(10, 10);
+
+ /*
+ // Draw record indicator
+ // WARNING: If drawn here, it will appear in the recorded image,
+ // use a render texture instead for the recording and LoadImageFromTexture(rt.texture)
+ if (gifRecording)
+ {
+ // Display the recording indicator every half-second
+ if ((int)(GetTime()/0.5)%2 == 1)
+ {
+ DrawCircle(30, GetScreenHeight() - 20, 10, MAROON);
+ DrawText("GIF RECORDING", 50, GetScreenHeight() - 25, 10, RED);
+ }
+ }
+ */
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
-
- // TODO: Unload all loaded resources at this point
+ // If still recording a GIF on close window, just finish
+ if (gifRecording)
+ {
+ MsfGifResult result = msf_gif_end(&gifState);
+ msf_gif_free(result);
+ gifRecording = false;
+ }
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
diff --git a/examples/core/core_screen_recording.png b/examples/core/core_screen_recording.png
index da99bbb0d..9b14af24d 100644
Binary files a/examples/core/core_screen_recording.png and b/examples/core/core_screen_recording.png differ
diff --git a/examples/core/core_text_file_loading.c b/examples/core/core_text_file_loading.c
index 033fd4dc6..852cc32c4 100644
--- a/examples/core/core_text_file_loading.c
+++ b/examples/core/core_text_file_loading.c
@@ -19,6 +19,8 @@
#include "raymath.h" // Required for: Lerp()
+#include
+
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
@@ -59,10 +61,11 @@ int main(void)
int lastSpace = 0; // Keeping track of last valid space to insert '\n'
int lastWrapStart = 0; // Keeping track of the start of this wrapped line.
- while (lines[i][j] != '\0')
+ while (j <= strlen(lines[i]))
{
- if (lines[i][j] == ' ')
+ if (lines[i][j] == ' ' || lines[i][j] == '\0')
{
+ char before = lines[i][j];
// Making a C Style string by adding a '\0' at the required location so that we can use the MeasureText function
lines[i][j] = '\0';
@@ -75,7 +78,7 @@ int main(void)
lastWrapStart = lastSpace + 1;
}
- lines[i][j] = ' '; // Resetting the space back
+ if(before != '\0') lines[i][j] = ' '; // Resetting the space back
lastSpace = j; // Since we encountered a new space we update our last encountered space location
}
@@ -88,16 +91,16 @@ int main(void)
for (int i = 0; i < lineCount; i++)
{
- Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2);
- textHeight += size.y + 10;
+ Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2);
+ textHeight += (int)size.y + 10;
}
- // A simple scrollbar on the side to show how far we have red into the file
+ // A simple scrollbar on the side to show how far we have read into the file
Rectangle scrollBar = {
- .x = screenWidth - 5,
+ .x = (float)screenWidth - 5,
.y = 0,
.width = 5,
- .height = screenHeight*100/(textHeight - screenHeight) // Scrollbar height is just a percentage
+ .height = screenHeight*100.0f/(textHeight - screenHeight) // Scrollbar height is just a percentage
};
SetTargetFPS(60);
@@ -115,10 +118,10 @@ int main(void)
// Ensuring that the camera does not scroll past all text
if (cam.target.y > textHeight - screenHeight + textTop)
- cam.target.y = textHeight - screenHeight + textTop;
+ cam.target.y = (float)textHeight - screenHeight + textTop;
// Computing the position of the scrollBar depending on the percentage of text covered
- scrollBar.y = Lerp(textTop, screenHeight - scrollBar.height, (cam.target.y - textTop)/(textHeight - screenHeight));
+ scrollBar.y = Lerp((float)textTop, (float)screenHeight - scrollBar.height, (float)(cam.target.y - textTop)/(textHeight - screenHeight));
//----------------------------------------------------------------------------------
// Draw
@@ -132,13 +135,19 @@ int main(void)
for (int i = 0, t = textTop; i < lineCount; i++)
{
// Each time we go through and calculate the height of the text to move the cursor appropriately
- Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2);
+ Vector2 size;
+ if(strcmp(lines[i], "")){
+ // Fix for empty line in the text file
+ size = MeasureTextEx( GetFontDefault(), lines[i], (float)fontSize, 2);
+ }else{
+ size = MeasureTextEx( GetFontDefault(), " ", (float)fontSize, 2);
+ }
DrawText(lines[i], 10, t, fontSize, RED);
// Inserting extra space for real newlines,
// wrapped lines are rendered closer together
- t += size.y + 10;
+ t += (int)size.y + 10;
}
EndMode2D();
diff --git a/examples/core/core_undo_redo.c b/examples/core/core_undo_redo.c
index 45b19e10f..78971e689 100644
--- a/examples/core/core_undo_redo.c
+++ b/examples/core/core_undo_redo.c
@@ -22,7 +22,7 @@
#define MAX_UNDO_STATES 26 // Maximum undo states supported for the ring buffer
-#define GRID_CELL_SIZE 24
+#define GRID_CELL_SIZE 24
#define MAX_GRID_CELLS_X 30
#define MAX_GRID_CELLS_Y 13
@@ -57,7 +57,7 @@ int main(void)
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
-
+
// We have multiple options to implement an Undo/Redo system
// Probably the most professional one is using the Command pattern to
// define Actions and store those actions into an array as the events happen,
@@ -187,7 +187,7 @@ int main(void)
if (lastUndoIndex > firstUndoIndex)
{
for (int i = firstUndoIndex; i < currentUndoIndex; i++)
- DrawRectangleRec((Rectangle){gridPosition.x + states[i].cell.x * GRID_CELL_SIZE, gridPosition.y + states[i].cell.y * GRID_CELL_SIZE,
+ DrawRectangleRec((Rectangle){gridPosition.x + states[i].cell.x*GRID_CELL_SIZE, gridPosition.y + states[i].cell.y*GRID_CELL_SIZE,
GRID_CELL_SIZE, GRID_CELL_SIZE }, LIGHTGRAY);
}
else if (firstUndoIndex > lastUndoIndex)
@@ -195,7 +195,7 @@ int main(void)
if ((currentUndoIndex < MAX_UNDO_STATES) && (currentUndoIndex > lastUndoIndex))
{
for (int i = firstUndoIndex; i < currentUndoIndex; i++)
- DrawRectangleRec((Rectangle) { gridPosition.x + states[i].cell.x * GRID_CELL_SIZE, gridPosition.y + states[i].cell.y * GRID_CELL_SIZE,
+ DrawRectangleRec((Rectangle) { gridPosition.x + states[i].cell.x*GRID_CELL_SIZE, gridPosition.y + states[i].cell.y*GRID_CELL_SIZE,
GRID_CELL_SIZE, GRID_CELL_SIZE }, LIGHTGRAY);
}
else
diff --git a/examples/core/core_viewport_scaling.c b/examples/core/core_viewport_scaling.c
new file mode 100644
index 000000000..adcd51ea3
--- /dev/null
+++ b/examples/core/core_viewport_scaling.c
@@ -0,0 +1,321 @@
+/*******************************************************************************************
+*
+* raylib [core] example - viewport scaling
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.5, last time updated with raylib 5.5
+*
+* Example contributed by Agnis Aldiņš (@nezvers) 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 Agnis Aldiņš (@nezvers)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define RESOLUTION_COUNT 4 // For iteration purposes and teaching example
+
+typedef enum {
+ // Only upscale, useful for pixel art
+ KEEP_ASPECT_INTEGER,
+ KEEP_HEIGHT_INTEGER,
+ KEEP_WIDTH_INTEGER,
+ // Can also downscale
+ KEEP_ASPECT,
+ KEEP_HEIGHT,
+ KEEP_WIDTH,
+ // For itteration purposes and as a teaching example
+ VIEWPORT_TYPE_COUNT,
+} ViewportType;
+
+// For displaying on GUI
+const char *ViewportTypeNames[VIEWPORT_TYPE_COUNT] = {
+ "KEEP_ASPECT_INTEGER",
+ "KEEP_HEIGHT_INTEGER",
+ "KEEP_WIDTH_INTEGER",
+ "KEEP_ASPECT",
+ "KEEP_HEIGHT",
+ "KEEP_WIDTH",
+};
+
+//--------------------------------------------------------------------------------------
+// Module Functions Declaration
+//--------------------------------------------------------------------------------------
+static void KeepAspectCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
+static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
+static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
+static void KeepAspectCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
+static void KeepHeightCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
+static void KeepWidthCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect);
+static void ResizeRenderSize(ViewportType viewportType, int *screenWidth, int *screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect, RenderTexture2D *target);
+
+// Example how to calculate position on RenderTexture
+static Vector2 Screen2RenderTexturePosition(Vector2 point, Rectangle *textureRect, Rectangle *scaledRect);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //---------------------------------------------------------
+ int screenWidth = 800;
+ int screenHeight = 450;
+
+ SetConfigFlags(FLAG_WINDOW_RESIZABLE);
+ InitWindow(screenWidth, screenHeight, "raylib [core] example - viewport scaling");
+
+ // Preset resolutions that could be created by subdividing screen resolution
+ Vector2 resolutionList[RESOLUTION_COUNT] = {
+ (Vector2){ 64, 64 },
+ (Vector2){ 256, 240 },
+ (Vector2){ 320, 180 },
+ // 4K doesn't work with integer scaling but included for example purposes with non-integer scaling
+ (Vector2){ 3840, 2160 },
+ };
+
+ int resolutionIndex = 0;
+ int gameWidth = 64;
+ int gameHeight = 64;
+
+ RenderTexture2D target = (RenderTexture2D){ 0 };
+ Rectangle sourceRect = (Rectangle){ 0 };
+ Rectangle destRect = (Rectangle){ 0 };
+
+ ViewportType viewportType = KEEP_ASPECT_INTEGER;
+ ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
+
+ // Button rectangles
+ Rectangle decreaseResolutionButton = (Rectangle){ 200, 30, 10, 10 };
+ Rectangle increaseResolutionButton = (Rectangle){ 215, 30, 10, 10 };
+ Rectangle decreaseTypeButton = (Rectangle){ 200, 45, 10, 10 };
+ Rectangle increaseTypeButton = (Rectangle){ 215, 45, 10, 10 };
+
+ 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
+ //----------------------------------------------------------------------------------
+ if (IsWindowResized()) ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
+
+ Vector2 mousePosition = GetMousePosition();
+ bool mousePressed = IsMouseButtonPressed(MOUSE_BUTTON_LEFT);
+
+ // Check buttons and rescale
+ if (CheckCollisionPointRec(mousePosition, decreaseResolutionButton) && mousePressed)
+ {
+ resolutionIndex = (resolutionIndex + RESOLUTION_COUNT - 1)%RESOLUTION_COUNT;
+ gameWidth = resolutionList[resolutionIndex].x;
+ gameHeight = 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;
+ ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
+ }
+
+ if (CheckCollisionPointRec(mousePosition, decreaseTypeButton) && mousePressed)
+ {
+ viewportType = (viewportType + VIEWPORT_TYPE_COUNT - 1)%VIEWPORT_TYPE_COUNT;
+ ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
+ }
+
+ if (CheckCollisionPointRec(mousePosition, increaseTypeButton) && mousePressed)
+ {
+ viewportType = (viewportType + 1)%VIEWPORT_TYPE_COUNT;
+ ResizeRenderSize(viewportType, &screenWidth, &screenHeight, gameWidth, gameHeight, &sourceRect, &destRect, &target);
+ }
+
+ Vector2 textureMousePosition = Screen2RenderTexturePosition(mousePosition, &sourceRect, &destRect);
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ // Draw our scene to the render texture
+ BeginTextureMode(target);
+ ClearBackground(WHITE);
+ DrawCircle(textureMousePosition.x, textureMousePosition.y, 20.0f, LIME);
+ EndTextureMode();
+
+ // Draw render texture to main framebuffer
+ BeginDrawing();
+ ClearBackground(BLACK);
+
+ // Draw our render texture with rotation applied
+ DrawTexturePro(target.texture, sourceRect, destRect, (Vector2){ 0.0f, 0.0f }, 0.0f, WHITE);
+
+ // Draw Native resolution (GUI or anything)
+ // 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);
+
+ 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);
+
+ DrawText(TextFormat("Type: %s", ViewportTypeNames[viewportType]), 15, 45, 10, BLACK);
+ Vector2 scaleRatio = (Vector2){destRect.width/sourceRect.width, -destRect.height/sourceRect.height};
+ if (scaleRatio.x < 0.001f || scaleRatio.y < 0.001f) DrawText(TextFormat("Scale ratio: INVALID"), 15, 60, 10, BLACK);
+ else DrawText(TextFormat("Scale ratio: %.2f x %.2f", scaleRatio.x, scaleRatio.y), 15, 60, 10, BLACK);
+
+ DrawText(TextFormat("Source size: %.2f x %.2f", sourceRect.width, -sourceRect.height), 15, 75, 10, BLACK);
+ DrawText(TextFormat("Destination size: %.2f x %.2f", destRect.width, destRect.height), 15, 90, 10, BLACK);
+
+ // Draw buttons
+ DrawRectangleRec(decreaseTypeButton, SKYBLUE);
+ DrawRectangleRec(increaseTypeButton, SKYBLUE);
+ DrawRectangleRec(decreaseResolutionButton, SKYBLUE);
+ DrawRectangleRec(increaseResolutionButton, SKYBLUE);
+ DrawText("<", decreaseTypeButton.x + 3, decreaseTypeButton.y + 1, 10, BLACK);
+ DrawText(">", increaseTypeButton.x + 3, increaseTypeButton.y + 1, 10, BLACK);
+ DrawText("<", decreaseResolutionButton.x + 3, decreaseResolutionButton.y + 1, 10, BLACK);
+ DrawText(">", increaseResolutionButton.x + 3, increaseResolutionButton.y + 1, 10, BLACK);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //----------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //----------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//--------------------------------------------------------------------------------------
+// Module Functions Definition
+//--------------------------------------------------------------------------------------
+static void KeepAspectCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
+{
+ sourceRect->x = 0.0f;
+ sourceRect->y = (float)gameHeight;
+ sourceRect->width = (float)gameWidth;
+ sourceRect->height = (float)-gameHeight;
+
+ const int ratio_x = (screenWidth/gameWidth);
+ const int ratio_y = (screenHeight/gameHeight);
+ const float resizeRatio = (float)((ratio_x < ratio_y)? ratio_x : ratio_y);
+
+ destRect->x = (float)(int)((screenWidth - (gameWidth*resizeRatio))*0.5f);
+ destRect->y = (float)(int)((screenHeight - (gameHeight*resizeRatio))*0.5f);
+ destRect->width = (float)(int)(gameWidth*resizeRatio);
+ destRect->height = (float)(int)(gameHeight*resizeRatio);
+}
+
+static void KeepHeightCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
+{
+ const float resizeRatio = (float)(screenHeight/gameHeight);
+ sourceRect->x = 0.0f;
+ sourceRect->y = 0.0f;
+ sourceRect->width = (float)(int)(screenWidth/resizeRatio);
+ sourceRect->height = (float)-gameHeight;
+
+ destRect->x = (float)(int)((screenWidth - (sourceRect->width*resizeRatio))*0.5f);
+ destRect->y = (float)(int)((screenHeight - (gameHeight*resizeRatio))*0.5f);
+ destRect->width = (float)(int)(sourceRect->width*resizeRatio);
+ destRect->height = (float)(int)(gameHeight*resizeRatio);
+}
+
+static void KeepWidthCenteredInteger(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
+{
+ const float resizeRatio = (float)(screenWidth/gameWidth);
+ sourceRect->x = 0.0f;
+ sourceRect->y = 0.0f;
+ sourceRect->width = (float)gameWidth;
+ sourceRect->height = (float)(int)(screenHeight/resizeRatio);
+
+ destRect->x = (float)(int)((screenWidth - (gameWidth*resizeRatio))*0.5f);
+ destRect->y = (float)(int)((screenHeight - (sourceRect->height*resizeRatio))*0.5f);
+ destRect->width = (float)(int)(gameWidth*resizeRatio);
+ destRect->height = (float)(int)(sourceRect->height*resizeRatio);
+
+ sourceRect->height *= -1.0f;
+}
+
+static void KeepAspectCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
+{
+ sourceRect->x = 0.0f;
+ sourceRect->y = (float)gameHeight;
+ sourceRect->width = (float)gameWidth;
+ sourceRect->height = (float)-gameHeight;
+
+ const float ratio_x = ((float)screenWidth/(float)gameWidth);
+ const float ratio_y = ((float)screenHeight/(float)gameHeight);
+ const float resizeRatio = (ratio_x < ratio_y ? ratio_x : ratio_y);
+
+ destRect->x = (float)(int)((screenWidth - (gameWidth*resizeRatio))*0.5f);
+ destRect->y = (float)(int)((screenHeight - (gameHeight*resizeRatio))*0.5f);
+ destRect->width = (float)(int)(gameWidth*resizeRatio);
+ destRect->height = (float)(int)(gameHeight*resizeRatio);
+}
+
+static void KeepHeightCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
+{
+ const float resizeRatio = ((float)screenHeight/(float)gameHeight);
+ sourceRect->x = 0.0f;
+ sourceRect->y = 0.0f;
+ sourceRect->width = (float)(int)((float)screenWidth/resizeRatio);
+ sourceRect->height = (float)-gameHeight;
+
+ destRect->x = (float)(int)((screenWidth - (sourceRect->width*resizeRatio))*0.5f);
+ destRect->y = (float)(int)((screenHeight - (gameHeight*resizeRatio))*0.5f);
+ destRect->width = (float)(int)(sourceRect->width*resizeRatio);
+ destRect->height = (float)(int)(gameHeight*resizeRatio);
+}
+
+static void KeepWidthCentered(int screenWidth, int screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect)
+{
+ const float resizeRatio = ((float)screenWidth/(float)gameWidth);
+ sourceRect->x = 0.0f;
+ sourceRect->y = 0.0f;
+ sourceRect->width = (float)gameWidth;
+ sourceRect->height = (float)(int)((float)screenHeight/resizeRatio);
+
+ destRect->x = (float)(int)((screenWidth - (gameWidth*resizeRatio))*0.5f);
+ destRect->y = (float)(int)((screenHeight - (sourceRect->height*resizeRatio))*0.5f);
+ destRect->width = (float)(int)(gameWidth*resizeRatio);
+ destRect->height = (float)(int)(sourceRect->height*resizeRatio);
+
+ sourceRect->height *= -1.f;
+}
+
+static void ResizeRenderSize(ViewportType viewportType, int *screenWidth, int *screenHeight, int gameWidth, int gameHeight, Rectangle *sourceRect, Rectangle *destRect, RenderTexture2D *target)
+{
+ *screenWidth = GetScreenWidth();
+ *screenHeight = GetScreenHeight();
+
+ switch(viewportType)
+ {
+ case KEEP_ASPECT_INTEGER: KeepAspectCenteredInteger(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
+ case KEEP_HEIGHT_INTEGER: KeepHeightCenteredInteger(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
+ case KEEP_WIDTH_INTEGER: KeepWidthCenteredInteger(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
+ case KEEP_ASPECT: KeepAspectCentered(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
+ case KEEP_HEIGHT: KeepHeightCentered(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
+ case KEEP_WIDTH: KeepWidthCentered(*screenWidth, *screenHeight, gameWidth, gameHeight, sourceRect, destRect); break;
+ default: break;
+ }
+
+ UnloadRenderTexture(*target);
+ *target = LoadRenderTexture(sourceRect->width, -sourceRect->height);
+}
+
+// Example how to calculate position on RenderTexture
+static Vector2 Screen2RenderTexturePosition(Vector2 point, Rectangle *textureRect, Rectangle *scaledRect)
+{
+ Vector2 relativePosition = {point.x - scaledRect->x, point.y - scaledRect->y};
+ Vector2 ratio = {textureRect->width/scaledRect->width, -textureRect->height/scaledRect->height};
+
+ return (Vector2){relativePosition.x*ratio.x, relativePosition.y*ratio.x};
+}
\ No newline at end of file
diff --git a/examples/core/core_viewport_scaling.png b/examples/core/core_viewport_scaling.png
new file mode 100644
index 000000000..68fad6209
Binary files /dev/null and b/examples/core/core_viewport_scaling.png differ
diff --git a/examples/core/core_window_flags.c b/examples/core/core_window_flags.c
index 048d2d245..a8096eeb4 100644
--- a/examples/core/core_window_flags.c
+++ b/examples/core/core_window_flags.c
@@ -97,7 +97,8 @@ int main(void)
if (IsWindowState(FLAG_WINDOW_MINIMIZED))
{
framesCounter++;
- if (framesCounter >= 240) {
+ if (framesCounter >= 240)
+ {
RestoreWindow(); // Restore window after 3 seconds
framesCounter = 0;
}
diff --git a/examples/core/core_window_should_close.c b/examples/core/core_window_should_close.c
index bb7daf3ee..f53f9d48d 100644
--- a/examples/core/core_window_should_close.c
+++ b/examples/core/core_window_should_close.c
@@ -18,7 +18,7 @@
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
-int main()
+int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
diff --git a/src/external/msf_gif.h b/examples/core/msf_gif.h
similarity index 100%
rename from src/external/msf_gif.h
rename to examples/core/msf_gif.h
diff --git a/examples/core/raygui.h b/examples/core/raygui.h
index a3fc51f0f..88fe5cc5b 100644
--- a/examples/core/raygui.h
+++ b/examples/core/raygui.h
@@ -4,7 +4,7 @@
*
* DESCRIPTION:
* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also
-* available as a standalone library, as long as input and drawing functions are provided.
+* available as a standalone library, as long as input and drawing functions are provided
*
* FEATURES:
* - Immediate-mode gui, minimal retained data
@@ -27,7 +27,7 @@
* - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for
* font atlas recs and glyphs, freeing that memory is (usually) up to the user,
* no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads
-* by default any previously loaded font (texture, recs, glyphs).
+* by default any previously loaded font (texture, recs, glyphs)
* - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions
*
* CONTROLS PROVIDED:
@@ -65,7 +65,7 @@
* - MessageBox --> Window, Label, Button
* - TextInputBox --> Window, Label, TextBox, Button
*
-* It also provides a set of functions for styling the controls based on its properties (size, color).
+* It also provides a set of functions for styling the controls based on its properties (size, color)
*
*
* RAYGUI STYLE (guiStyle):
@@ -77,11 +77,11 @@
*
* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)];
*
-* guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB
+* guiStyle size is by default: 16*(16 + 8) = 384 int = 384*4 bytes = 1536 bytes = 1.5 KB
*
* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style
* used for all controls, when any of those base values is set, it is automatically populated to all
-* controls, so, specific control values overwriting generic style should be set after base values.
+* controls, so, specific control values overwriting generic style should be set after base values
*
* After the first BASE set we have the EXTENDED properties (by default guiStyle[16..23]), those
* properties are actually common to all controls and can not be overwritten individually (like BASE ones)
@@ -100,7 +100,7 @@
* Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon
* requires 8 integers (16*16/32) to be stored in memory.
*
-* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set.
+* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set
*
* The global icons array size is fixed and depends on the number of icons and size:
*
@@ -112,20 +112,20 @@
*
* RAYGUI LAYOUT:
* raygui currently does not provide an auto-layout mechanism like other libraries,
-* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it.
+* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it
*
* TOOL: rGuiLayout is a visual tool to create raygui layouts: github.com/raysan5/rguilayout
*
* CONFIGURATION:
* #define RAYGUI_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 RAYGUI_STANDALONE
* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined
* internally in the library and input management and drawing functions must be provided by
-* the user (check library implementation for further details).
+* the user (check library implementation for further details)
*
* #define RAYGUI_NO_ICONS
* Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB)
@@ -141,12 +141,17 @@
* Draw text bounds rectangles for debug
*
* VERSIONS HISTORY:
-* 4.5-dev (Sep-2024) Current dev version...
+* 5.0 (xx-Nov-2025) ADDED: Support up to 32 controls (v500)
* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
* ADDED: GuiValueBoxFloat()
* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
* ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH
+* ADDED: GuiLoadIconsFromMemory()
* ADDED: Multiple new icons
+* REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties
+* REMOVED: GuiSliderPro(), functionality was redundant
+* REVIEWED: Controls using text labels to use LABEL properties
+* REVIEWED: Replaced sprintf() by snprintf() for more safety
* REVIEWED: GuiTabBar(), close tab with mouse middle button
* REVIEWED: GuiScrollPanel(), scroll speed proportional to content
* REVIEWED: GuiDropdownBox(), support roll up and hidden arrow
@@ -156,6 +161,8 @@
* REVIEWED: GuiIconText(), increase buffer size and reviewed padding
* REVIEWED: GuiDrawText(), improved wrap mode drawing
* REVIEWED: GuiScrollBar(), minor tweaks
+* REVIEWED: GuiProgressBar(), improved borders computing
+* REVIEWED: GuiTextBox(), multiple improvements: autocursor and more
* REVIEWED: Functions descriptions, removed wrong return value reference
* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion
*
@@ -259,16 +266,16 @@
* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones)
* 1.3 (12-Jun-2017) Complete redesign of style system
* 1.1 (01-Jun-2017) Complete review of the library
-* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria.
-* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria.
-* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria.
+* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria
+* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria
+* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria
*
* DEPENDENCIES:
-* raylib 5.0 - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing
+* raylib 5.6-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing
*
* STANDALONE MODE:
* By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled
-* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs.
+* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs
*
* The following functions should be redefined for a custom backend:
*
@@ -309,7 +316,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5)
+* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -334,7 +341,7 @@
#define RAYGUI_VERSION_MAJOR 4
#define RAYGUI_VERSION_MINOR 5
#define RAYGUI_VERSION_PATCH 0
-#define RAYGUI_VERSION "4.5-dev"
+#define RAYGUI_VERSION "5.0-dev"
#if !defined(RAYGUI_STANDALONE)
#include "raylib.h"
@@ -358,17 +365,6 @@
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
-// Allow custom memory allocators
-#ifndef RAYGUI_MALLOC
- #define RAYGUI_MALLOC(sz) malloc(sz)
-#endif
-#ifndef RAYGUI_CALLOC
- #define RAYGUI_CALLOC(n,sz) calloc(n,sz)
-#endif
-#ifndef RAYGUI_FREE
- #define RAYGUI_FREE(p) free(p)
-#endif
-
// Simple log system to avoid printf() calls if required
// NOTE: Avoiding those calls, also avoids const strings memory usage
#define RAYGUI_SUPPORT_LOG_INFO
@@ -421,13 +417,16 @@
// TODO: Texture2D type is very coupled to raylib, required by Font type
// It should be redesigned to be provided by user
- typedef struct Texture2D {
+ typedef struct Texture {
unsigned int id; // OpenGL texture id
int width; // Texture base width
int height; // Texture base height
int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (PixelFormat type)
- } Texture2D;
+ } Texture;
+
+ // Texture2D, same as Texture
+ typedef Texture Texture2D;
// Image, pixel data stored in CPU memory (RAM)
typedef struct Image {
@@ -527,7 +526,7 @@ typedef enum {
DROPDOWNBOX,
TEXTBOX, // Used also for: TEXTBOXMULTI
VALUEBOX,
- SPINNER, // Uses: BUTTON, VALUEBOX
+ CONTROL11,
LISTVIEW,
COLORPICKER,
SCROLLBAR,
@@ -549,12 +548,12 @@ typedef enum {
BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED
BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED
TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED
- BORDER_WIDTH, // Control border size, 0 for no border
+ BORDER_WIDTH = 12, // Control border size, 0 for no border
//TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls
//TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls
- //TEXT_LINE_SPACING // Control text spacing between lines -> GLOBAL for all controls
- TEXT_PADDING, // Control text padding, not considering border
- TEXT_ALIGNMENT, // Control text horizontal alignment inside control text bound (after border and padding)
+ //TEXT_LINE_SPACING, // Control text spacing between lines -> GLOBAL for all controls
+ TEXT_PADDING = 13, // Control text padding, not considering border
+ TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding)
//TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls
} GuiControlProperty;
@@ -641,11 +640,14 @@ typedef enum {
TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable
} GuiTextBoxProperty;
-// Spinner
+// ValueBox/Spinner
typedef enum {
- SPIN_BUTTON_WIDTH = 16, // Spinner left/right buttons width
- SPIN_BUTTON_SPACING, // Spinner buttons separation
-} GuiSpinnerProperty;
+ SPINNER_BUTTON_WIDTH = 16, // Spinner left/right buttons width
+ SPINNER_BUTTON_SPACING, // Spinner buttons separation
+} GuiValueBoxProperty;
+
+// Control11
+//typedef enum { } GuiControl11Property;
// ListView
typedef enum {
@@ -653,6 +655,7 @@ typedef enum {
LIST_ITEMS_SPACING, // ListView items separation
SCROLLBAR_WIDTH, // ListView scrollbar size (usually width)
SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE)
+ LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state
LIST_ITEMS_BORDER_WIDTH // ListView items border width
} GuiListViewProperty;
@@ -717,6 +720,9 @@ RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load
RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position
#endif
+// Utility functions
+RAYGUIAPI int GuiGetTextWidth(const char *text); // Get text width considering gui style and icon size (if required)
+
// Controls
//----------------------------------------------------------------------------------------------------------
// Container/separator controls, useful for controls organization
@@ -999,33 +1005,33 @@ typedef enum {
ICON_MLAYERS = 226,
ICON_MAPS = 227,
ICON_HOT = 228,
- ICON_229 = 229,
- ICON_230 = 230,
- ICON_231 = 231,
- ICON_232 = 232,
- ICON_233 = 233,
- ICON_234 = 234,
- ICON_235 = 235,
- ICON_236 = 236,
- ICON_237 = 237,
- ICON_238 = 238,
- ICON_239 = 239,
- ICON_240 = 240,
- ICON_241 = 241,
- ICON_242 = 242,
- ICON_243 = 243,
- ICON_244 = 244,
- ICON_245 = 245,
- ICON_246 = 246,
- ICON_247 = 247,
- ICON_248 = 248,
- ICON_249 = 249,
+ ICON_LABEL = 229,
+ ICON_NAME_ID = 230,
+ ICON_SLICING = 231,
+ ICON_MANUAL_CONTROL = 232,
+ ICON_COLLISION = 233,
+ ICON_CIRCLE_ADD = 234,
+ ICON_CIRCLE_ADD_FILL = 235,
+ ICON_CIRCLE_WARNING = 236,
+ ICON_CIRCLE_WARNING_FILL = 237,
+ ICON_BOX_MORE = 238,
+ ICON_BOX_MORE_FILL = 239,
+ ICON_BOX_MINUS = 240,
+ ICON_BOX_MINUS_FILL = 241,
+ ICON_UNION = 242,
+ ICON_INTERSECTION = 243,
+ ICON_DIFFERENCE = 244,
+ ICON_SPHERE = 245,
+ ICON_CYLINDER = 246,
+ ICON_CONE = 247,
+ ICON_ELLIPSOID = 248,
+ ICON_CAPSULE = 249,
ICON_250 = 250,
ICON_251 = 251,
ICON_252 = 252,
ICON_253 = 253,
ICON_254 = 254,
- ICON_255 = 255,
+ ICON_255 = 255
} GuiIconName;
#endif
@@ -1046,12 +1052,24 @@ typedef enum {
#if defined(RAYGUI_IMPLEMENTATION)
#include // required for: isspace() [GuiTextBox()]
-#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
-#include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()]
+#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
#include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
#include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
#include // Required for: roundf() [GuiColorPicker()]
+// Allow custom memory allocators
+#if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE)
+ #if !defined(RAYGUI_MALLOC) || !defined(RAYGUI_CALLOC) || !defined(RAYGUI_FREE)
+ #error "RAYGUI: if RAYGUI_MALLOC, RAYGUI_CALLOC, or RAYGUI_FREE is customized, all three must be customized"
+ #endif
+#else
+ #include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()]
+
+ #define RAYGUI_MALLOC(sz) malloc(sz)
+ #define RAYGUI_CALLOC(n,sz) calloc(n,sz)
+ #define RAYGUI_FREE(p) free(p)
+#endif
+
#ifdef __cplusplus
#define RAYGUI_CLITERAL(name) name
#else
@@ -1060,7 +1078,7 @@ typedef enum {
// Check if two rectangles are equal, used to validate a slider bounds as an id
#ifndef CHECK_BOUNDS_ID
- #define CHECK_BOUNDS_ID(src, dst) ((src.x == dst.x) && (src.y == dst.y) && (src.width == dst.width) && (src.height == dst.height))
+ #define CHECK_BOUNDS_ID(src, dst) (((int)src.x == (int)dst.x) && ((int)src.y == (int)dst.y) && ((int)src.width == (int)dst.width) && ((int)src.height == (int)dst.height))
#endif
#if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS)
@@ -1318,27 +1336,27 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] =
0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS
0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS
0x04200000, 0x1cf00c60, 0x11f019f0, 0x0f3807b8, 0x1e3c0f3c, 0x1c1c1e1c, 0x1e3c1c1c, 0x00000f70, // ICON_HOT
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_229
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_230
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_231
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_232
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_233
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_234
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_235
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_236
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_237
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_238
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_239
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_240
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_241
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_242
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_243
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_244
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_245
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_246
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_247
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_248
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_249
+ 0x00000000, 0x20803f00, 0x2a202e40, 0x20082e10, 0x08021004, 0x02040402, 0x00900108, 0x00000060, // ICON_LABEL
+ 0x00000000, 0x042007e0, 0x47e27c3e, 0x4ffa4002, 0x47fa4002, 0x4ffa4002, 0x7ffe4002, 0x00000000, // ICON_NAME_ID
+ 0x7fe00000, 0x402e4020, 0x43ce5e0a, 0x40504078, 0x438e4078, 0x402e5e0a, 0x7fe04020, 0x00000000, // ICON_SLICING
+ 0x00000000, 0x40027ffe, 0x47c24002, 0x55425d42, 0x55725542, 0x50125552, 0x10105016, 0x00001ff0, // ICON_MANUAL_CONTROL
+ 0x7ffe0000, 0x43c24002, 0x48124422, 0x500a500a, 0x500a500a, 0x44224812, 0x400243c2, 0x00007ffe, // ICON_COLLISION
+ 0x03c00000, 0x10080c30, 0x21842184, 0x4ff24182, 0x41824ff2, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_ADD
+ 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x700e7e7e, 0x7e7e700e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_ADD_FILL
+ 0x03c00000, 0x10080c30, 0x21842184, 0x41824182, 0x40024182, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_WARNING
+ 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x7e7e7e7e, 0x7ffe7e7e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_WARNING_FILL
+ 0x00000000, 0x10041ffc, 0x10841004, 0x13e41084, 0x10841084, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MORE
+ 0x00000000, 0x1ffc1ffc, 0x1f7c1ffc, 0x1c1c1f7c, 0x1f7c1f7c, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MORE_FILL
+ 0x00000000, 0x1ffc1ffc, 0x1ffc1ffc, 0x1c1c1ffc, 0x1ffc1ffc, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS
+ 0x00000000, 0x10041ffc, 0x10041004, 0x13e41004, 0x10041004, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS_FILL
+ 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x55766eba, 0x55766eaa, 0x55606ffe, 0x55606aa0, 0x00007fe0, // ICON_UNION
+ 0x07fe0000, 0x04020402, 0x7fe20402, 0x456246a2, 0x456246a2, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_INTERSECTION
+ 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x4436442a, 0x4436442a, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_DIFFERENCE
+ 0x03c00000, 0x10080c30, 0x20042004, 0x60064002, 0x47e2581a, 0x20042004, 0x0c301008, 0x000003c0, // ICON_SPHERE
+ 0x03e00000, 0x08080410, 0x0c180808, 0x08080be8, 0x08080808, 0x08080808, 0x04100808, 0x000003e0, // ICON_CYLINDER
+ 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE
+ 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID
+ 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252
@@ -1363,7 +1381,7 @@ static unsigned int *guiIconsPtr = guiIcons;
#define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties
//----------------------------------------------------------------------------------
-// Types and Structures Definition
+// Module Types and Structures Definition
//----------------------------------------------------------------------------------
// Gui control property style color element
typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement;
@@ -1387,8 +1405,7 @@ static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds
static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*()
//static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking
-static int autoCursorCooldownCounter = 0; // Cooldown frame counter for automatic cursor movement on key-down
-static int autoCursorDelayCounter = 0; // Delay frame counter for automatic cursor movement
+static int autoCursorCounter = 0; // Frame counter for automatic repeated cursor movement on key-down (cooldown and delay)
//----------------------------------------------------------------------------------
// Style data array for all gui style properties (allocated on data segment by default)
@@ -1484,7 +1501,6 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co
//----------------------------------------------------------------------------------
static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only)
-static int GetTextWidth(const char *text); // Gui get text width using gui font and style
static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds
static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor
@@ -1589,6 +1605,10 @@ int GuiWindowBox(Rectangle bounds, const char *title)
#define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24
#endif
+ #if !defined(RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT)
+ #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18
+ #endif
+
int result = 0;
//GuiState state = guiState;
@@ -1597,9 +1617,10 @@ int GuiWindowBox(Rectangle bounds, const char *title)
Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight };
if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f;
+ const float vPadding = statusBarHeight/2.0f - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT/2.0f;
Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 };
- Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 20,
- statusBar.y + statusBarHeight/2.0f - 18.0f/2.0f, 18, 18 };
+ Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT - vPadding,
+ statusBar.y + vPadding, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT };
// Update control
//--------------------------------------------------------------------
@@ -1653,7 +1674,7 @@ int GuiGroupBox(Rectangle bounds, const char *text)
// Line control
int GuiLine(Rectangle bounds, const char *text)
{
- #if !defined(RAYGUI_LINE_ORIGIN_SIZE)
+ #if !defined(RAYGUI_LINE_MARGIN_TEXT)
#define RAYGUI_LINE_MARGIN_TEXT 12
#endif
#if !defined(RAYGUI_LINE_TEXT_PADDING)
@@ -1671,7 +1692,7 @@ int GuiLine(Rectangle bounds, const char *text)
else
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
textBounds.height = bounds.height;
textBounds.x = bounds.x + RAYGUI_LINE_MARGIN_TEXT;
textBounds.y = bounds.y;
@@ -1711,8 +1732,8 @@ int GuiPanel(Rectangle bounds, const char *text)
//--------------------------------------------------------------------
if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar
- GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED: (int)LINE_COLOR)),
- GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR)));
+ GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)),
+ GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR)));
//--------------------------------------------------------------------
return result;
@@ -1722,7 +1743,7 @@ int GuiPanel(Rectangle bounds, const char *text)
// NOTE: Using GuiToggle() for the TABS
int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
{
- #define RAYGUI_TABBAR_ITEM_WIDTH 160
+ #define RAYGUI_TABBAR_ITEM_WIDTH 148
int result = -1;
//GuiState state = guiState;
@@ -1755,12 +1776,12 @@ int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
if (i == (*active))
{
toggle = true;
- GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle);
+ GuiToggle(tabBounds, text[i], &toggle);
}
else
{
toggle = false;
- GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle);
+ GuiToggle(tabBounds, text[i], &toggle);
if (toggle) *active = i;
}
@@ -2011,7 +2032,7 @@ int GuiLabelButton(Rectangle bounds, const char *text)
bool pressed = false;
// NOTE: We force bounds.width to be all text
- float textWidth = (float)GetTextWidth(text);
+ float textWidth = (float)GuiGetTextWidth(text);
if ((bounds.width - 2*GuiGetStyle(LABEL, BORDER_WIDTH) - 2*GuiGetStyle(LABEL, TEXT_PADDING)) < textWidth) bounds.width = textWidth + 2*GuiGetStyle(LABEL, BORDER_WIDTH) + 2*GuiGetStyle(LABEL, TEXT_PADDING) + 2;
// Update control
@@ -2149,7 +2170,9 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
// Get substrings items from text (items pointers)
int itemCount = 0;
- const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
+ const char **items = NULL;
+
+ if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
Rectangle slider = {
0, // Calculated later depending on the active toggle
@@ -2196,7 +2219,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
if (text != NULL)
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(text);
+ textBounds.width = (float)GuiGetTextWidth(text);
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = slider.x + slider.width/2 - textBounds.width/2;
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
@@ -2221,7 +2244,7 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked)
if (text != NULL)
{
- textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
@@ -2474,7 +2497,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod
int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
{
#if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)
- #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 40 // Frames to wait for autocursor movement
+ #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 20 // Frames to wait for autocursor movement
#endif
#if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY)
#define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement
@@ -2487,10 +2510,10 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE);
Rectangle textBounds = GetTextBounds(TEXTBOX, bounds);
- int textLength = (int)strlen(text); // Get current text length
+ int textLength = (text != NULL)? (int)strlen(text) : 0; // Get current text length
int thisCursorIndex = textBoxCursorIndex;
if (thisCursorIndex > textLength) thisCursorIndex = textLength;
- int textWidth = GetTextWidth(text) - GetTextWidth(text + thisCursorIndex);
+ int textWidth = GuiGetTextWidth(text) - GuiGetTextWidth(text + thisCursorIndex);
int textIndexOffset = 0; // Text index offset to start drawing in the box
// Cursor rectangle
@@ -2511,15 +2534,6 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
mouseCursor.x = -1;
mouseCursor.width = 1;
- // Auto-cursor movement logic
- // NOTE: Cursor moves automatically when key down after some time
- if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCooldownCounter++;
- else
- {
- autoCursorCooldownCounter = 0; // GLOBAL: Cursor cooldown counter
- autoCursorDelayCounter = 0; // GLOBAL: Cursor delay counter
- }
-
// Blink-cursor frame counter
//if (!autoCursorMode) blinkCursorFrameCounter++;
//else blinkCursorFrameCounter = 0;
@@ -2537,6 +2551,13 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if (editMode)
{
+ // GLOBAL: Auto-cursor movement logic
+ // NOTE: Keystrokes are handled repeatedly when button is held down for some time
+ if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCounter++;
+ else autoCursorCounter = 0;
+
+ bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0);
+
state = STATE_PRESSED;
if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
@@ -2550,7 +2571,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
textIndexOffset += nextCodepointSize;
- textWidth = GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex);
+ textWidth = GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex);
}
int codepoint = GetCharPressed(); // Get Unicode codepoint
@@ -2560,10 +2581,43 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
int codepointSize = 0;
const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize);
- // Add codepoint to text, at current cursor position
- // NOTE: Make sure we do not overflow buffer size
- if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize))
+ // Handle text paste action
+ if (IsKeyPressed(KEY_V) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
{
+ const char *pasteText = GetClipboardText();
+ if (pasteText != NULL)
+ {
+ int pasteLength = 0;
+ int pasteCodepoint;
+ int pasteCodepointSize;
+
+ // Count how many codepoints to copy, stopping at the first unwanted control character
+ while (true)
+ {
+ pasteCodepoint = GetCodepointNext(pasteText + pasteLength, &pasteCodepointSize);
+ if (textLength + pasteLength + pasteCodepointSize >= textSize) break;
+ if (!(multiline && (pasteCodepoint == (int)'\n')) && !(pasteCodepoint >= 32)) break;
+ pasteLength += pasteCodepointSize;
+ }
+
+ if (pasteLength > 0)
+ {
+ // Move forward data from cursor position
+ for (int i = textLength + pasteLength; i > textBoxCursorIndex; i--) text[i] = text[i - pasteLength];
+
+ // Paste data in at cursor
+ for (int i = 0; i < pasteLength; i++) text[textBoxCursorIndex + i] = pasteText[i];
+
+ textBoxCursorIndex += pasteLength;
+ textLength += pasteLength;
+ text[textLength] = '\0';
+ }
+ }
+ }
+ else if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize))
+ {
+ // Adding codepoint to text, at current cursor position
+
// Move forward data from cursor position
for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize];
@@ -2583,113 +2637,185 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
// Move cursor to end
if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
- // Delete codepoint from text, after current cursor position
- if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
+ // Delete related codepoints from text, after current cursor position
+ if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_DELETE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
{
- autoCursorDelayCounter++;
+ int offset = textBoxCursorIndex;
+ int accCodepointSize = 0;
+ int nextCodepointSize;
+ int nextCodepoint;
- if (IsKeyPressed(KEY_DELETE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
+ // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ bool puctuation = ispunct(nextCodepoint & 0xff);
+ while (offset < textLength)
{
- int nextCodepointSize = 0;
- GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
-
- // Move backward text from cursor position
- for (int i = textBoxCursorIndex; i < textLength; i++) text[i] = text[i + nextCodepointSize];
-
- textLength -= codepointSize;
- if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
-
- // Make sure text last character is EOL
- text[textLength] = '\0';
+ if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff))))
+ break;
+ offset += nextCodepointSize;
+ accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
}
+
+ // Check whitespace to delete (ASCII only)
+ while (offset < textLength)
+ {
+ if (!isspace(nextCodepoint & 0xff)) break;
+
+ offset += nextCodepointSize;
+ accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ }
+
+ // Move text after cursor forward (including final null terminator)
+ for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i];
+
+ textLength -= accCodepointSize;
+ }
+
+ else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && autoCursorShouldTrigger)))
+ {
+ // Delete single codepoint from text, after current cursor position
+
+ int nextCodepointSize = 0;
+ GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
+
+ // Move text after cursor forward (including final null terminator)
+ for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i];
+
+ textLength -= nextCodepointSize;
}
// Delete related codepoints from text, before current cursor position
- if ((textLength > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
+ if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
{
- int i = textBoxCursorIndex - 1;
+ int offset = textBoxCursorIndex;
int accCodepointSize = 0;
+ int prevCodepointSize;
+ int prevCodepoint;
- // Move cursor to the end of word if on space already
- while ((i > 0) && isspace(text[i]))
+ // Check whitespace to delete (ASCII only)
+ while (offset > 0)
{
- int prevCodepointSize = 0;
- GetCodepointPrevious(text + i, &prevCodepointSize);
- i -= prevCodepointSize;
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if (!isspace(prevCodepoint & 0xff)) break;
+
+ offset -= prevCodepointSize;
accCodepointSize += prevCodepointSize;
}
- // Move cursor to the start of the word
- while ((i > 0) && !isspace(text[i]))
+ // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ bool puctuation = ispunct(prevCodepoint & 0xff);
+ while (offset > 0)
{
- int prevCodepointSize = 0;
- GetCodepointPrevious(text + i, &prevCodepointSize);
- i -= prevCodepointSize;
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break;
+
+ offset -= prevCodepointSize;
accCodepointSize += prevCodepointSize;
}
- // Move forward text from cursor position
- for (int j = (textBoxCursorIndex - accCodepointSize); j < textLength; j++) text[j] = text[j + accCodepointSize];
+ // Move text after cursor forward (including final null terminator)
+ for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - accCodepointSize] = text[i];
- // Prevent cursor index from decrementing past 0
- if (textBoxCursorIndex > 0)
- {
- textBoxCursorIndex -= accCodepointSize;
- textLength -= accCodepointSize;
- }
+ textLength -= accCodepointSize;
+ textBoxCursorIndex -= accCodepointSize;
+ }
- // Make sure text last character is EOL
- text[textLength] = '\0';
- }
- else if ((textLength > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
+ else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && autoCursorShouldTrigger)))
{
- autoCursorDelayCounter++;
+ // Delete single codepoint from text, before current cursor position
- if (IsKeyPressed(KEY_BACKSPACE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
- {
- int prevCodepointSize = 0;
+ int prevCodepointSize = 0;
- // Prevent cursor index from decrementing past 0
- if (textBoxCursorIndex > 0)
- {
- GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
+ GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
- // Move backward text from cursor position
- for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize];
+ // Move text after cursor forward (including final null terminator)
+ for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - prevCodepointSize] = text[i];
- textBoxCursorIndex -= codepointSize;
- textLength -= codepointSize;
- }
-
- // Make sure text last character is EOL
- text[textLength] = '\0';
- }
+ textLength -= prevCodepointSize;
+ textBoxCursorIndex -= prevCodepointSize;
}
// Move cursor position with keys
- if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
+ if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_LEFT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
{
- autoCursorDelayCounter++;
+ int offset = textBoxCursorIndex;
+ //int accCodepointSize = 0;
+ int prevCodepointSize;
+ int prevCodepoint;
- if (IsKeyPressed(KEY_LEFT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
+ // Check whitespace to skip (ASCII only)
+ while (offset > 0)
{
- int prevCodepointSize = 0;
- if (textBoxCursorIndex > 0) GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if (!isspace(prevCodepoint & 0xff)) break;
- if (textBoxCursorIndex >= prevCodepointSize) textBoxCursorIndex -= prevCodepointSize;
+ offset -= prevCodepointSize;
+ //accCodepointSize += prevCodepointSize;
}
+
+ // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ bool puctuation = ispunct(prevCodepoint & 0xff);
+ while (offset > 0)
+ {
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break;
+
+ offset -= prevCodepointSize;
+ //accCodepointSize += prevCodepointSize;
+ }
+
+ textBoxCursorIndex = offset;
}
- else if (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
+ else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && autoCursorShouldTrigger)))
{
- autoCursorDelayCounter++;
+ int prevCodepointSize = 0;
+ GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
- if (IsKeyPressed(KEY_RIGHT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
+ textBoxCursorIndex -= prevCodepointSize;
+ }
+ else if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_RIGHT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
+ {
+ int offset = textBoxCursorIndex;
+ //int accCodepointSize = 0;
+ int nextCodepointSize;
+ int nextCodepoint;
+
+ // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ bool puctuation = ispunct(nextCodepoint & 0xff);
+ while (offset < textLength)
{
- int nextCodepointSize = 0;
- GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
+ if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break;
- if ((textBoxCursorIndex + nextCodepointSize) <= textLength) textBoxCursorIndex += nextCodepointSize;
+ offset += nextCodepointSize;
+ //accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
}
+
+ // Check whitespace to skip (ASCII only)
+ while (offset < textLength)
+ {
+ if (!isspace(nextCodepoint & 0xff)) break;
+
+ offset += nextCodepointSize;
+ //accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ }
+
+ textBoxCursorIndex = offset;
+ }
+ else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && autoCursorShouldTrigger)))
+ {
+ int nextCodepointSize = 0;
+ GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
+
+ textBoxCursorIndex += nextCodepointSize;
}
// Move cursor position with mouse
@@ -2701,7 +2827,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
float widthToMouseX = 0;
int mouseCursorIndex = 0;
- for (int i = textIndexOffset; i < textLength; i++)
+ for (int i = textIndexOffset; i < textLength; i += codepointSize)
{
codepoint = GetCodepointNext(&text[i], &codepointSize);
codepointIndex = GetGlyphIndex(guiFont, codepoint);
@@ -2720,7 +2846,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
}
// Check if mouse cursor is at the last position
- int textEndWidth = GetTextWidth(text + textIndexOffset);
+ int textEndWidth = GuiGetTextWidth(text + textIndexOffset);
if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2))
{
mouseCursor.x = textBounds.x + textEndWidth;
@@ -2737,7 +2863,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
else mouseCursor.x = -1;
// Recalculate cursor position.y depending on textBoxCursorIndex
- cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING);
+ cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING);
//if (multiline) cursor.y = GetTextLines()
// Finish text editing on ENTER or mouse click outside bounds
@@ -2745,6 +2871,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
(!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
{
textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index
+ autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes
result = 1;
}
}
@@ -2757,6 +2884,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
{
textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text
+ autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes
result = 1;
}
}
@@ -2825,19 +2953,22 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int
int tempValue = *value;
- Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING), bounds.y,
- bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING)), bounds.height };
- Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
- Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
+ Rectangle valueBoxBounds = {
+ bounds.x + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING),
+ bounds.y,
+ bounds.width - 2*(GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING)), bounds.height };
+ Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height };
+ Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.y,
+ (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height };
Rectangle textBounds = { 0 };
if (text != NULL)
{
- textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
- textBounds.x = bounds.x + bounds.width + GuiGetStyle(SPINNER, TEXT_PADDING);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
- if (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SPINNER, TEXT_PADDING);
+ if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
}
// Update control
@@ -2871,20 +3002,20 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int
// Draw control
//--------------------------------------------------------------------
- result = GuiValueBox(spinner, NULL, &tempValue, minValue, maxValue, editMode);
+ result = GuiValueBox(valueBoxBounds, NULL, &tempValue, minValue, maxValue, editMode);
// Draw value selector custom buttons
// NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
- GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH));
+ GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(VALUEBOX, BORDER_WIDTH));
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
// Draw text label if provided
- GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
//--------------------------------------------------------------------
*value = tempValue;
@@ -2902,13 +3033,13 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
int result = 0;
GuiState state = guiState;
- char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
- sprintf(textValue, "%i", *value);
+ char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 };
+ snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value);
Rectangle textBounds = { 0 };
if (text != NULL)
{
- textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
@@ -2920,7 +3051,6 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
{
Vector2 mousePoint = GetMousePosition();
-
bool valueHasChanged = false;
if (editMode)
@@ -2929,30 +3059,53 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
int keyCount = (int)strlen(textValue);
- // Only allow keys in range [48..57]
- if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
+ // Add or remove minus symbol
+ if (IsKeyPressed(KEY_MINUS))
{
- if (GetTextWidth(textValue) < bounds.width)
+ if (textValue[0] == '-')
{
- int key = GetCharPressed();
- if ((key >= 48) && (key <= 57))
+ for (int i = 0 ; i < keyCount; i++) textValue[i] = textValue[i + 1];
+
+ keyCount--;
+ valueHasChanged = true;
+ }
+ else if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
+ {
+ if (keyCount == 0)
{
- textValue[keyCount] = (char)key;
+ textValue[0] = '0';
+ textValue[1] = '\0';
keyCount++;
- valueHasChanged = true;
}
+
+ for (int i = keyCount ; i > -1; i--) textValue[i + 1] = textValue[i];
+
+ textValue[0] = '-';
+ keyCount++;
+ valueHasChanged = true;
+ }
+ }
+
+ // Add new digit to text value
+ if ((keyCount >= 0) && (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) && (GuiGetTextWidth(textValue) < bounds.width))
+ {
+ int key = GetCharPressed();
+
+ // Only allow keys in range [48..57]
+ if ((key >= 48) && (key <= 57))
+ {
+ textValue[keyCount] = (char)key;
+ keyCount++;
+ valueHasChanged = true;
}
}
// Delete text
- if (keyCount > 0)
+ if ((keyCount > 0) && IsKeyPressed(KEY_BACKSPACE))
{
- if (IsKeyPressed(KEY_BACKSPACE))
- {
- keyCount--;
- textValue[keyCount] = '\0';
- valueHasChanged = true;
- }
+ keyCount--;
+ textValue[keyCount] = '\0';
+ valueHasChanged = true;
}
if (valueHasChanged) *value = TextToInteger(textValue);
@@ -2992,11 +3145,14 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor);
GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))));
- // Draw cursor
+ // Draw cursor rectangle
if (editMode)
{
// NOTE: ValueBox internal text is always centered
- Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) };
+ Rectangle cursor = { bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1,
+ bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + 2,
+ 2, bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2 - 4 };
+ if (cursor.height > bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2;
GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)));
}
@@ -3019,12 +3175,12 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float
GuiState state = guiState;
//char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
- //sprintf(textValue, "%2.2f", *value);
+ //snprintf(textValue, sizeof(textValue), "%2.2f", *value);
- Rectangle textBounds = {0};
+ Rectangle textBounds = { 0 };
if (text != NULL)
{
- textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
@@ -3045,10 +3201,37 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float
int keyCount = (int)strlen(textValue);
+ // Add or remove minus symbol
+ if (IsKeyPressed(KEY_MINUS))
+ {
+ if (textValue[0] == '-')
+ {
+ for (int i = 0; i < keyCount; i++) textValue[i] = textValue[i + 1];
+
+ keyCount--;
+ valueHasChanged = true;
+ }
+ else if (keyCount < (RAYGUI_VALUEBOX_MAX_CHARS - 1))
+ {
+ if (keyCount == 0)
+ {
+ textValue[0] = '0';
+ textValue[1] = '\0';
+ keyCount++;
+ }
+
+ for (int i = keyCount; i > -1; i--) textValue[i + 1] = textValue[i];
+
+ textValue[0] = '-';
+ keyCount++;
+ valueHasChanged = true;
+ }
+ }
+
// Only allow keys in range [48..57]
if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
{
- if (GetTextWidth(textValue) < bounds.width)
+ if (GuiGetTextWidth(textValue) < bounds.width)
{
int key = GetCharPressed();
if (((key >= 48) && (key <= 57)) ||
@@ -3103,7 +3286,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float
if (editMode)
{
// NOTE: ValueBox internal text is always centered
- Rectangle cursor = {bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1,
+ Rectangle cursor = {bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1,
bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4,
bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH)};
GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)));
@@ -3120,7 +3303,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float
// Slider control with pro parameters
// NOTE: Other GuiSlider*() controls use this one
-int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth)
+int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
{
int result = 0;
GuiState state = guiState;
@@ -3129,6 +3312,8 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
if (value == NULL) value = &temp;
float oldValue = *value;
+ int sliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH);
+
Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) };
@@ -3146,7 +3331,7 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
{
state = STATE_PRESSED;
// Get equivalent value and slider position from mousePosition.x
- *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue;
+ *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue;
}
}
else
@@ -3166,7 +3351,7 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
if (!CheckCollisionPointRec(mousePoint, slider))
{
// Get equivalent value and slider position from mousePosition.x
- *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue;
+ *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue;
}
}
else state = STATE_FOCUSED;
@@ -3205,44 +3390,45 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)));
else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED)));
+ else if (state == STATE_DISABLED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_DISABLED)));
// Draw left/right text if provided
if (textLeft != NULL)
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(textLeft);
+ textBounds.width = (float)GuiGetTextWidth(textLeft);
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
- GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))));
+ GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
}
if (textRight != NULL)
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(textRight);
+ textBounds.width = (float)GuiGetTextWidth(textRight);
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
- GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))));
+ GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
}
//--------------------------------------------------------------------
return result;
}
-// Slider control extended, returns selected value and has text
-int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
-{
- return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH));
-}
-
// Slider Bar control extended, returns selected value
int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
{
- return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, 0);
+ int result = 0;
+ int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH);
+ GuiSetStyle(SLIDER, SLIDER_WIDTH, 0);
+ result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue);
+ GuiSetStyle(SLIDER, SLIDER_WIDTH, preSliderWidth);
+
+ return result;
}
// Progress Bar control extended, shows current progress value
@@ -3257,14 +3443,14 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight
// Progress bar
Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH),
bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0,
- bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) };
+ bounds.height - GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) -1 };
// Update control
//--------------------------------------------------------------------
if (*value > maxValue) *value = maxValue;
// WARNING: Working with floats could lead to rounding issues
- if ((state != STATE_DISABLED)) progress.width = (float)(*value/(maxValue - minValue))*bounds.width - ((*value >= maxValue)? (float)(2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)) : 0.0f);
+ if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH));
//--------------------------------------------------------------------
// Draw control
@@ -3282,15 +3468,15 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight
GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
}
- else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
- if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + 1, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
+ if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1}, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
else
{
// Draw borders not yet reached by value
- GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
- GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y + bounds.height - 1, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
- GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y + bounds.height - 1, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
}
// Draw slider internal progress bar (depends on state)
@@ -3301,23 +3487,23 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight
if (textLeft != NULL)
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(textLeft);
+ textBounds.width = (float)GuiGetTextWidth(textLeft);
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
- GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))));
+ GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
}
if (textRight != NULL)
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(textRight);
+ textBounds.width = (float)GuiGetTextWidth(textRight);
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
- GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))));
+ GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
}
//--------------------------------------------------------------------
@@ -3467,11 +3653,11 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd
// Draw visible items
for (int i = 0; ((i < visibleItems) && (text != NULL)); i++)
{
- GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK);
+ if (GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL)) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK);
if (state == STATE_DISABLED)
{
- if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)));
+ if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)));
GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)));
}
@@ -3480,18 +3666,18 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd
if (((startIndex + i) == itemSelected) && (active != NULL))
{
// Draw item selected
- GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)));
+ GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)));
GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)));
}
else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: We want items focused, despite not returned!
{
// Draw item focused
- GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)));
+ GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)));
GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)));
}
else
{
- // Draw item normal
+ // Draw item normal (no rectangle)
GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)));
}
}
@@ -3531,22 +3717,22 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd
return result;
}
-// Color Panel control - Color (RGBA) variant.
+// Color Panel control - Color (RGBA) variant
int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
{
int result = 0;
Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f };
Vector3 hsv = ConvertRGBtoHSV(vcolor);
- Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv.
+ Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv
GuiColorPanelHSV(bounds, text, &hsv);
- // Check if the hsv was changed, only then change the color.
- // This is required, because the Color->HSV->Color conversion has precision errors.
- // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value.
- // Otherwise GuiColorPanel would often modify it's color without user input.
- // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check.
+ // Check if the hsv was changed, only then change the color
+ // This is required, because the Color->HSV->Color conversion has precision errors
+ // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value
+ // Otherwise GuiColorPanel would often modify it's color without user input
+ // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check
if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z)
{
Vector3 rgb = ConvertHSVtoRGB(hsv);
@@ -3570,7 +3756,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
int result = 0;
GuiState state = guiState;
- Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 };
+ Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2,
+ (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW),
+ (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT),
+ (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 };
// Update control
//--------------------------------------------------------------------
@@ -3617,7 +3806,6 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
// Draw control
//--------------------------------------------------------------------
-
// Draw alpha bar: checked background
if (state != STATE_DISABLED)
{
@@ -3755,7 +3943,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color)
Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height };
//Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) };
- // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used.
+ // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used
Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f });
GuiColorBarHue(boundsHue, NULL, &hsv.x);
@@ -3768,8 +3956,8 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color)
return result;
}
-// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering.
-// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB.
+// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering
+// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB
// NOTE: It's divided in multiple controls:
// int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
// int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
@@ -3917,7 +4105,7 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons
buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount;
buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT;
- //int textWidth = GetTextWidth(message) + 2;
+ //int textWidth = GuiGetTextWidth(message) + 2;
Rectangle textBounds = { 0 };
textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
@@ -3981,7 +4169,7 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co
Rectangle textBounds = { 0 };
if (message != NULL)
{
- int textSize = GetTextWidth(message) + 2;
+ int textSize = GuiGetTextWidth(message) + 2;
textBounds.x = bounds.x + bounds.width/2 - textSize/2;
textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
@@ -4221,7 +4409,7 @@ void GuiLoadStyle(const char *fileName)
if (fileDataSize > 0)
{
- unsigned char *fileData = (unsigned char *)RAYGUI_MALLOC(fileDataSize*sizeof(unsigned char));
+ unsigned char *fileData = (unsigned char *)RAYGUI_CALLOC(fileDataSize, sizeof(unsigned char));
fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile);
GuiLoadStyleFromMemory(fileData, fileDataSize);
@@ -4283,8 +4471,6 @@ void GuiLoadStyleDefault(void)
GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
GuiSetStyle(VALUEBOX, TEXT_PADDING, 0);
GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
- GuiSetStyle(SPINNER, TEXT_PADDING, 0);
- GuiSetStyle(SPINNER, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
GuiSetStyle(STATUSBAR, TEXT_PADDING, 8);
GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
@@ -4299,8 +4485,8 @@ void GuiLoadStyleDefault(void)
GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2);
GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16);
GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2);
- GuiSetStyle(SPINNER, SPIN_BUTTON_WIDTH, 24);
- GuiSetStyle(SPINNER, SPIN_BUTTON_SPACING, 2);
+ GuiSetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH, 24);
+ GuiSetStyle(VALUEBOX, SPINNER_BUTTON_SPACING, 2);
GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0);
GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0);
GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6);
@@ -4310,6 +4496,7 @@ void GuiLoadStyleDefault(void)
GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12);
GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28);
GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2);
+ GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH, 1);
GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12);
GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE);
GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8);
@@ -4322,8 +4509,8 @@ void GuiLoadStyleDefault(void)
{
// Unload previous font texture
UnloadTexture(guiFont.texture);
- RL_FREE(guiFont.recs);
- RL_FREE(guiFont.glyphs);
+ RAYGUI_FREE(guiFont.recs);
+ RAYGUI_FREE(guiFont.glyphs);
guiFont.recs = NULL;
guiFont.glyphs = NULL;
@@ -4352,7 +4539,7 @@ const char *GuiIconText(int iconId, const char *text)
if (text != NULL)
{
memset(buffer, 0, 1024);
- sprintf(buffer, "#%03i#", iconId);
+ snprintf(buffer, 1024, "#%03i#", iconId);
for (int i = 5; i < 1024; i++)
{
@@ -4364,7 +4551,7 @@ const char *GuiIconText(int iconId, const char *text)
}
else
{
- sprintf(iconBuffer, "#%03i#", iconId);
+ snprintf(iconBuffer, 16, "#%03i#", iconId);
return iconBuffer;
}
@@ -4430,17 +4617,17 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName)
{
if (loadIconsName)
{
- guiIconsName = (char **)RAYGUI_MALLOC(iconCount*sizeof(char **));
+ guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *));
for (int i = 0; i < iconCount; i++)
{
- guiIconsName[i] = (char *)RAYGUI_MALLOC(RAYGUI_ICON_MAX_NAME_LENGTH);
+ guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char));
fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile);
}
}
else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR);
// Read icons data directly over internal icons array
- fread(guiIconsPtr, sizeof(unsigned int), iconCount*(iconSize*iconSize/32), rgiFile);
+ fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile);
}
fclose(rgiFile);
@@ -4449,6 +4636,56 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName)
return guiIconsName;
}
+// Load icons from memory
+// WARNING: Binary files only
+char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName)
+{
+ unsigned char *fileDataPtr = (unsigned char *)fileData;
+ char **guiIconsName = NULL;
+
+ char signature[5] = { 0 };
+ short version = 0;
+ short reserved = 0;
+ short iconCount = 0;
+ short iconSize = 0;
+
+ memcpy(signature, fileDataPtr, 4);
+ memcpy(&version, fileDataPtr + 4, sizeof(short));
+ memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short));
+ memcpy(&iconCount, fileDataPtr + 4 + 2 + 2, sizeof(short));
+ memcpy(&iconSize, fileDataPtr + 4 + 2 + 2 + 2, sizeof(short));
+ fileDataPtr += 12;
+
+ if ((signature[0] == 'r') &&
+ (signature[1] == 'G') &&
+ (signature[2] == 'I') &&
+ (signature[3] == ' '))
+ {
+ if (loadIconsName)
+ {
+ guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *));
+ for (int i = 0; i < iconCount; i++)
+ {
+ guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char));
+ memcpy(guiIconsName[i], fileDataPtr, RAYGUI_ICON_MAX_NAME_LENGTH);
+ fileDataPtr += RAYGUI_ICON_MAX_NAME_LENGTH;
+ }
+ }
+ else
+ {
+ // Skip icon name data if not required
+ fileDataPtr += iconCount*RAYGUI_ICON_MAX_NAME_LENGTH;
+ }
+
+ int iconDataSize = iconCount*((int)iconSize*(int)iconSize/32)*(int)sizeof(unsigned int);
+ guiIconsPtr = (unsigned int *)RAYGUI_CALLOC(iconDataSize, 1);
+
+ memcpy(guiIconsPtr, fileDataPtr, iconDataSize);
+ }
+
+ return guiIconsName;
+}
+
// Draw selected icon using rectangles pixel-by-pixel
void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color)
{
@@ -4476,12 +4713,73 @@ void GuiSetIconScale(int scale)
if (scale >= 1) guiIconScale = scale;
}
+// Get text width considering gui style and icon size (if required)
+int GuiGetTextWidth(const char *text)
+{
+ #if !defined(ICON_TEXT_PADDING)
+ #define ICON_TEXT_PADDING 4
+ #endif
+
+ Vector2 textSize = { 0 };
+ int textIconOffset = 0;
+
+ if ((text != NULL) && (text[0] != '\0'))
+ {
+ if (text[0] == '#')
+ {
+ for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
+ {
+ if (text[i] == '#')
+ {
+ textIconOffset = i;
+ break;
+ }
+ }
+ }
+
+ text += textIconOffset;
+
+ // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
+ float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+
+ // Custom MeasureText() implementation
+ if ((guiFont.texture.id > 0) && (text != NULL))
+ {
+ // Get size in bytes of text, considering end of line and line break
+ int size = 0;
+ for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++)
+ {
+ if ((text[i] != '\0') && (text[i] != '\n')) size++;
+ else break;
+ }
+
+ float scaleFactor = fontSize/(float)guiFont.baseSize;
+ textSize.y = (float)guiFont.baseSize*scaleFactor;
+ float glyphWidth = 0.0f;
+
+ for (int i = 0, codepointSize = 0; i < size; i += codepointSize)
+ {
+ int codepoint = GetCodepointNext(&text[i], &codepointSize);
+ int codepointIndex = GetGlyphIndex(guiFont, codepoint);
+
+ if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
+ else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
+
+ textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ }
+ }
+
+ if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING);
+ }
+
+ return (int)textSize.x;
+}
+
#endif // !RAYGUI_NO_ICONS
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
-
// Load style from memory
// WARNING: Binary files only
static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
@@ -4567,7 +4865,7 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
{
// Compressed font atlas image data (DEFLATE), it requires DecompressData()
int dataUncompSize = 0;
- unsigned char *compData = (unsigned char *)RAYGUI_MALLOC(fontImageCompSize);
+ unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char));
memcpy(compData, fileDataPtr, fontImageCompSize);
fileDataPtr += fontImageCompSize;
@@ -4581,7 +4879,7 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
else
{
// Font atlas image data is not compressed
- imFont.data = (unsigned char *)RAYGUI_MALLOC(fontImageUncompSize);
+ imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char));
memcpy(imFont.data, fileDataPtr, fontImageUncompSize);
fileDataPtr += fontImageUncompSize;
}
@@ -4609,7 +4907,7 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize))
{
// Recs data is compressed, uncompress it
- unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_MALLOC(recsDataCompressedSize);
+ unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char));
memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize);
fileDataPtr += recsDataCompressedSize;
@@ -4651,7 +4949,7 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize))
{
// Glyphs data is compressed, uncompress it
- unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_MALLOC(glyphsDataCompressedSize);
+ unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char));
memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize);
fileDataPtr += glyphsDataCompressedSize;
@@ -4704,68 +5002,6 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
}
}
-// Gui get text width considering icon
-static int GetTextWidth(const char *text)
-{
- #if !defined(ICON_TEXT_PADDING)
- #define ICON_TEXT_PADDING 4
- #endif
-
- Vector2 textSize = { 0 };
- int textIconOffset = 0;
-
- if ((text != NULL) && (text[0] != '\0'))
- {
- if (text[0] == '#')
- {
- for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
- {
- if (text[i] == '#')
- {
- textIconOffset = i;
- break;
- }
- }
- }
-
- text += textIconOffset;
-
- // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
- float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
-
- // Custom MeasureText() implementation
- if ((guiFont.texture.id > 0) && (text != NULL))
- {
- // Get size in bytes of text, considering end of line and line break
- int size = 0;
- for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++)
- {
- if ((text[i] != '\0') && (text[i] != '\n')) size++;
- else break;
- }
-
- float scaleFactor = fontSize/(float)guiFont.baseSize;
- textSize.y = (float)guiFont.baseSize*scaleFactor;
- float glyphWidth = 0.0f;
-
- for (int i = 0, codepointSize = 0; i < size; i += codepointSize)
- {
- int codepoint = GetCodepointNext(&text[i], &codepointSize);
- int codepointIndex = GetGlyphIndex(guiFont, codepoint);
-
- if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
- else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
-
- textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
- }
- }
-
- if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING);
- }
-
- return (int)textSize.x;
-}
-
// Get text bounds considering control bounds
static Rectangle GetTextBounds(int control, Rectangle bounds)
{
@@ -4786,7 +5022,7 @@ static Rectangle GetTextBounds(int control, Rectangle bounds)
case SLIDER:
case CHECKBOX:
case VALUEBOX:
- case SPINNER:
+ case CONTROL11:
// TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER
default:
{
@@ -4832,7 +5068,8 @@ static const char *GetTextIcon(const char *text, int *iconId)
}
// Get text divided into lines (by line-breaks '\n')
-const char **GetTextLines(const char *text, int *count)
+// WARNING: It returns pointers to new lines but it does not add NULL ('\0') terminator!
+static const char **GetTextLines(const char *text, int *count)
{
#define RAYGUI_MAX_TEXT_LINES 128
@@ -4842,25 +5079,18 @@ const char **GetTextLines(const char *text, int *count)
int textSize = (int)strlen(text);
lines[0] = text;
- int len = 0;
*count = 1;
- //int lineSize = 0; // Stores current line size, not returned
for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
{
if (text[i] == '\n')
{
- //lineSize = len;
k++;
- lines[k] = &text[i + 1]; // WARNING: next value is valid?
- len = 0;
+ lines[k] = &text[i + 1]; // WARNING: next value is valid?
*count += 1;
}
- else len++;
}
- //lines[*count - 1].size = len;
-
return lines;
}
@@ -4936,8 +5166,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
float textBoundsWidthOffset = 0.0f;
// NOTE: We get text size after icon has been processed
- // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed?
- int textSizeX = GetTextWidth(lines[i]);
+ // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed?
+ int textSizeX = GuiGetTextWidth(lines[i]);
// If text requires an icon, add size to measure
if (iconId >= 0)
@@ -5000,7 +5230,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
float textOffsetX = 0.0f;
float glyphWidth = 0;
- int ellipsisWidth = GetTextWidth("...");
+ int ellipsisWidth = GuiGetTextWidth("...");
bool textOverflow = false;
for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize)
{
@@ -5144,13 +5374,13 @@ static void GuiTooltip(Rectangle controlRec)
if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width);
- GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, NULL);
+ GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, NULL);
int textPadding = GuiGetStyle(LABEL, TEXT_PADDING);
int textAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
GuiSetStyle(LABEL, TEXT_PADDING, 0);
GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
- GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, guiTooltipPtr);
+ GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, guiTooltipPtr);
GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment);
GuiSetStyle(LABEL, TEXT_PADDING, textPadding);
}
@@ -5204,7 +5434,7 @@ static const char **GuiTextSplit(const char *text, char delimiter, int *count, i
buffer[i] = '\0'; // Set an end of string at this point
counter++;
- if (counter > RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
+ if (counter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
}
}
@@ -5526,10 +5756,10 @@ static Color GetColor(int hexValue)
{
Color color;
- color.r = (unsigned char)(hexValue >> 24) & 0xFF;
- color.g = (unsigned char)(hexValue >> 16) & 0xFF;
- color.b = (unsigned char)(hexValue >> 8) & 0xFF;
- color.a = (unsigned char)hexValue & 0xFF;
+ color.r = (unsigned char)(hexValue >> 24) & 0xff;
+ color.g = (unsigned char)(hexValue >> 16) & 0xff;
+ color.b = (unsigned char)(hexValue >> 8) & 0xff;
+ color.a = (unsigned char)hexValue & 0xff;
return color;
}
@@ -5562,7 +5792,7 @@ static const char *TextFormat(const char *text, ...)
va_list args;
va_start(args, text);
- vsprintf(buffer, text, args);
+ vsnprintf(buffer, RAYGUI_TEXTFORMAT_MAX_SIZE, text, args);
va_end(args);
return buffer;
@@ -5731,7 +5961,7 @@ static int GetCodepointNext(const char *text, int *codepointSize)
}
else if (0xe0 == (0xf0 & ptr[0]))
{
- // 3 byte UTF-8 codepoint */
+ // 3 byte UTF-8 codepoint
if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks
codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]);
*codepointSize = 3;
diff --git a/examples/examples_list.txt b/examples/examples_list.txt
index 71cda6c1a..605ddf263 100644
--- a/examples/examples_list.txt
+++ b/examples/examples_list.txt
@@ -25,7 +25,7 @@ core;core_3d_camera_mode;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@rays
core;core_3d_camera_free;★☆☆☆;1.3;1.3;2015;2025;"Ramon Santamaria";@raysan5
core;core_3d_camera_first_person;★★☆☆;1.3;1.3;2015;2025;"Ramon Santamaria";@raysan5
core;core_3d_camera_split_screen;★★★☆;3.7;4.0;2021;2025;"Jeffery Myers";@JeffM2501
-core;core_3d_camera_fps;★★★☆;5.5;5.5;2025;2025;"Agnis Aldins";@nezvers
+core;core_3d_camera_fps;★★★☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers
core;core_3d_picking;★★☆☆;1.3;4.0;2015;2025;"Ramon Santamaria";@raysan5
core;core_world_screen;★★☆☆;1.3;1.4;2015;2025;"Ramon Santamaria";@raysan5
core;core_window_flags;★★★☆;3.5;3.5;2020;2025;"Ramon Santamaria";@raysan5
@@ -46,12 +46,14 @@ core;core_automation_events;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria";@r
core;core_high_dpi;★★☆☆;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
core;core_input_actions;★★☆☆;5.5;5.6;2025;2025;"Jett";@JettMonstersGoBoom
core;core_directory_files;★☆☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal
core;core_highdpi_testbed;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
-core;core_screen_recording;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
-core;core_clipboard_text;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary
+core;core_screen_recording;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
+core;core_clipboard_text;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ananth S";@Ananth1839
core;core_text_file_loading;★☆☆☆;5.5;5.6;0;0;"Aanjishnu Bhattacharyya";@NimComPoo-04
+core;core_compute_hash;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ramon Santamaria";@raysan5
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
@@ -80,9 +82,14 @@ shapes;shapes_vector_angle;★★☆☆;1.0;5.0;2023;2025;"Ramon Santamaria";@ra
shapes;shapes_pie_chart;★★★☆;5.5;5.6;2025;2025;"Gideon Serfontein";@GideonSerf
shapes;shapes_kaleidoscope;★★☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal
shapes;shapes_clock_of_clocks;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates
+shapes;shapes_math_sine_cosine;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe
shapes;shapes_mouse_trail;★☆☆☆;5.6;5.6-dev;2025;2025;"Balamurugan R";@Bala050814
shapes;shapes_simple_particles;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
shapes;shapes_starfield_effect;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates
+shapes;shapes_lines_drawing;★☆☆☆;5.6-dev;5.6;2025;2025;"Robin";@RobinsAviary
+shapes;shapes_math_angle_rotation;★☆☆☆;5.6-dev;5.6;2025;2025;"Kris";@krispy-snacc
+shapes;shapes_rlgl_color_wheel;★★★☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary
+shapes;shapes_rlgl_triangle;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary
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
@@ -108,7 +115,9 @@ textures;textures_gif_player;★★★☆;4.2;4.2;2021;2025;"Ramon Santamaria";@
textures;textures_image_kernel;★★★★;1.3;1.3;2015;2025;"Karim Salem";@kimo-s
textures;textures_image_channel;★★☆☆;5.5;5.5;2024;2025;"Bruno Cabral";@brccabral
textures;textures_image_rotate;★★☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5
+textures;textures_screen_buffer;★★☆☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers
textures;textures_textured_curve;★★★☆;4.5;4.5;2022;2025;"Jeffery Myers";@JeffM2501
+textures;textures_sprite_stacking;★★☆☆;5.6-dev;6.0;2025;2025;"Robin";@RobinsAviary
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
@@ -149,6 +158,8 @@ models;models_bone_socket;★★★★;4.5;4.5;2024;2025;"iP";@ipzaur
models;models_tesseract_view;★★☆☆;5.6-dev;5.6-dev;2024;2025;"Timothy van der Valk";@arceryz
models;models_basic_voxel;★★☆☆;5.5;5.5;2025;2025;"Tim Little";@timlittle
models;models_rotating_cube;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe
+models;models_decals;★★★★;5.6-dev;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates
+models;models_directional_billboard;★★☆☆;5.6-dev;5.6;2025;2025;"Robin";@RobinsAviary
shaders;shaders_ascii_rendering;★★☆☆;5.5;5.6;2025;2025;"Maicon Santana";@maiconpintoabreu
shaders;shaders_basic_lighting;★★★★;3.0;4.2;2019;2025;"Chris Camacho";@chriscamacho
shaders;shaders_model_shader;★★☆☆;1.3;3.7;2014;2025;"Ramon Santamaria";@raysan5
@@ -162,6 +173,7 @@ shaders;shaders_texture_outline;★★★☆;4.0;4.0;2021;2025;"Serenity Skiff";
shaders;shaders_texture_waves;★★☆☆;2.5;3.7;2019;2025;"Anata";@anatagawa
shaders;shaders_julia_set;★★★☆;2.5;4.0;2019;2025;"Josh Colclough";@joshcol9232
shaders;shaders_mandelbrot_set;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
+shaders;shaders_color_correction;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
shaders;shaders_eratosthenes_sieve;★★★☆;2.5;4.0;2019;2025;"ProfJski";@ProfJski
shaders;shaders_fog_rendering;★★★☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho
shaders;shaders_simple_mask;★★☆☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho
@@ -188,6 +200,7 @@ audio;audio_mixed_processor;★★★★;4.2;4.2;2023;2025;"hkc";@hatkidchan
audio;audio_stream_effects;★★★★;4.2;5.0;2022;2025;"Ramon Santamaria";@raysan5
audio;audio_sound_multi;★★☆☆;5.0;5.0;2023;2025;"Jeffery Myers";@JeffM2501
audio;audio_sound_positioning;★★☆☆;5.5;5.5;2025;2025;"Le Juez Victor";@Bigfoot71
+audio;audio_spectrum_visualizer;★★★☆;6.0;5.6-dev;2025;2025;"IANN";@meisei4
others;rlgl_standalone;★★★★;1.6;4.0;2014;2025;"Ramon Santamaria";@raysan5
others;rlgl_compute_shader;★★★★;4.0;4.0;2021;2025;"Teddy Astie";@tsnake41
others;easings_testbed;★★★☆;2.5;3.0;2019;2025;"Juan Miguel López";@flashback-fx
diff --git a/examples/examples_template.c b/examples/examples_template.c
index 39a19351d..211749e82 100644
--- a/examples/examples_template.c
+++ b/examples/examples_template.c
@@ -36,7 +36,7 @@
10. Have fun!
- The following files must be updated when adding a new example,
+ The following files must be updated when adding a new example,
but it can be automatically done using the raylib provided tool: rexm
So, no worries if just the .c/.png are provided when adding the example.
diff --git a/examples/models/models_decals.c b/examples/models/models_decals.c
new file mode 100644
index 000000000..f556139e1
--- /dev/null
+++ b/examples/models/models_decals.c
@@ -0,0 +1,605 @@
+/*******************************************************************************************
+*
+* raylib [models] example - decals
+*
+* Example complexity rating: [★★★★] 4/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*
+* Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
+* Based on previous work by @mrdoob
+*
+* 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 JP Mortiboys (@themushroompirates) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+
+#include // Required for: memcpy()
+
+#undef FLT_MAX
+#define FLT_MAX 340282346638528859811704183484516925440.0f // Maximum value of a float, from bit pattern 01111111011111111111111111111111
+
+#define MAX_DECALS 256
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct MeshBuilder {
+ int vertexCount;
+ int vertexCapacity;
+ Vector3 *vertices;
+ Vector2 *uvs;
+} MeshBuilder;
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3]);
+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 bool GuiButton(Rectangle rec, const char *label);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ SetConfigFlags(FLAG_MSAA_4X_HINT);
+ InitWindow(screenWidth, screenHeight, "raylib [models] example - decals");
+
+ // Define the camera to look into our 3d world
+ Camera camera = { 0 };
+ camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position
+ camera.target = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera looking at point
+ camera.up = (Vector3){ 0.0f, 1.6f, 0.0f }; // Camera up vector (rotation towards target)
+ camera.fovy = 45.0f; // Camera field-of-view Y
+ camera.projection = CAMERA_PERSPECTIVE; // Camera projection type
+
+ // Load character model
+ Model model = LoadModel("resources/models/obj/character.obj");
+
+ // Apply character skin
+ Texture2D modelTexture = LoadTexture("resources/models/obj/character_diffuse.png");
+ SetTextureFilter(modelTexture, TEXTURE_FILTER_BILINEAR);
+ model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = modelTexture;
+
+ BoundingBox modelBBox = GetMeshBoundingBox(model.meshes[0]); // Get mesh bounding box
+
+ camera.target = Vector3Lerp(modelBBox.min, modelBBox.max, 0.5f);
+ camera.position = Vector3Scale(modelBBox.max, 1.0f);
+ camera.position.x *= 0.1f;
+
+ float modelSize = fminf(
+ fminf(fabsf(modelBBox.max.x - modelBBox.min.x), fabsf(modelBBox.max.y - modelBBox.min.y)),
+ fabsf(modelBBox.max.z - modelBBox.min.z));
+
+ camera.position = (Vector3){ 0.0f, modelBBox.max.y*1.2f, modelSize*3.0f };
+
+ float decalSize = modelSize*0.25f;
+ float decalOffset = 0.01f;
+
+ Model placementCube = LoadModelFromMesh(GenMeshCube(decalSize, decalSize, decalSize));
+ placementCube.materials[0].maps[0].color = LIME;
+
+ Material decalMaterial = LoadMaterialDefault();
+ decalMaterial.maps[0].color = YELLOW;
+
+ Image decalImage = LoadImage("resources/raylib_logo.png");
+ ImageResizeNN(&decalImage, decalImage.width/4, decalImage.height/4);
+ Texture decalTexture = LoadTextureFromImage(decalImage);
+ UnloadImage(decalImage);
+
+ SetTextureFilter(decalTexture, TEXTURE_FILTER_BILINEAR);
+ decalMaterial.maps[MATERIAL_MAP_DIFFUSE].texture = decalTexture;
+ decalMaterial.maps[MATERIAL_MAP_DIFFUSE].color = RAYWHITE;
+
+ bool showModel = true;
+ Model decalModels[MAX_DECALS] = { 0 };
+ int decalCount = 0;
+
+ 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
+ //----------------------------------------------------------------------------------
+ if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) UpdateCamera(&camera, CAMERA_THIRD_PERSON);
+
+ // Display information about closest hit
+ RayCollision collision = { 0 };
+ collision.distance = FLT_MAX;
+ collision.hit = false;
+
+ // Get mouse ray
+ Ray ray = GetScreenToWorldRay(GetMousePosition(), camera);
+
+ // Check ray collision against bounding box first, before trying the full ray-mesh test
+ RayCollision boxHitInfo = GetRayCollisionBox(ray, modelBBox);
+
+ if ((boxHitInfo.hit) && (decalCount < MAX_DECALS))
+ {
+ // Check ray collision against model meshes
+ RayCollision meshHitInfo = { 0 };
+ for (int m = 0; m < model.meshCount; m++)
+ {
+ // NOTE: We consider the model.transform for the collision check but
+ // it can be checked against any transform Matrix, used when checking against same
+ // model drawn multiple times with multiple transforms
+ meshHitInfo = GetRayCollisionMesh(ray, model.meshes[m], model.transform);
+ if (meshHitInfo.hit)
+ {
+ // Save the closest hit mesh
+ if (!collision.hit || (collision.distance > meshHitInfo.distance)) collision = meshHitInfo;
+ }
+ }
+
+ if (meshHitInfo.hit) collision = meshHitInfo;
+ }
+
+ // Add decal to mesh on hit point
+ if (collision.hit && IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (decalCount < MAX_DECALS))
+ {
+ // Create the transformation to project the decal
+ Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f));
+ Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){ 0.0f, 1.0f, 0.0f });
+
+ // Spin the placement around a bit
+ splat = MatrixMultiply(splat, MatrixRotateZ(DEG2RAD*((float)GetRandomValue(-180, 180))));
+
+ Mesh decalMesh = GenMeshDecal(model, splat, decalSize, decalOffset);
+
+ if (decalMesh.vertexCount > 0)
+ {
+ int decalIndex = decalCount++;
+ decalModels[decalIndex] = LoadModelFromMesh(decalMesh);
+ decalModels[decalIndex].materials[0].maps[0] = decalMaterial.maps[0];
+ }
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(RAYWHITE);
+
+ BeginMode3D(camera);
+ // Draw the model at the origin and default scale
+ if (showModel) DrawModel(model, (Vector3){0.0f, 0.0f, 0.0f}, 1.0f, WHITE);
+
+ // Draw the decal models
+ for (int i = 0; i < decalCount; i++) DrawModel(decalModels[i], (Vector3){0}, 1.0f, WHITE);
+
+ // If we hit the mesh, draw the box for the decal
+ if (collision.hit)
+ {
+ Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f));
+ Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){0,1,0});
+ placementCube.transform = MatrixInvert(splat);
+ DrawModel(placementCube, (Vector3){0}, 1.0f, Fade(WHITE, 0.5f));
+ }
+
+ DrawGrid(10, 10.0f);
+ EndMode3D();
+
+ float yPos = 10;
+ float x0 = GetScreenWidth() - 300;
+ float x1 = x0 + 100;
+ float x2 = x1 + 100;
+
+ DrawText("Vertices", x1, yPos, 10, LIME);
+ DrawText("Triangles", x2, yPos, 10, LIME);
+ yPos += 15;
+
+ int vertexCount = 0;
+ int triangleCount = 0;
+
+ for (int i = 0; i < model.meshCount; i++)
+ {
+ vertexCount += model.meshes[i].vertexCount;
+ 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);
+ yPos += 15;
+
+ for (int i = 0; i < decalCount; i++)
+ {
+ if (i == 20)
+ {
+ DrawText("...", x0, 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);
+ yPos += 15;
+ }
+
+ vertexCount += decalModels[i].meshes[0].vertexCount;
+ 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);
+ 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 + 110, screenHeight - 100, 100, 60 }, "Clear Decals"))
+ {
+ // Clear decals, unload all decal models
+ for (int i = 0; i < decalCount; i++) UnloadModel(decalModels[i]);
+ decalCount = 0;
+ }
+
+ DrawFPS(10, 10);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadModel(model);
+ UnloadTexture(modelTexture);
+
+ // Unload decal models
+ for (int i = 0; i < decalCount; i++) UnloadModel(decalModels[i]);
+
+ UnloadTexture(decalTexture);
+
+ FreeDecalMeshData(); // Free the data for decal generation
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+// Add triangles to mesh builder (dynamic array manager)
+static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3])
+{
+ // Reallocate and copy if we need to
+ if (mb->vertexCapacity <= (mb->vertexCount + 3))
+ {
+ int newVertexCapacity = (1 + (mb->vertexCapacity/256))*256;
+ Vector3 *newVertices = (Vector3 *)MemAlloc(newVertexCapacity*sizeof(Vector3));
+
+ if (mb->vertexCapacity > 0)
+ {
+ memcpy(newVertices, mb->vertices, mb->vertexCount*sizeof(Vector3));
+ MemFree(mb->vertices);
+ }
+
+ mb->vertices = newVertices;
+ mb->vertexCapacity = newVertexCapacity;
+ }
+
+ // Add 3 vertices
+ int index = mb->vertexCount;
+ mb->vertexCount += 3;
+
+ for (int i = 0; i < 3; i++) mb->vertices[index+i] = vertices[i];
+}
+
+// Free mesh builder
+static void FreeMeshBuilder(MeshBuilder *mb)
+{
+ MemFree(mb->vertices);
+ if (mb->uvs) MemFree(mb->uvs);
+ *mb = (MeshBuilder){ 0 };
+}
+
+// Build a Mesh from MeshBuilder data
+static Mesh BuildMesh(MeshBuilder *mb)
+{
+ Mesh outMesh = { 0 };
+
+ outMesh.vertexCount = mb->vertexCount;
+ outMesh.triangleCount = mb->vertexCount/3;
+ outMesh.vertices = MemAlloc(outMesh.vertexCount*3*sizeof(float));
+ if (mb->uvs) outMesh.texcoords = MemAlloc(outMesh.vertexCount*2*sizeof(float));
+
+ for (int i = 0; i < mb->vertexCount; i++)
+ {
+ outMesh.vertices[3*i+0] = mb->vertices[i].x;
+ outMesh.vertices[3*i+1] = mb->vertices[i].y;
+ outMesh.vertices[3*i+2] = mb->vertices[i].z;
+
+ if (mb->uvs)
+ {
+ outMesh.texcoords[2*i+0] = mb->uvs[i].x;
+ outMesh.texcoords[2*i+1] = mb->uvs[i].y;
+ }
+ }
+
+ UploadMesh(&outMesh, false);
+
+ return outMesh;
+}
+
+// Clip segment
+static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s)
+{
+ float d0 = Vector3DotProduct(v0, p) - s;
+ float d1 = Vector3DotProduct(v1, p) - s;
+ float s0 = d0/(d0 - d1);
+
+ Vector3 position = Vector3Lerp(v0, v1, s0);
+
+ return position;
+}
+
+// Generate mesh decals for provided model
+static Mesh GenMeshDecal(Model target, Matrix projection, float decalSize, float decalOffset)
+{
+ // We're going to use these to build up our decal meshes
+ // They'll resize automatically as we go, we'll free them at the end
+ static MeshBuilder meshBuilders[2] = { 0 };
+
+ // Ugly way of telling us to free the static MeshBuilder data
+ if (target.meshCount == -1)
+ {
+ FreeMeshBuilder(&meshBuilders[0]);
+ FreeMeshBuilder(&meshBuilders[1]);
+ return (Mesh){ 0 };
+ }
+
+ // We're going to need the inverse matrix
+ Matrix invProj = MatrixInvert(projection);
+
+ // Reset the mesh builders
+ meshBuilders[0].vertexCount = 0;
+ meshBuilders[1].vertexCount = 0;
+
+ // We'll be flip-flopping between the two mesh builders
+ // Reading from one and writing to the other, then swapping
+ int mbIndex = 0;
+
+ // First pass, just get any triangle inside the bounding box (for each mesh of the model)
+ for (int meshIndex = 0; meshIndex < target.meshCount; meshIndex++)
+ {
+ Mesh mesh = target.meshes[meshIndex];
+ for (int tri = 0; tri < mesh.triangleCount; tri++)
+ {
+ Vector3 vertices[3] = { 0 };
+
+ // The way we calculate the vertices of the mesh triangle
+ // depend on whether the mesh vertices are indexed or not
+ if (mesh.indices == 0)
+ {
+ for (int v = 0; v < 3; v++)
+ {
+ vertices[v] = (Vector3){
+ mesh.vertices[3*3*tri + 3*v + 0],
+ mesh.vertices[3*3*tri + 3*v + 1],
+ mesh.vertices[3*3*tri + 3*v + 2]
+ };
+ }
+ }
+ else
+ {
+ for (int v = 0; v < 3; v++)
+ {
+ vertices[v] = (Vector3){
+ mesh.vertices[ 3*mesh.indices[3*tri+0] + v],
+ mesh.vertices[ 3*mesh.indices[3*tri+1] + v],
+ mesh.vertices[ 3*mesh.indices[3*tri+2] + v]
+ };
+ }
+ }
+
+ // Transform all 3 vertices of the triangle
+ // and check if they are inside our decal box
+ int insideCount = 0;
+ for (int i = 0; i < 3; i++)
+ {
+ // To projection space
+ Vector3 v = Vector3Transform(vertices[i], projection);
+
+ if ((fabsf(v.x) < decalSize) || (fabsf(v.y) <= decalSize) || (fabsf(v.z) <= decalSize)) insideCount++;
+
+ // We need to keep the transformed vertex
+ vertices[i] = v;
+ }
+
+ // If any of them are inside, we add the triangle - we'll clip it later
+ if (insideCount > 0) AddTriangleToMeshBuilder(&meshBuilders[mbIndex], vertices);
+ }
+ }
+
+ // Clipping time! We need to clip against all 6 directions
+ Vector3 planes[6] = {
+ { 1, 0, 0 },
+ { -1, 0, 0 },
+ { 0, 1, 0 },
+ { 0, -1, 0 },
+ { 0, 0, 1 },
+ { 0, 0, -1 }
+ };
+
+ for (int face = 0; face < 6; face++)
+ {
+ // Swap current model builder (so we read from the one we just wrote to)
+ mbIndex = 1 - mbIndex;
+
+ MeshBuilder *inMesh = &meshBuilders[1 - mbIndex];
+ MeshBuilder *outMesh = &meshBuilders[mbIndex];
+
+ // Reset write builder
+ outMesh->vertexCount = 0;
+
+ float s = 0.5f*decalSize;
+
+ for (int i = 0; i < inMesh->vertexCount; i += 3)
+ {
+ Vector3 nV1, nV2, nV3, nV4;
+
+ float d1 = Vector3DotProduct(inMesh->vertices[ i + 0 ], planes[face] ) - s;
+ float d2 = Vector3DotProduct(inMesh->vertices[ i + 1 ], planes[face] ) - s;
+ float d3 = Vector3DotProduct(inMesh->vertices[ i + 2 ], planes[face] ) - s;
+
+ int v1Out = (d1 > 0);
+ int v2Out = (d2 > 0);
+ int v3Out = (d3 > 0);
+
+ // Calculate, how many vertices of the face lie outside of the clipping plane
+ int total = v1Out + v2Out + v3Out;
+
+ switch (total)
+ {
+ case 0:
+ {
+ // The entire face lies inside of the plane, no clipping needed
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){inMesh->vertices[i], inMesh->vertices[i+1], inMesh->vertices[i+2]});
+ } break;
+ case 1:
+ {
+ // One vertex lies outside of the plane, perform clipping
+ if (v1Out)
+ {
+ nV1 = inMesh->vertices[i + 1];
+ nV2 = inMesh->vertices[i + 2];
+ nV3 = ClipSegment(inMesh->vertices[i], nV1, planes[face], s);
+ nV4 = ClipSegment(inMesh->vertices[i], nV2, planes[face], s);
+ }
+
+ if (v2Out)
+ {
+ nV1 = inMesh->vertices[i];
+ nV2 = inMesh->vertices[i + 2];
+ nV3 = ClipSegment(inMesh->vertices[i + 1], nV1, planes[face], s);
+ nV4 = ClipSegment(inMesh->vertices[i + 1], nV2, planes[face], s);
+
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV3, nV2, nV1});
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV2, nV3, nV4});
+ break;
+ }
+
+ if (v3Out)
+ {
+ nV1 = inMesh->vertices[i];
+ nV2 = inMesh->vertices[i + 1];
+ nV3 = ClipSegment(inMesh->vertices[i + 2], nV1, planes[face], s);
+ nV4 = ClipSegment(inMesh->vertices[i + 2], nV2, planes[face], s);
+ }
+
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV4, nV3, nV2});
+ } break;
+ case 2:
+ {
+ // Two vertices lies outside of the plane, perform clipping
+ if (!v1Out)
+ {
+ nV1 = inMesh->vertices[i];
+ nV2 = ClipSegment(nV1, inMesh->vertices[i + 1], planes[face], s);
+ nV3 = ClipSegment(nV1, inMesh->vertices[i + 2], planes[face], s);
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ }
+
+ if (!v2Out)
+ {
+ nV1 = inMesh->vertices[i + 1];
+ nV2 = ClipSegment(nV1, inMesh->vertices[i + 2], planes[face], s);
+ nV3 = ClipSegment(nV1, inMesh->vertices[i], planes[face], s);
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ }
+
+ if (!v3Out)
+ {
+ nV1 = inMesh->vertices[i + 2];
+ nV2 = ClipSegment(nV1, inMesh->vertices[i], planes[face], s);
+ nV3 = ClipSegment(nV1, inMesh->vertices[i + 1], planes[face], s);
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ }
+ } break;
+ case 3: // The entire face lies outside of the plane, so let's discard the corresponding vertices
+ default: break;
+ }
+ }
+ }
+
+ // Now we just need to re-transform the vertices
+ MeshBuilder *theMesh = &meshBuilders[mbIndex];
+
+ // Allocate room for UVs
+ if (theMesh->vertexCount > 0)
+ {
+ theMesh->uvs = (Vector2 *)MemAlloc(sizeof(Vector2)*theMesh->vertexCount);
+
+ for (int i = 0; i < theMesh->vertexCount; i++)
+ {
+ // Calculate the UVs based on the projected coords
+ // They are clipped to (-decalSize .. decalSize) and we want them (0..1)
+ theMesh->uvs[i].x = (theMesh->vertices[i].x/decalSize + 0.5f);
+ theMesh->uvs[i].y = (theMesh->vertices[i].y/decalSize + 0.5f);
+
+ // Tiny nudge in the normal direction so it renders properly over the mesh
+ theMesh->vertices[i].z -= decalOffset;
+
+ // From projection space to world space
+ theMesh->vertices[i] = Vector3Transform(theMesh->vertices[i], invProj);
+ }
+
+ // Decal model data ready, create the mesh and return it
+ return BuildMesh(theMesh);
+ }
+ else
+ {
+ // Return a blank mesh as there's nothing to add
+ return (Mesh){ 0 };
+ }
+}
+
+// Button UI element
+static bool GuiButton(Rectangle rec, const char *label)
+{
+ Color bgColor = GRAY;
+ bool pressed = false;
+
+ if (CheckCollisionPointRec(GetMousePosition(), rec))
+ {
+ bgColor = LIGHTGRAY;
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) pressed = true;
+ }
+
+ DrawRectangleRec(rec, bgColor);
+ DrawRectangleLinesEx(rec, 2.0f, DARKGRAY);
+
+ float fontSize = 10.0f;
+ float 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);
+
+ return pressed;
+}
diff --git a/examples/models/models_decals.png b/examples/models/models_decals.png
new file mode 100644
index 000000000..6bdbaf17c
Binary files /dev/null and b/examples/models/models_decals.png differ
diff --git a/examples/models/models_directional_billboard.c b/examples/models/models_directional_billboard.c
new file mode 100644
index 000000000..e2c75c15a
--- /dev/null
+++ b/examples/models/models_directional_billboard.c
@@ -0,0 +1,116 @@
+/*******************************************************************************************
+*
+* raylib [models] example - directional billboard
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6
+*
+* Example contributed by Robin (@RobinsAviary) 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 Robin (@RobinsAviary)
+* Killbot art by patvanmackelberg https://opengameart.org/content/killbot-8-directional under CC0
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "raymath.h"
+#include
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [models] example - directional billboard");
+
+ // Set up the camera
+ Camera camera = { 0 };
+ camera.position = (Vector3){ 2.0f, 1.0f, 2.0f }; // Starting position
+ camera.target = (Vector3){ 0.0f, 0.5f, 0.0f }; // Target position
+ camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Up vector
+ camera.fovy = 45.0f; // FOV
+ camera.projection = CAMERA_PERSPECTIVE; // Projection type (Standard 3D perspective)
+
+ // Load billboard texture
+ Texture skillbot = LoadTexture("resources/skillbot.png");
+
+ // Timer to update animation
+ float anim_timer = 0.0f;
+ // Animation frame
+ unsigned int anim = 0;
+
+ SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ UpdateCamera(&camera, CAMERA_ORBITAL);
+
+ // Update timer with delta time
+ anim_timer += GetFrameTime();
+
+ // Update frame index after a certain amount of time (half a second)
+ if (anim_timer > 0.5f)
+ {
+ anim_timer = 0.0f;
+ anim += 1;
+ }
+
+ // Reset frame index to zero on overflow
+ if (anim >= 4) anim = 0;
+
+ // Find the current direction frame based on the camera position to the billboard object
+ float dir = (float)floor(((Vector2Angle((Vector2){ 2.0f, 0.0f }, (Vector2){ camera.position.x, camera.position.z })/PI)*4.0f) + 0.25f);
+
+ // Correct frame index if angle is negative
+ if (dir < 0.0f)
+ {
+ dir = 8.0f - (float)abs((int)dir);
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ BeginMode3D(camera);
+
+ DrawGrid(10, 1.0f);
+
+ // Draw billboard pointing straight up to the sky, rotated relative to the camera and offset from the bottom
+ DrawBillboardPro(camera, skillbot, (Rectangle){ 0.0f + (anim*24.0f), 0.0f + (dir*24.0f), 24.0f, 24.0f }, Vector3Zero(), (Vector3){ 0.0f, 1.0f, 0.0f }, Vector2One(), (Vector2){ 0.5f, 0.0f }, 0, WHITE);
+
+ EndMode3D();
+
+ // Render various variables for reference
+ DrawText(TextFormat("animation: %d", anim), 10, 10, 20, DARKGRAY);
+ DrawText(TextFormat("direction frame: %.0f", dir), 10, 40, 20, DARKGRAY);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ // Unload billboard texture
+ UnloadTexture(skillbot);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/models/models_directional_billboard.png b/examples/models/models_directional_billboard.png
new file mode 100644
index 000000000..cbbe11065
Binary files /dev/null and b/examples/models/models_directional_billboard.png differ
diff --git a/examples/models/models_loading_vox.c b/examples/models/models_loading_vox.c
index 956c181a0..06dc651d7 100644
--- a/examples/models/models_loading_vox.c
+++ b/examples/models/models_loading_vox.c
@@ -35,171 +35,157 @@
//------------------------------------------------------------------------------------
int main(void)
{
- // Initialization
- //--------------------------------------------------------------------------------------
- const int screenWidth = 800;
- const int screenHeight = 450;
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
- const char *voxFileNames[] = {
- "resources/models/vox/chr_knight.vox",
- "resources/models/vox/chr_sword.vox",
- "resources/models/vox/monu9.vox",
- "resources/models/vox/fez.vox"
- };
+ const char *voxFileNames[] = {
+ "resources/models/vox/chr_knight.vox",
+ "resources/models/vox/chr_sword.vox",
+ "resources/models/vox/monu9.vox",
+ "resources/models/vox/fez.vox"
+ };
- InitWindow(screenWidth, screenHeight, "raylib [models] example - loading vox");
+ InitWindow(screenWidth, screenHeight, "raylib [models] example - loading vox");
- // Define the camera to look into our 3d world
- Camera camera = { 0 };
- camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position
- camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point
- camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
- camera.fovy = 45.0f; // Camera field-of-view Y
- camera.projection = CAMERA_PERSPECTIVE; // Camera projection type
+ // Define the camera to look into our 3d world
+ Camera camera = { 0 };
+ camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position
+ camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point
+ camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
+ camera.fovy = 45.0f; // Camera field-of-view Y
+ camera.projection = CAMERA_PERSPECTIVE; // Camera projection type
- // Load MagicaVoxel files
- Model models[MAX_VOX_FILES] = { 0 };
+ // Load MagicaVoxel files
+ Model models[MAX_VOX_FILES] = { 0 };
- for (int i = 0; i < MAX_VOX_FILES; i++)
- {
- // Load VOX file and measure time
- double t0 = GetTime()*1000.0;
- models[i] = LoadModel(voxFileNames[i]);
- double t1 = GetTime()*1000.0;
+ for (int i = 0; i < MAX_VOX_FILES; i++)
+ {
+ // Load VOX file and measure time
+ double t0 = GetTime()*1000.0;
+ models[i] = LoadModel(voxFileNames[i]);
+ double t1 = GetTime()*1000.0;
- TraceLog(LOG_WARNING, TextFormat("[%s] File loaded in %.3f ms", voxFileNames[i], t1 - t0));
+ TraceLog(LOG_INFO, TextFormat("[%s] Model file loaded in %.3f ms", voxFileNames[i], t1 - t0));
- // Compute model translation matrix to center model on draw position (0, 0 , 0)
- BoundingBox bb = GetModelBoundingBox(models[i]);
- Vector3 center = { 0 };
- center.x = bb.min.x + (((bb.max.x - bb.min.x)/2));
- center.z = bb.min.z + (((bb.max.z - bb.min.z)/2));
+ // Compute model translation matrix to center model on draw position (0, 0 , 0)
+ BoundingBox bb = GetModelBoundingBox(models[i]);
+ Vector3 center = { 0 };
+ center.x = bb.min.x + (((bb.max.x - bb.min.x)/2));
+ center.z = bb.min.z + (((bb.max.z - bb.min.z)/2));
- Matrix matTranslate = MatrixTranslate(-center.x, 0, -center.z);
- models[i].transform = matTranslate;
- }
+ Matrix matTranslate = MatrixTranslate(-center.x, 0, -center.z);
+ models[i].transform = matTranslate;
+ }
- int currentModel = 0;
+ int currentModel = 0;
+ Vector3 modelpos = { 0 };
+ Vector3 camerarot = { 0 };
- // Load voxel shader
- Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/voxel_lighting.vs", GLSL_VERSION),
- TextFormat("resources/shaders/glsl%i/voxel_lighting.fs", GLSL_VERSION));
+ // Load voxel shader
+ Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/voxel_lighting.vs", GLSL_VERSION),
+ TextFormat("resources/shaders/glsl%i/voxel_lighting.fs", GLSL_VERSION));
- // Get some required shader locations
- shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos");
- // NOTE: "matModel" location name is automatically assigned on shader loading,
- // no need to get the location again if using that uniform name
- //shader.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel");
+ // Get some required shader locations
+ shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos");
+ // NOTE: "matModel" location name is automatically assigned on shader loading,
+ // no need to get the location again if using that uniform name
+ //shader.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel");
- // Ambient light level (some basic lighting)
- int ambientLoc = GetShaderLocation(shader, "ambient");
- SetShaderValue(shader, ambientLoc, (float[4]) { 0.1f, 0.1f, 0.1f, 1.0f }, SHADER_UNIFORM_VEC4);
+ // Ambient light level (some basic lighting)
+ int ambientLoc = GetShaderLocation(shader, "ambient");
+ SetShaderValue(shader, ambientLoc, (float[4]) { 0.1f, 0.1f, 0.1f, 1.0f }, SHADER_UNIFORM_VEC4);
- // Assign out lighting shader to model
- for (int i = 0; i < MAX_VOX_FILES; i++)
- {
- Model m = models[i];
- for (int j = 0; j < m.materialCount; j++)
- {
- m.materials[j].shader = shader;
- }
- }
+ // Assign out lighting shader to model
+ for (int i = 0; i < MAX_VOX_FILES; i++)
+ {
+ for (int j = 0; j < models[i].materialCount; j++) models[i].materials[j].shader = shader;
+ }
- // Create lights
- Light lights[MAX_LIGHTS] = { 0 };
- lights[0] = CreateLight(LIGHT_POINT, (Vector3) { -20, 20, -20 }, Vector3Zero(), GRAY, shader);
- lights[1] = CreateLight(LIGHT_POINT, (Vector3) { 20, -20, 20 }, Vector3Zero(), GRAY, shader);
- lights[2] = CreateLight(LIGHT_POINT, (Vector3) { -20, 20, 20 }, Vector3Zero(), GRAY, shader);
- lights[3] = CreateLight(LIGHT_POINT, (Vector3) { 20, -20, -20 }, Vector3Zero(), GRAY, shader);
+ // Create lights
+ Light lights[MAX_LIGHTS] = { 0 };
+ lights[0] = CreateLight(LIGHT_POINT, (Vector3) { -20, 20, -20 }, Vector3Zero(), GRAY, shader);
+ lights[1] = CreateLight(LIGHT_POINT, (Vector3) { 20, -20, 20 }, Vector3Zero(), GRAY, shader);
+ lights[2] = CreateLight(LIGHT_POINT, (Vector3) { -20, 20, 20 }, Vector3Zero(), GRAY, shader);
+ lights[3] = CreateLight(LIGHT_POINT, (Vector3) { 20, -20, -20 }, Vector3Zero(), GRAY, shader);
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ //--------------------------------------------------------------------------------------
- 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
+ //----------------------------------------------------------------------------------
+ if (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE))
+ {
+ const Vector2 mouseDelta = GetMouseDelta();
+ camerarot.x = mouseDelta.x*0.05f;
+ camerarot.y = mouseDelta.y*0.05f;
+ }
+ else
+ {
+ camerarot.x = 0;
+ camerarot.y = 0;
+ }
- //--------------------------------------------------------------------------------------
- Vector3 modelpos = { 0 };
- Vector3 camerarot = { 0 };
+ UpdateCameraPro(&camera,
+ (Vector3){ (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f, // Move forward-backward
+ (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f, // Move right-left
+ 0.0f }, // Move up-down
+ camerarot, // Camera rotation
+ GetMouseWheelMove()*-2.0f); // Move to target (zoom)
- // Main game loop
- while (!WindowShouldClose()) // Detect window close button or ESC key
- {
- // Update
- //----------------------------------------------------------------------------------
- if (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE))
- {
- const Vector2 mouseDelta = GetMouseDelta();
- camerarot.x = mouseDelta.x*0.05f;
- camerarot.y = mouseDelta.y*0.05f;
- }
- else
- {
- camerarot.x = 0;
- camerarot.y = 0;
- }
+ // Cycle between models on mouse click
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) currentModel = (currentModel + 1)%MAX_VOX_FILES;
- UpdateCameraPro(&camera,
- (Vector3) {
- (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))*0.1f - // Move forward-backward
- (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))*0.1f,
- (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))*0.1f - // Move right-left
- (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))*0.1f,
- 0.0f // Move up-down
- },
- camerarot,
- GetMouseWheelMove()*-2.0f); // Move to target (zoom)
+ // Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
+ float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };
+ SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], cameraPos, SHADER_UNIFORM_VEC3);
- // Cycle between models on mouse click
- if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) currentModel = (currentModel + 1) % MAX_VOX_FILES;
+ // Update light values (actually, only enable/disable them)
+ for (int i = 0; i < MAX_LIGHTS; i++) UpdateLightValues(shader, lights[i]);
+ //----------------------------------------------------------------------------------
- // Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
- float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z };
- SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], cameraPos, SHADER_UNIFORM_VEC3);
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
- // Update light values (actually, only enable/disable them)
- for (int i = 0; i < MAX_LIGHTS; i++) UpdateLightValues(shader, lights[i]);
+ ClearBackground(RAYWHITE);
- //----------------------------------------------------------------------------------
- // Draw
- //----------------------------------------------------------------------------------
- BeginDrawing();
+ // Draw 3D model
+ BeginMode3D(camera);
+ DrawModel(models[currentModel], modelpos, 1.0f, WHITE);
+ DrawGrid(10, 1.0);
- ClearBackground(RAYWHITE);
+ // Draw spheres to show where the lights are
+ for (int i = 0; i < MAX_LIGHTS; i++)
+ {
+ if (lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, lights[i].color);
+ else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(lights[i].color, 0.3f));
+ }
+ EndMode3D();
- // Draw 3D model
- BeginMode3D(camera);
+ // Display info
+ DrawRectangle(10, 40, 340, 70, Fade(SKYBLUE, 0.5f));
+ DrawRectangleLines(10, 40, 340, 70, Fade(DARKBLUE, 0.5f));
+ DrawText("- MOUSE LEFT BUTTON: CYCLE VOX MODELS", 20, 50, 10, BLUE);
+ DrawText("- MOUSE MIDDLE BUTTON: ZOOM OR ROTATE CAMERA", 20, 70, 10, BLUE);
+ DrawText("- UP-DOWN-LEFT-RIGHT KEYS: MOVE CAMERA", 20, 90, 10, BLUE);
+ DrawText(TextFormat("Model file: %s", GetFileName(voxFileNames[currentModel])), 10, 10, 20, GRAY);
- DrawModel(models[currentModel], modelpos, 1.0f, WHITE);
- DrawGrid(10, 1.0);
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
- // Draw spheres to show where the lights are
- for (int i = 0; i < MAX_LIGHTS; i++)
- {
- if (lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, lights[i].color);
- else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(lights[i].color, 0.3f));
- }
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ // Unload models data (GPU VRAM)
+ for (int i = 0; i < MAX_VOX_FILES; i++) UnloadModel(models[i]);
- EndMode3D();
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
- // Display info
- DrawRectangle(10, 400, 340, 60, Fade(SKYBLUE, 0.5f));
- DrawRectangleLines(10, 400, 340, 60, Fade(DARKBLUE, 0.5f));
- DrawText("MOUSE LEFT BUTTON to CYCLE VOX MODELS", 40, 410, 10, BLUE);
- DrawText("MOUSE MIDDLE BUTTON to ZOOM OR ROTATE CAMERA", 40, 420, 10, BLUE);
- DrawText("UP-DOWN-LEFT-RIGHT KEYS to MOVE CAMERA", 40, 430, 10, BLUE);
- DrawText(TextFormat("File: %s", GetFileName(voxFileNames[currentModel])), 10, 10, 20, GRAY);
-
- EndDrawing();
- //----------------------------------------------------------------------------------
- }
-
- // De-Initialization
- //--------------------------------------------------------------------------------------
- // Unload models data (GPU VRAM)
- for (int i = 0; i < MAX_VOX_FILES; i++) UnloadModel(models[i]);
-
- CloseWindow(); // Close window and OpenGL context
- //--------------------------------------------------------------------------------------
-
- return 0;
+ return 0;
}
-
-
diff --git a/examples/models/models_point_rendering.c b/examples/models/models_point_rendering.c
index 3a93fc8d9..71b907225 100644
--- a/examples/models/models_point_rendering.c
+++ b/examples/models/models_point_rendering.c
@@ -32,7 +32,7 @@ static Mesh GenMeshPoints(int numPoints);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
-int main()
+int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
@@ -57,7 +57,7 @@ int main()
Mesh mesh = GenMeshPoints(numPoints);
Model model = LoadModelFromMesh(mesh);
- //SetTargetFPS(60);
+ SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
@@ -92,15 +92,12 @@ int main()
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
+
ClearBackground(BLACK);
BeginMode3D(camera);
-
// The new method only uploads the points once to the GPU
- if (useDrawModelPoints)
- {
- DrawModelPoints(model, position, 1.0f, WHITE);
- }
+ if (useDrawModelPoints) DrawModelPoints(model, position, 1.0f, WHITE);
else
{
// The old method must continually draw the "points" (lines)
@@ -124,17 +121,16 @@ int main()
// Draw a unit sphere for reference
DrawSphereWires(position, 1.0f, 10, 10, YELLOW);
-
EndMode3D();
// Draw UI text
- DrawText(TextFormat("Point Count: %d", numPoints), 20, screenHeight - 50, 40, WHITE);
- DrawText("Up - increase points", 20, 70, 20, WHITE);
- DrawText("Down - decrease points", 20, 100, 20, WHITE);
- DrawText("Space - drawing function", 20, 130, 20, WHITE);
+ DrawText(TextFormat("Point Count: %d", numPoints), 10, screenHeight - 50, 40, WHITE);
+ DrawText("UP - Increase points", 10, 40, 20, WHITE);
+ DrawText("DOWN - Decrease points", 10, 70, 20, WHITE);
+ DrawText("SPACE - Drawing function", 10, 100, 20, WHITE);
- if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 20, 160, 20, GREEN);
- else DrawText("Using: DrawPoint3D()", 20, 160, 20, RED);
+ if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 10, 130, 20, GREEN);
+ else DrawText("Using: DrawPoint3D()", 10, 130, 20, RED);
DrawFPS(10, 10);
diff --git a/examples/models/models_rotating_cube.c b/examples/models/models_rotating_cube.c
index 930dae516..c5b633fea 100644
--- a/examples/models/models_rotating_cube.c
+++ b/examples/models/models_rotating_cube.c
@@ -5,7 +5,7 @@
* Example complexity rating: [★☆☆☆] 1/4
*
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
-*
+*
* Example contributed by Jopestpe (@jopestpe)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
@@ -48,7 +48,7 @@ int main(void)
model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture;
float rotation = 0.0f;
-
+
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
@@ -59,7 +59,7 @@ int main(void)
//----------------------------------------------------------------------------------
rotation += 1.0f;
//----------------------------------------------------------------------------------
-
+
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
@@ -67,13 +67,13 @@ int main(void)
ClearBackground(RAYWHITE);
BeginMode3D(camera);
-
- // Draw model defining: position, size, rotation-axis, rotation (degrees), size, and tint-color
- DrawModelEx(model, (Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.5f, 1.0f, 0.0f },
+
+ // Draw model defining: position, size, rotation-axis, rotation (degrees), size, and tint-color
+ DrawModelEx(model, (Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.5f, 1.0f, 0.0f },
rotation, (Vector3){ 1.0f, 1.0f, 1.0f }, WHITE);
-
+
DrawGrid(10, 1.0f);
-
+
EndMode3D();
DrawFPS(10, 10);
diff --git a/examples/models/models_skybox_rendering.c b/examples/models/models_skybox_rendering.c
index ddce6a28f..9359e03dc 100644
--- a/examples/models/models_skybox_rendering.c
+++ b/examples/models/models_skybox_rendering.c
@@ -54,7 +54,8 @@ int main(void)
Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f);
Model skybox = LoadModelFromMesh(cube);
- // Set this to true to use an HDR Texture, Note that raylib must be built with HDR Support for this to work SUPPORT_FILEFORMAT_HDR
+ // Set this to true to use an HDR Texture
+ // NOTE: raylib must be built with HDR Support for this to work: SUPPORT_FILEFORMAT_HDR
bool useHDR = false;
// Load skybox shader and set required locations
@@ -63,8 +64,8 @@ int main(void)
TextFormat("resources/shaders/glsl%i/skybox.fs", GLSL_VERSION));
SetShaderValue(skybox.materials[0].shader, GetShaderLocation(skybox.materials[0].shader, "environmentMap"), (int[1]){ MATERIAL_MAP_CUBEMAP }, SHADER_UNIFORM_INT);
- SetShaderValue(skybox.materials[0].shader, GetShaderLocation(skybox.materials[0].shader, "doGamma"), (int[1]) { useHDR ? 1 : 0 }, SHADER_UNIFORM_INT);
- SetShaderValue(skybox.materials[0].shader, GetShaderLocation(skybox.materials[0].shader, "vflipped"), (int[1]){ useHDR ? 1 : 0 }, SHADER_UNIFORM_INT);
+ SetShaderValue(skybox.materials[0].shader, GetShaderLocation(skybox.materials[0].shader, "doGamma"), (int[1]){ useHDR? 1 : 0 }, SHADER_UNIFORM_INT);
+ SetShaderValue(skybox.materials[0].shader, GetShaderLocation(skybox.materials[0].shader, "vflipped"), (int[1]){ useHDR? 1 : 0 }, SHADER_UNIFORM_INT);
// Load cubemap shader and setup required shader locations
Shader shdrCubemap = LoadShader(TextFormat("resources/shaders/glsl%i/cubemap.vs", GLSL_VERSION),
@@ -91,9 +92,11 @@ int main(void)
}
else
{
- Image img = LoadImage("resources/skybox.png");
- skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(img, CUBEMAP_LAYOUT_AUTO_DETECT); // CUBEMAP_LAYOUT_PANORAMA
- UnloadImage(img);
+ // TODO: WARNING: On PLATFORM_WEB it requires a big amount of memory to process input image
+ // and generate the required cubemap image to be passed to rlLoadTextureCubemap()
+ Image image = LoadImage("resources/skybox.png");
+ skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(image, CUBEMAP_LAYOUT_AUTO_DETECT);
+ UnloadImage(image);
}
DisableCursor(); // Limit cursor to relative movement inside the window
@@ -132,9 +135,9 @@ int main(void)
}
else
{
- Image img = LoadImage(droppedFiles.paths[0]);
- skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(img, CUBEMAP_LAYOUT_AUTO_DETECT);
- UnloadImage(img);
+ Image image = LoadImage(droppedFiles.paths[0]);
+ skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = LoadTextureCubemap(image, CUBEMAP_LAYOUT_AUTO_DETECT);
+ UnloadImage(image);
}
TextCopy(skyboxFileName, droppedFiles.paths[0]);
diff --git a/examples/models/models_waving_cubes.c b/examples/models/models_waving_cubes.c
index 51febf39d..7996c1c8a 100644
--- a/examples/models/models_waving_cubes.c
+++ b/examples/models/models_waving_cubes.c
@@ -22,7 +22,7 @@
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
-int main()
+int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
diff --git a/examples/models/resources/models/obj/character.mtl b/examples/models/resources/models/obj/character.mtl
new file mode 100644
index 000000000..96b272b29
--- /dev/null
+++ b/examples/models/resources/models/obj/character.mtl
@@ -0,0 +1,12 @@
+# Blender MTL File: 'None'
+# Material Count: 1
+
+newmtl skin
+Ns 86.470579
+Ka 1.000000 1.000000 1.000000
+Kd 0.800000 0.800000 0.800000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 0.000000
+illum 9
diff --git a/examples/models/resources/models/obj/character.obj b/examples/models/resources/models/obj/character.obj
new file mode 100644
index 000000000..be7e47863
--- /dev/null
+++ b/examples/models/resources/models/obj/character.obj
@@ -0,0 +1,3454 @@
+# Blender v2.83.2 OBJ File: ''
+# www.blender.org
+mtllib character.mtl
+o characterMedium
+v 0.410751 3.453012 0.200817
+v 0.176931 3.516046 -0.492870
+v 0.176931 3.069885 -0.492870
+v 0.193767 2.961166 0.489574
+v 0.193767 3.452389 0.455386
+v 0.400606 2.998632 0.217911
+v 0.400606 3.035397 -0.212411
+v 0.410751 3.483905 -0.212411
+v 0.188780 3.698580 0.247489
+v 0.188780 3.731344 -0.224509
+v 0.188780 2.741884 -0.224509
+v 0.188780 2.664058 0.281677
+v 0.338542 2.788810 0.205190
+v 0.323730 3.496119 -0.410188
+v 0.323730 3.441588 0.352035
+v 0.338542 3.642598 0.223085
+v 0.338542 2.852551 -0.208748
+v 0.176295 2.876968 -0.427238
+v 0.323730 3.072495 -0.410188
+v 0.193131 2.735571 0.459728
+v 0.323730 2.996823 0.381949
+v 0.338542 3.655763 -0.208748
+v 0.176295 3.660861 -0.399904
+v 0.193131 3.617279 0.405342
+v 0.180529 3.275434 -0.517282
+v 0.197366 3.218354 0.478425
+v 0.409350 3.230555 0.194491
+v 0.403118 3.253443 -0.219099
+v 0.429171 3.009897 0.014208
+v 0.439316 3.472003 0.009934
+v 0.198303 3.743473 0.020506
+v 0.198303 2.669343 0.029053
+v 0.286423 2.928726 -0.357824
+v 0.286423 2.767836 0.367046
+v 0.286423 3.636701 -0.357824
+v 0.301893 3.594941 0.358830
+v 0.357587 2.802252 0.025342
+v 0.322536 3.266541 -0.423686
+v 0.327481 3.227505 0.360122
+v 0.357587 3.654801 0.017864
+v 0.434369 3.238045 0.005717
+v 0.111250 2.648599 -0.113100
+v 0.129723 2.623841 0.000772
+v 0.110155 2.617475 0.111510
+v 0.098894 2.551101 -0.119944
+v 0.140309 2.525439 -0.009396
+v 0.098894 2.517193 0.100599
+v 0.208678 2.515187 -0.122760
+v 0.245812 2.502890 -0.002447
+v 0.208678 2.483677 0.109699
+v 0.271570 2.206755 -0.145013
+v 0.319908 2.187368 0.032075
+v 0.271570 2.177688 0.191096
+v 0.303127 1.441376 -0.106186
+v 0.355115 1.410218 0.080975
+v 0.289850 1.402806 0.240428
+v 0.260948 1.763152 0.232137
+v 0.307393 1.770383 0.075582
+v 0.260948 1.788246 -0.089088
+v 0.247213 2.324639 0.153241
+v 0.247213 2.354879 -0.163591
+v 0.115069 1.290704 0.269082
+v 0.017798 1.168477 -0.035384
+v 0.183067 1.284675 -0.183271
+v 0.084912 3.522239 -0.501146
+v 0.084912 3.064342 -0.512888
+v 0.084912 2.943401 0.510254
+v 0.084912 3.458095 0.476066
+v 0.090590 3.723567 0.254122
+v 0.090590 3.746935 -0.231142
+v 0.090590 2.722769 -0.231142
+v 0.090590 2.643034 0.288310
+v 0.084607 2.864935 -0.440534
+v 0.084607 2.702693 0.473189
+v 0.084607 3.673055 -0.413200
+v 0.084607 3.629352 0.421907
+v 0.086637 3.278739 -0.526585
+v 0.086636 3.215177 0.507309
+v 0.095154 3.754534 0.020506
+v 0.060191 2.658972 -0.154656
+v 0.053444 2.613782 0.136010
+v 0.047516 2.554504 -0.139039
+v 0.047516 2.514067 0.124693
+v 0.100126 2.519134 -0.142488
+v 0.100126 2.479805 0.136555
+v 0.130264 2.209162 -0.175208
+v 0.130264 2.175989 0.226360
+v 0.145386 1.454041 -0.168399
+v 0.145386 1.399946 0.290329
+v 0.125174 1.790136 -0.123980
+v 0.125174 1.762047 0.266843
+v 0.118592 2.321896 0.187758
+v 0.118592 2.358026 -0.194066
+v 0.064118 0.867640 -0.065778
+v 0.139275 0.844466 0.140266
+v 0.257486 0.890374 -0.145882
+v 0.359097 0.900878 0.061199
+v 0.074195 0.752219 -0.105874
+v 0.147259 0.698792 0.087905
+v 0.263534 0.755735 -0.191206
+v 0.364126 0.730329 0.010206
+v 0.092608 0.518587 -0.156357
+v 0.161208 0.488124 0.011298
+v 0.257654 0.503497 -0.235568
+v 0.342662 0.497755 -0.059963
+v 0.100936 1.052740 0.183646
+v 0.362186 1.124208 0.082677
+v 0.035605 1.007707 -0.051248
+v 0.244578 1.066754 -0.153714
+v 0.055029 1.214705 -0.163442
+v 0.255589 1.328226 0.210676
+v 0.140172 0.882954 -0.138230
+v 0.262287 0.869133 0.135226
+v 0.152224 0.756748 -0.186384
+v 0.268705 0.704238 0.080827
+v 0.163237 0.508650 -0.221611
+v 0.266438 0.484781 0.003128
+v 0.113057 1.038591 -0.152600
+v 0.246990 1.089520 0.173845
+v 0.054756 1.198160 0.101170
+v 0.310361 1.325851 -0.067512
+v 0.060255 0.853278 0.049460
+v 0.343613 0.899484 -0.056313
+v 0.071380 0.718974 0.002418
+v 0.350589 0.741909 -0.110914
+v 0.091684 0.503566 -0.057160
+v 0.339310 0.499423 -0.163148
+v 0.344611 1.099522 -0.066307
+v 0.028575 1.027615 0.082498
+v 0.455190 2.450647 -0.082374
+v 0.462809 2.465601 0.006612
+v 0.448972 2.441031 0.081440
+v 0.434408 2.252116 -0.088512
+v 0.448014 2.213438 0.029647
+v 0.428671 2.233589 0.135751
+v 0.442147 2.332059 0.110493
+v 1.328482 2.369486 -0.025838
+v 0.448115 2.351334 -0.094647
+v 0.717408 2.422497 -0.064617
+v 0.727228 2.428632 0.006928
+v 0.711866 2.404597 0.073618
+v 0.698886 2.236229 -0.077850
+v 0.706620 2.199933 0.027458
+v 0.693774 2.219717 0.102536
+v 0.705784 2.307478 0.109237
+v 0.945792 2.289033 0.134562
+v 0.711103 2.324656 -0.097021
+v 1.329792 2.357378 0.034079
+v 1.323088 2.354750 0.089928
+v 1.305094 2.214479 -0.036920
+v 1.300746 2.180356 0.051271
+v 1.300117 2.200886 0.110979
+v 1.313884 2.273778 0.121339
+v 1.509906 2.320435 -0.046242
+v 1.319060 2.287920 -0.055202
+v 0.930288 2.200850 0.122871
+v 0.936312 2.211617 -0.068478
+v 0.952059 2.307598 -0.088140
+v 0.936310 2.172915 0.046302
+v 0.968273 2.418404 0.023926
+v 0.961626 2.413997 -0.054054
+v 0.955096 2.394653 0.096614
+v 0.330881 2.488142 0.003375
+v 0.305188 2.468017 0.099597
+v 0.315496 2.226114 -0.122984
+v 0.320825 2.354873 -0.139518
+v 0.303439 2.230228 0.158131
+v 0.309166 2.327404 0.136383
+v 0.348316 2.192029 0.031171
+v 0.315498 2.485255 -0.117814
+v 1.401711 2.330388 -0.053750
+v 1.402313 2.325266 0.037149
+v 1.368471 2.326110 0.116069
+v 1.380995 2.227921 -0.070645
+v 1.378716 2.209659 0.062973
+v 1.340428 2.225900 0.146512
+v 1.351661 2.274332 0.162481
+v 1.795120 2.206148 -0.017422
+v 1.399326 2.275373 -0.096810
+v 1.525167 2.312472 0.043161
+v 1.504512 2.310743 0.126497
+v 1.486518 2.218486 -0.062778
+v 1.505804 2.196043 0.068815
+v 1.481542 2.209545 0.157907
+v 1.495307 2.257487 0.173365
+v 1.626749 2.173789 0.059473
+v 1.500484 2.266789 -0.090058
+v 1.809535 2.198612 0.054630
+v 1.788894 2.200041 0.121791
+v 1.762707 2.137646 -0.030749
+v 1.779807 2.119442 0.075304
+v 1.756964 2.132012 0.147105
+v 1.774950 2.163872 0.159563
+v 1.797727 2.160531 0.057501
+v 1.780926 2.169733 -0.052734
+v 1.607462 2.193023 -0.059653
+v 1.616252 2.226447 0.154119
+v 1.602486 2.185360 0.140125
+v 1.646111 2.273569 0.036250
+v 1.630851 2.280393 -0.044683
+v 1.621429 2.234418 -0.084348
+v 1.625457 2.272087 0.111690
+v 1.379530 2.252804 0.224500
+v 1.371148 2.204101 0.211689
+v 1.461364 2.245535 0.213279
+v 1.452982 2.196833 0.200468
+v 1.424118 2.225873 0.279904
+v 1.419068 2.175998 0.270241
+v 1.481443 2.235304 0.220739
+v 1.476394 2.185430 0.211076
+v 1.509712 2.198027 0.341520
+v 1.506171 2.163050 0.334743
+v 1.549915 2.204642 0.300027
+v 1.546374 2.169665 0.293251
+v 0.262061 0.256721 -0.179629
+v 0.125851 0.263241 -0.073885
+v 0.264548 0.252916 -0.065338
+v 0.141817 0.268149 -0.192735
+v 0.270091 0.253667 -0.122910
+v 0.125675 0.264206 -0.137064
+v 0.206420 0.264077 -0.203655
+v 0.230977 0.000692 0.289805
+v 0.342493 0.000690 0.270761
+v 0.163985 0.000688 -0.230879
+v 0.270393 0.000686 -0.245194
+v 0.144177 0.000691 0.033839
+v 0.288000 0.000691 0.291562
+v 0.372899 0.000687 -0.002369
+v 0.227192 0.000686 -0.254522
+v 0.257567 0.000689 0.016768
+v 0.137243 0.000692 0.170051
+v 0.391563 0.000688 0.127957
+v 0.273728 0.000690 0.160912
+v 0.338169 0.000686 -0.146682
+v 0.108448 0.000690 -0.113832
+v 0.239700 0.000687 -0.142594
+v 0.167568 0.000692 0.233611
+v 0.383765 0.000689 0.197667
+v 0.281809 0.000691 0.232984
+v 0.309290 0.000686 -0.218277
+v 0.229983 0.000687 -0.223266
+v 0.118360 0.000689 -0.190507
+v 0.130135 0.000690 -0.034828
+v 0.349068 0.000687 -0.064281
+v 0.249487 0.000688 -0.055304
+v 0.387775 0.000687 0.061323
+v 0.265648 0.000689 0.088840
+v 0.129773 0.000692 0.103416
+v 0.232718 0.085533 0.288274
+v 0.363576 0.085530 0.268239
+v 0.154897 0.085528 -0.243375
+v 0.260403 0.080414 -0.243911
+v 0.128135 0.085532 0.035193
+v 0.299506 0.085532 0.289325
+v 0.383870 0.085527 -0.003576
+v 0.214830 0.085527 -0.261124
+v 0.132008 0.085533 0.181044
+v 0.405763 0.085528 0.135972
+v 0.339530 0.085526 -0.157915
+v 0.096516 0.085530 -0.123177
+v 0.167580 0.085533 0.249102
+v 0.395495 0.085529 0.210885
+v 0.304116 0.077122 -0.204676
+v 0.110617 0.085530 -0.206279
+v 0.114426 0.085531 -0.038332
+v 0.357741 0.085527 -0.069335
+v 0.401320 0.085528 0.064622
+v 0.123244 0.085533 0.109694
+v 0.235360 0.121957 0.282892
+v 0.342479 0.121955 0.271351
+v 0.155498 0.140203 -0.234632
+v 0.258674 0.141703 -0.233045
+v 0.147943 0.140206 0.045064
+v 0.367478 0.140202 0.015099
+v 0.209678 0.140554 -0.248081
+v 0.151504 0.140207 0.167879
+v 0.387046 0.140203 0.131704
+v 0.326827 0.140201 -0.142554
+v 0.113117 0.142231 -0.125673
+v 0.174977 0.140207 0.230696
+v 0.378520 0.140204 0.201276
+v 0.291506 0.139635 -0.192779
+v 0.127237 0.141691 -0.187001
+v 0.134396 0.140206 -0.008056
+v 0.354118 0.140202 -0.035038
+v 0.382905 0.140203 0.065200
+v 0.143705 0.140207 0.101330
+v 0.244012 0.174412 0.250246
+v 0.312400 0.174411 0.237719
+v 0.154929 0.197920 -0.224667
+v 0.244653 0.200889 -0.226557
+v 0.200247 0.182648 0.039626
+v 0.320975 0.193251 0.026737
+v 0.200815 0.200081 -0.230324
+v 0.176892 0.181218 0.144060
+v 0.349336 0.193278 0.128903
+v 0.299466 0.209667 -0.141685
+v 0.117610 0.203001 -0.122411
+v 0.197637 0.187029 0.207154
+v 0.340156 0.188834 0.188204
+v 0.275703 0.199069 -0.189682
+v 0.130048 0.198871 -0.180965
+v 0.183002 0.199344 -0.013043
+v 0.295575 0.215862 -0.011766
+v 0.341167 0.191744 0.072780
+v 0.191423 0.184576 0.092515
+v 0.338887 0.000686 -0.105818
+v 0.244594 0.000688 -0.098949
+v 0.116803 0.000690 -0.073995
+v 0.348659 0.085527 -0.113812
+v 0.102306 0.085531 -0.080271
+v 0.339594 0.140202 -0.089574
+v 0.118165 0.140205 -0.060612
+v 0.304014 0.215861 -0.085942
+v 0.129758 0.215864 -0.062783
+v 0.261646 0.242079 -0.188306
+v 0.230162 0.234212 -0.224732
+v 0.193922 0.242264 -0.221201
+v 0.165941 0.245963 -0.208302
+v 0.280499 0.229314 -0.077601
+v 0.279868 0.243470 -0.137553
+v 0.127675 0.236447 -0.179834
+v 0.120948 0.240070 -0.122668
+v 0.128658 0.229317 -0.058955
+v 0.189612 0.231437 -0.029962
+v 0.259835 0.229315 -0.044259
+v 0.190037 0.256893 -0.038329
+v -0.410268 3.453012 0.200817
+v -0.176448 3.516046 -0.492870
+v -0.176448 3.069885 -0.492870
+v -0.193285 2.961166 0.489574
+v -0.193285 3.452389 0.455386
+v -0.400123 2.998632 0.217911
+v -0.400123 3.035397 -0.212411
+v -0.410268 3.483905 -0.212411
+v -0.188297 3.698580 0.247489
+v -0.188298 3.731344 -0.224509
+v -0.188298 2.741884 -0.224509
+v -0.188298 2.664058 0.281677
+v -0.338060 2.788810 0.205190
+v -0.323248 3.496119 -0.410188
+v -0.323248 3.441588 0.352035
+v -0.338059 3.642598 0.223085
+v -0.338060 2.852551 -0.208748
+v -0.175812 2.876968 -0.427238
+v -0.323248 3.072495 -0.410188
+v -0.192649 2.735571 0.459728
+v -0.323248 2.996823 0.381949
+v -0.338060 3.655763 -0.208748
+v -0.175812 3.660861 -0.399904
+v -0.192648 3.617279 0.405342
+v -0.180047 3.275434 -0.517282
+v 0.000241 3.527937 -0.505363
+v 0.000241 3.059241 -0.517105
+v -0.196883 3.218354 0.478425
+v 0.000241 2.927055 0.514236
+v 0.000241 3.457695 0.495095
+v -0.408868 3.230555 0.194491
+v -0.402636 3.253443 -0.219099
+v -0.428688 3.009897 0.014208
+v -0.438833 3.472003 0.009934
+v 0.000241 3.735282 0.260225
+v 0.000241 3.756304 -0.237245
+v -0.197821 3.743473 0.020506
+v -0.197821 2.669343 0.029053
+v 0.000241 2.716923 -0.237245
+v 0.000241 2.623689 0.294413
+v -0.285941 2.928726 -0.357824
+v -0.285941 2.767836 0.367046
+v -0.285941 3.636701 -0.357824
+v -0.301410 3.594941 0.358830
+v -0.357105 2.802252 0.025342
+v 0.000241 2.853864 -0.452768
+v -0.322054 3.266541 -0.423686
+v 0.000241 2.695371 0.485576
+v -0.326999 3.227505 0.360122
+v -0.357105 3.654801 0.017864
+v 0.000241 3.684277 -0.419779
+v 0.000241 3.640461 0.434294
+v 0.000241 3.279187 -0.533908
+v 0.000241 3.212254 0.507793
+v -0.433886 3.238045 0.005717
+v 0.000241 3.765371 0.020506
+v 0.000241 2.608866 0.157665
+v 0.000241 2.662452 -0.152277
+v -0.110768 2.648599 -0.113100
+v -0.129241 2.623841 0.000772
+v -0.109673 2.617475 0.111510
+v 0.000241 2.511192 0.146864
+v 0.000241 2.557636 -0.161210
+v -0.098412 2.551101 -0.119944
+v -0.139827 2.525439 -0.009396
+v -0.098412 2.517193 0.100599
+v 0.000241 2.476242 0.161267
+v 0.000241 2.522766 -0.165241
+v -0.208196 2.515187 -0.122760
+v -0.245330 2.502890 -0.002447
+v -0.208196 2.483677 0.109699
+v 0.000241 2.174426 0.258809
+v 0.000241 2.211377 -0.202993
+v -0.271088 2.206755 -0.145013
+v -0.319426 2.187368 0.032075
+v -0.271088 2.177688 0.191096
+v 0.000241 1.398135 0.309651
+v 0.000241 1.463624 -0.206620
+v -0.302644 1.441376 -0.106186
+v -0.354291 1.410232 0.081480
+v -0.288561 1.402802 0.240545
+v 0.000241 1.761031 0.298778
+v -0.260465 1.763152 0.232137
+v -0.306911 1.770383 0.075582
+v -0.260465 1.788246 -0.089088
+v 0.000241 1.791875 -0.156086
+v -0.246731 2.324639 0.153241
+v -0.246731 2.354880 -0.163592
+v 0.000241 2.360921 -0.206229
+v 0.000241 2.319373 0.219519
+v -0.113364 1.290662 0.268232
+v -0.018429 1.168483 -0.035181
+v -0.184480 1.284700 -0.183080
+v -0.000316 1.168480 -0.035282
+v -0.084430 3.522239 -0.501146
+v -0.084430 3.064342 -0.512888
+v -0.084430 2.943401 0.510254
+v -0.084429 3.458095 0.476066
+v -0.090108 3.723567 0.254122
+v -0.090108 3.746935 -0.231142
+v -0.090108 2.722769 -0.231142
+v -0.090108 2.643034 0.288310
+v -0.084125 2.864935 -0.440534
+v -0.084125 2.702693 0.473189
+v -0.084125 3.673055 -0.413200
+v -0.084125 3.629352 0.421907
+v -0.086154 3.278739 -0.526585
+v -0.086154 3.215177 0.507309
+v -0.094671 3.754534 0.020506
+v -0.059709 2.658972 -0.154656
+v -0.052962 2.613782 0.136010
+v -0.047034 2.554504 -0.139039
+v -0.047034 2.514068 0.124693
+v -0.099643 2.519134 -0.142488
+v -0.099643 2.479805 0.136555
+v -0.129782 2.209162 -0.175208
+v -0.129782 2.175989 0.226360
+v -0.144904 1.454041 -0.168399
+v -0.144904 1.399946 0.290329
+v -0.124691 1.790136 -0.123980
+v -0.124691 1.762047 0.266843
+v -0.118110 2.321897 0.187758
+v -0.118110 2.358026 -0.194066
+v 0.000241 1.284807 0.281643
+v 0.000241 1.284807 -0.179892
+v -0.065606 0.867575 -0.068223
+v -0.137184 0.844409 0.139088
+v -0.260316 0.890440 -0.144957
+v -0.358304 0.900967 0.063854
+v -0.076447 0.752149 -0.108154
+v -0.146162 0.698757 0.086858
+v -0.267231 0.755783 -0.190189
+v -0.364320 0.730428 0.012933
+v -0.095873 0.518518 -0.158302
+v -0.161565 0.488099 0.010515
+v -0.262272 0.503526 -0.234639
+v -0.344217 0.497838 -0.057588
+v -0.097973 1.052652 0.181831
+v -0.360885 1.124295 0.085420
+v -0.036763 1.007622 -0.054166
+v -0.247441 1.066813 -0.152981
+v -0.057083 1.214724 -0.162813
+v -0.253453 1.328216 0.210857
+v -0.001001 1.201565 -0.157958
+v -0.142896 0.882948 -0.139342
+v -0.260245 0.869150 0.136185
+v -0.155858 0.756730 -0.187298
+v -0.267706 0.704276 0.081887
+v -0.167628 0.508623 -0.222321
+v -0.266919 0.484820 0.004171
+v -0.115942 1.038571 -0.154153
+v -0.244148 1.089522 0.174570
+v -0.053830 1.198178 0.101779
+v -0.310544 1.325896 -0.066387
+v 0.000415 1.184651 0.093554
+v -0.059751 0.853190 0.046927
+v -0.344866 0.899585 -0.053907
+v -0.071771 0.718897 0.000070
+v -0.352883 0.742005 -0.108402
+v -0.093234 0.503499 -0.059137
+v -0.342657 0.499502 -0.160814
+v -0.345917 1.099626 -0.063848
+v -0.027398 1.027503 0.079441
+v -0.454708 2.450647 -0.082374
+v -0.462326 2.465601 0.006612
+v -0.448490 2.441031 0.081440
+v -0.433925 2.252116 -0.088512
+v -0.447532 2.213438 0.029647
+v -0.428189 2.233589 0.135751
+v -0.441665 2.332059 0.110493
+v -1.328000 2.369487 -0.025839
+v -0.447632 2.351334 -0.094647
+v -0.716926 2.422497 -0.064618
+v -0.726745 2.428632 0.006928
+v -0.711384 2.404597 0.073617
+v -0.698403 2.236229 -0.077851
+v -0.706138 2.199933 0.027457
+v -0.693291 2.219717 0.102535
+v -0.705302 2.307478 0.109236
+v -0.945310 2.289035 0.134561
+v -0.710620 2.324656 -0.097021
+v -1.329309 2.357379 0.034077
+v -1.322606 2.354751 0.089927
+v -1.304611 2.214480 -0.036921
+v -1.300263 2.180357 0.051270
+v -1.299635 2.200886 0.110977
+v -1.313401 2.273779 0.121337
+v -1.509424 2.320436 -0.046244
+v -1.318578 2.287921 -0.055203
+v -0.929806 2.200852 0.122871
+v -0.935830 2.211618 -0.068479
+v -0.951576 2.307599 -0.088141
+v -0.935828 2.172916 0.046301
+v -0.967791 2.418405 0.023925
+v -0.961144 2.413998 -0.054055
+v -0.954614 2.394654 0.096613
+v -0.330399 2.488142 0.003375
+v -0.304706 2.468017 0.099597
+v -0.315013 2.226115 -0.122984
+v -0.320343 2.354873 -0.139518
+v -0.302957 2.230229 0.158131
+v -0.308683 2.327404 0.136383
+v -0.347834 2.192029 0.031171
+v -0.315016 2.485255 -0.117814
+v -1.401229 2.330389 -0.053752
+v -1.401832 2.325267 0.037148
+v -1.367989 2.326111 0.116068
+v -1.380512 2.227921 -0.070646
+v -1.378233 2.209659 0.062972
+v -1.339946 2.225900 0.146510
+v -1.351179 2.274333 0.162479
+v -1.794637 2.206148 -0.017425
+v -1.398844 2.275373 -0.096812
+v -1.524685 2.312473 0.043160
+v -1.504030 2.310744 0.126495
+v -1.486035 2.218486 -0.062780
+v -1.505322 2.196043 0.068813
+v -1.481060 2.209546 0.157905
+v -1.494826 2.257488 0.173364
+v -1.626266 2.173790 0.059471
+v -1.500002 2.266789 -0.090059
+v -1.809052 2.198613 0.054628
+v -1.788411 2.200042 0.121789
+v -1.762224 2.137647 -0.030751
+v -1.779324 2.119443 0.075302
+v -1.756481 2.132013 0.147103
+v -1.774468 2.163872 0.159561
+v -1.797244 2.160531 0.057499
+v -1.780442 2.169733 -0.052736
+v -1.606979 2.193023 -0.059655
+v -1.615770 2.226447 0.154117
+v -1.602004 2.185361 0.140123
+v -1.645628 2.273569 0.036248
+v -1.630368 2.280394 -0.044685
+v -1.620946 2.234419 -0.084350
+v -1.624974 2.272088 0.111689
+v -1.379048 2.252805 0.224499
+v -1.370666 2.204103 0.211687
+v -1.460882 2.245536 0.213278
+v -1.452500 2.196834 0.200466
+v -1.423636 2.225874 0.279902
+v -1.418586 2.176000 0.270239
+v -1.480961 2.235306 0.220738
+v -1.475912 2.185432 0.211075
+v -1.509230 2.198029 0.341518
+v -1.505689 2.163052 0.334741
+v -1.549433 2.204644 0.300026
+v -1.545892 2.169667 0.293249
+v -0.265503 0.256741 -0.179040
+v -0.128605 0.263213 -0.074647
+v -0.266996 0.252931 -0.064922
+v -0.145572 0.268133 -0.193156
+v -0.273029 0.253686 -0.122348
+v -0.128976 0.264181 -0.137721
+v -0.210161 0.264081 -0.203502
+v -0.234285 0.000684 0.289802
+v -0.345794 0.000685 0.270758
+v -0.167301 0.000685 -0.230884
+v -0.273702 0.000685 -0.245200
+v -0.147492 0.000684 0.033835
+v -0.291304 0.000684 0.291559
+v -0.376200 0.000685 -0.002375
+v -0.230503 0.000685 -0.254528
+v -0.260875 0.000685 0.016763
+v -0.140559 0.000683 0.170049
+v -0.394861 0.000685 0.127952
+v -0.277034 0.000684 0.160908
+v -0.341473 0.000685 -0.146689
+v -0.111766 0.000684 -0.113835
+v -0.243010 0.000685 -0.142600
+v -0.170881 0.000684 0.233609
+v -0.387064 0.000685 0.197662
+v -0.285114 0.000684 0.232981
+v -0.312595 0.000685 -0.218283
+v -0.233294 0.000685 -0.223272
+v -0.121678 0.000684 -0.190511
+v -0.133452 0.000684 -0.034831
+v -0.352371 0.000685 -0.064287
+v -0.252796 0.000685 -0.055309
+v -0.391075 0.000685 0.061317
+v -0.268955 0.000685 0.088836
+v -0.133089 0.000684 0.103414
+v -0.236024 0.085525 0.288271
+v -0.366872 0.085526 0.268235
+v -0.158210 0.085526 -0.243380
+v -0.263710 0.080414 -0.243917
+v -0.131449 0.085526 0.035190
+v -0.302807 0.085526 0.289322
+v -0.387167 0.085527 -0.003582
+v -0.218139 0.085526 -0.261130
+v -0.135320 0.085525 0.181042
+v -0.409058 0.085527 0.135967
+v -0.342831 0.085527 -0.157921
+v -0.099833 0.085525 -0.123180
+v -0.170889 0.085525 0.249100
+v -0.398790 0.085527 0.210881
+v -0.307420 0.077122 -0.204682
+v -0.113933 0.085526 -0.206283
+v -0.117741 0.085526 -0.038335
+v -0.361040 0.085527 -0.069341
+v -0.404616 0.085527 0.064617
+v -0.126558 0.085525 0.109692
+v -0.238664 0.121950 0.282890
+v -0.345776 0.121951 0.271347
+v -0.158809 0.140201 -0.234637
+v -0.261978 0.141703 -0.233051
+v -0.151253 0.140201 0.045061
+v -0.370775 0.140202 0.015093
+v -0.212986 0.140554 -0.248087
+v -0.154814 0.140200 0.167876
+v -0.390340 0.140202 0.131699
+v -0.330126 0.140202 -0.142561
+v -0.116431 0.142227 -0.125676
+v -0.178285 0.140200 0.230694
+v -0.381814 0.140202 0.201272
+v -0.294809 0.139635 -0.192786
+v -0.130550 0.141688 -0.187006
+v -0.137707 0.140201 -0.008060
+v -0.357415 0.140202 -0.035044
+v -0.386200 0.140202 0.065195
+v -0.147016 0.140200 0.101327
+v -0.247314 0.174407 0.250243
+v -0.315698 0.174407 0.237716
+v -0.158239 0.197919 -0.224671
+v -0.247956 0.200890 -0.226562
+v -0.203553 0.182644 0.039623
+v -0.324272 0.193250 0.026732
+v -0.204122 0.200081 -0.230329
+v -0.180198 0.181212 0.144057
+v -0.352631 0.193276 0.128898
+v -0.302766 0.209668 -0.141691
+v -0.120922 0.202998 -0.122415
+v -0.200942 0.187023 0.207151
+v -0.343452 0.188832 0.188200
+v -0.279004 0.199070 -0.189688
+v -0.133359 0.198869 -0.180969
+v -0.186309 0.199341 -0.013046
+v -0.298874 0.215861 -0.011771
+v -0.344463 0.191743 0.072775
+v -0.194729 0.184572 0.092512
+v -0.342190 0.000685 -0.105824
+v -0.247903 0.000685 -0.098954
+v -0.120121 0.000684 -0.073998
+v -0.351959 0.085527 -0.113818
+v -0.105622 0.085526 -0.080274
+v -0.342893 0.140202 -0.089580
+v -0.121478 0.140201 -0.060615
+v -0.307313 0.215861 -0.085948
+v -0.133068 0.215860 -0.062786
+v -0.264947 0.242080 -0.188311
+v -0.233465 0.234212 -0.224737
+v -0.197228 0.242264 -0.221206
+v -0.169248 0.245962 -0.208306
+v -0.283799 0.229314 -0.077606
+v -0.283168 0.243471 -0.137559
+v -0.130985 0.236445 -0.179838
+v -0.124258 0.240067 -0.122671
+v -0.131967 0.229313 -0.058958
+v -0.192917 0.231434 -0.029966
+v -0.263136 0.229314 -0.044264
+v -0.192377 0.256884 -0.038600
+v -1.684602 2.165335 -0.045203
+v -1.679243 2.158687 0.143613
+v -1.727340 2.236091 0.045438
+v -1.702795 2.146616 0.067387
+v -1.695118 2.195160 0.156839
+v -1.712502 2.243271 -0.031055
+v -1.700694 2.202076 -0.068543
+v -1.706693 2.236064 0.116739
+v 1.685084 2.165334 -0.045201
+v 1.679725 2.158686 0.143615
+v 1.727823 2.236091 0.045440
+v 1.703278 2.146616 0.067389
+v 1.695601 2.195159 0.156841
+v 1.712985 2.243270 -0.031053
+v 1.701177 2.202075 -0.068541
+v 1.707175 2.236064 0.116741
+v 1.566276 2.184916 0.064144
+v 1.555779 2.241967 0.163742
+v 1.570378 2.300414 -0.045463
+v 1.560956 2.250603 -0.087203
+v 1.564984 2.291415 0.119094
+v 1.546990 2.205754 -0.061216
+v 1.542014 2.197453 0.149016
+v 1.585639 2.293020 0.039706
+v -1.565794 2.184916 0.064142
+v -1.555298 2.241968 0.163740
+v -1.569896 2.300415 -0.045465
+v -1.560474 2.250604 -0.087204
+v -1.564502 2.291416 0.119092
+v -1.546507 2.205755 -0.061217
+v -1.541532 2.197453 0.149014
+v -1.585157 2.293021 0.039704
+v 0.817599 2.223923 -0.073164
+v 0.817657 2.186424 0.036880
+v 0.839517 2.418247 -0.059336
+v 0.833481 2.399625 0.085116
+v 0.812031 2.210284 0.112704
+v 0.831581 2.316127 -0.092581
+v 0.836919 2.423518 0.015427
+v -0.817117 2.223924 -0.073165
+v -0.817175 2.186424 0.036879
+v -0.839035 2.418248 -0.059336
+v -0.832999 2.399626 0.085115
+v -0.811549 2.210284 0.112703
+v -0.831098 2.316128 -0.092581
+v -0.836436 2.423519 0.015427
+v 0.000241 1.579583 0.304214
+v 0.334021 1.590260 0.078120
+v 0.000241 1.627749 -0.181353
+v 0.277708 1.583014 0.235970
+v 0.282037 1.614811 -0.097637
+v 0.135280 1.622088 -0.146189
+v 0.135280 1.580997 0.278586
+v -0.333345 1.590268 0.078406
+v -0.276778 1.583012 0.236050
+v -0.281555 1.614811 -0.097637
+v -0.134797 1.622088 -0.146189
+v -0.134797 1.580997 0.278586
+v 0.266259 1.970420 0.211617
+v 0.266259 1.997501 -0.117050
+v 0.000241 1.967728 0.278793
+v 0.313651 1.978875 0.053829
+v 0.000241 2.001626 -0.179539
+v 0.127719 1.969018 0.246602
+v 0.127719 1.999649 -0.149594
+v -0.265777 1.970420 0.211617
+v -0.265777 1.997501 -0.117050
+v -0.313168 1.978875 0.053829
+v -0.127236 1.969018 0.246602
+v -0.127236 1.999649 -0.149594
+v 1.122344 2.200868 0.116925
+v 1.142700 2.297759 -0.071671
+v 1.154038 2.387891 0.029002
+v 1.136979 2.281405 0.127950
+v 1.127844 2.213048 -0.052699
+v 1.133873 2.176636 0.048787
+v 1.152195 2.391741 -0.039946
+v 1.146233 2.374701 0.093271
+v -1.121862 2.200869 0.116924
+v -1.142218 2.297760 -0.071672
+v -1.153556 2.387892 0.029001
+v -1.136497 2.281407 0.127949
+v -1.127362 2.213049 -0.052700
+v -1.133391 2.176636 0.048786
+v -1.151713 2.391742 -0.039947
+v -1.145751 2.374702 0.093270
+v 0.581107 2.319769 0.109865
+v 0.586750 2.337995 -0.095834
+v 0.593441 2.436572 -0.073496
+v 0.600412 2.447117 0.006770
+v 0.587561 2.422814 0.077529
+v 0.577991 2.206686 0.028552
+v 0.568364 2.226653 0.119143
+v 0.573788 2.244173 -0.083181
+v -0.580625 2.319769 0.109865
+v -0.586267 2.337995 -0.095834
+v -0.592958 2.436572 -0.073496
+v -0.599929 2.447117 0.006770
+v -0.587078 2.422814 0.077529
+v -0.577509 2.206685 0.028552
+v -0.567881 2.226653 0.119143
+v -0.573305 2.244173 -0.083181
+v 0.069151 0.811140 -0.084140
+v 0.143267 0.769931 0.115422
+v 0.361608 0.814996 0.037936
+v 0.265496 0.785043 0.109763
+v 0.146190 0.822050 -0.160339
+v 0.347095 0.821727 -0.081373
+v 0.065815 0.785709 0.027417
+v -0.070991 0.811069 -0.086508
+v -0.141651 0.769890 0.114305
+v -0.361270 0.815091 0.040619
+v -0.263946 0.785076 0.110766
+v -0.149333 0.822031 -0.161359
+v -0.348828 0.821822 -0.078922
+v -0.065734 0.785628 0.024971
+vt 0.424701 0.840048
+vt 0.423209 0.793785
+vt 0.461737 0.792426
+vt 0.464884 0.838834
+vt 0.468357 0.881332
+vt 0.416097 0.891155
+vt 0.382303 0.875623
+vt 0.388845 0.838885
+vt 0.386734 0.795098
+vt 0.579037 0.844668
+vt 0.567369 0.879717
+vt 0.544300 0.865660
+vt 0.547922 0.837220
+vt 0.549707 0.794263
+vt 0.582610 0.796170
+vt 0.598269 0.849956
+vt 0.602276 0.796592
+vt 0.621565 0.796099
+vt 0.617431 0.855287
+vt 0.601115 0.901709
+vt 0.583674 0.890608
+vt 0.580062 0.754791
+vt 0.546804 0.757119
+vt 0.544177 0.724490
+vt 0.573455 0.711359
+vt 0.598626 0.752337
+vt 0.595019 0.704367
+vt 0.617289 0.699781
+vt 0.620532 0.750242
+vt 0.349273 0.747190
+vt 0.347330 0.708825
+vt 0.370455 0.709217
+vt 0.379997 0.749138
+vt 0.352581 0.794437
+vt 0.329588 0.744940
+vt 0.331063 0.794428
+vt 0.315002 0.794084
+vt 0.314985 0.741795
+vt 0.314901 0.703498
+vt 0.329344 0.703695
+vt 0.354491 0.840733
+vt 0.357743 0.880856
+vt 0.332172 0.842510
+vt 0.333959 0.884940
+vt 0.315019 0.885796
+vt 0.315031 0.842108
+vt 0.414559 0.747483
+vt 0.399518 0.701783
+vt 0.448949 0.694770
+vt 0.456853 0.745548
+vt 0.505141 0.748829
+vt 0.508784 0.706093
+vt 0.507142 0.792801
+vt 0.508074 0.837122
+vt 0.514661 0.872259
+vt 0.419137 0.937326
+vt 0.478349 0.922822
+vt 0.424097 0.965195
+vt 0.486594 0.948330
+vt 0.495723 0.973192
+vt 0.428443 0.990876
+vt 0.345577 0.936058
+vt 0.314782 0.941388
+vt 0.375705 0.922558
+vt 0.532102 0.902649
+vt 0.545515 0.922196
+vt 0.559814 0.940878
+vt 0.436532 0.655316
+vt 0.362648 0.645806
+vt 0.382595 0.577465
+vt 0.445393 0.577416
+vt 0.535122 0.656711
+vt 0.561397 0.634699
+vt 0.607811 0.622342
+vt 0.339216 0.643866
+vt 0.314578 0.640560
+vt 0.510735 0.577421
+vt 0.559529 0.577420
+vt 0.444090 0.534948
+vt 0.509270 0.534980
+vt 0.347826 0.577463
+vt 0.314959 0.577465
+vt 0.314357 0.535019
+vt 0.343869 0.535021
+vt 0.327559 0.284656
+vt 0.332242 0.271386
+vt 0.359600 0.274896
+vt 0.357633 0.299914
+vt 0.321315 0.250312
+vt 0.314290 0.247970
+vt 0.314171 0.231740
+vt 0.334433 0.243039
+vt 0.382847 0.535032
+vt 0.558656 0.534925
+vt 0.325529 0.253434
+vt 0.351430 0.248123
+vt 0.319754 0.286217
+vt 0.333829 0.303559
+vt 0.418691 0.370972
+vt 0.389352 0.351632
+vt 0.418603 0.335552
+vt 0.431990 0.354981
+vt 0.338145 0.328760
+vt 0.366602 0.325961
+vt 0.377808 0.356778
+vt 0.343676 0.358303
+vt 0.335864 0.210609
+vt 0.314003 0.207365
+vt 0.314103 0.176477
+vt 0.345144 0.178504
+vt 0.387039 0.219621
+vt 0.390341 0.194177
+vt 0.422363 0.207716
+vt 0.418946 0.229929
+vt 0.345500 0.054288
+vt 0.315138 0.054235
+vt 0.315528 0.018181
+vt 0.347504 0.018238
+vt 0.376599 0.479159
+vt 0.415450 0.479198
+vt 0.416158 0.512649
+vt 0.378862 0.512649
+vt 0.417869 0.054390
+vt 0.379180 0.054356
+vt 0.383732 0.018359
+vt 0.421058 0.018359
+vt 0.344804 0.479148
+vt 0.345824 0.512586
+vt 0.343730 0.404567
+vt 0.376072 0.404566
+vt 0.374336 0.441555
+vt 0.343784 0.441555
+vt 0.416751 0.128948
+vt 0.377222 0.128952
+vt 0.374628 0.091879
+vt 0.414680 0.091883
+vt 0.414734 0.404572
+vt 0.414742 0.441555
+vt 0.344319 0.128948
+vt 0.314426 0.128944
+vt 0.314749 0.091873
+vt 0.343495 0.091877
+vt 0.377580 0.274898
+vt 0.379110 0.250741
+vt 0.414096 0.254865
+vt 0.413016 0.274926
+vt 0.383845 0.322909
+vt 0.415778 0.316747
+vt 0.785443 0.156150
+vt 0.764725 0.156147
+vt 0.765086 0.122612
+vt 0.785862 0.122612
+vt 0.799682 0.217712
+vt 0.787967 0.231864
+vt 0.787944 0.209717
+vt 0.806383 0.217712
+vt 0.817931 0.209717
+vt 0.817908 0.231864
+vt 0.313408 0.304910
+vt 0.313716 0.329378
+vt 0.371733 0.216071
+vt 0.314416 0.404567
+vt 0.314870 0.441555
+vt 0.315301 0.479147
+vt 0.315731 0.512570
+vt 0.379817 0.180762
+vt 0.313963 0.358401
+vt 0.313509 0.286997
+vt 0.603163 0.577407
+vt 0.606192 0.534877
+vt 0.745241 0.200706
+vt 0.748033 0.232049
+vt 0.860635 0.200706
+vt 0.857842 0.232049
+vt 0.709972 0.232115
+vt 0.709972 0.200711
+vt 0.709972 0.171386
+vt 0.709972 0.163211
+vt 0.711885 0.163092
+vt 0.722930 0.172839
+vt 0.895904 0.232115
+vt 0.895904 0.200711
+vt 0.882945 0.172839
+vt 0.893990 0.163092
+vt 0.895904 0.163211
+vt 0.895904 0.171386
+vt 0.746436 0.108499
+vt 0.728058 0.108499
+vt 0.727994 0.095821
+vt 0.746362 0.095822
+vt 0.742320 0.156136
+vt 0.722900 0.156121
+vt 0.728122 0.122612
+vt 0.746509 0.122612
+vt 0.820432 0.156150
+vt 0.806711 0.156148
+vt 0.806948 0.122612
+vt 0.820014 0.122612
+vt 0.863555 0.156136
+vt 0.841092 0.156147
+vt 0.840811 0.122612
+vt 0.859366 0.122612
+vt 0.820810 0.095822
+vt 0.806988 0.095820
+vt 0.807180 0.054984
+vt 0.822926 0.054984
+vt 0.820412 0.108499
+vt 0.806968 0.108499
+vt 0.859513 0.095822
+vt 0.859440 0.108499
+vt 0.840859 0.095821
+vt 0.785464 0.108499
+vt 0.765055 0.108499
+vt 0.765025 0.095821
+vt 0.785065 0.095822
+vt 0.765027 0.054984
+vt 0.748996 0.054984
+vt 0.749674 0.016269
+vt 0.765051 0.016269
+vt 0.840857 0.054984
+vt 0.856880 0.054984
+vt 0.782949 0.054984
+vt 0.729510 0.054983
+vt 0.799277 0.156148
+vt 0.882975 0.156121
+vt 0.798935 0.095820
+vt 0.798699 0.054984
+vt 0.877882 0.095821
+vt 0.876366 0.054983
+vt 0.730059 0.016269
+vt 0.798960 0.108499
+vt 0.877818 0.108499
+vt 0.877753 0.122612
+vt 0.798985 0.122612
+vt 0.840838 0.016269
+vt 0.856202 0.016269
+vt 0.782896 0.016268
+vt 0.798648 0.016268
+vt 0.449700 0.220684
+vt 0.449796 0.204123
+vt 0.480859 0.204123
+vt 0.480685 0.220695
+vt 0.449654 0.257610
+vt 0.449682 0.238404
+vt 0.480652 0.238492
+vt 0.480599 0.257655
+vt 0.449661 0.302478
+vt 0.449646 0.286082
+vt 0.480577 0.286036
+vt 0.480601 0.302370
+vt 0.449670 0.274956
+vt 0.480593 0.274987
+vt 0.377299 0.292342
+vt 0.412883 0.292280
+vt 0.427685 0.190243
+vt 0.435707 0.203873
+vt 0.566812 0.286023
+vt 0.566812 0.275036
+vt 0.595577 0.275057
+vt 0.595566 0.286095
+vt 0.566827 0.354952
+vt 0.566822 0.326817
+vt 0.595512 0.326825
+vt 0.595500 0.354952
+vt 0.566782 0.238670
+vt 0.566782 0.220717
+vt 0.595706 0.220705
+vt 0.595699 0.238600
+vt 0.566815 0.302227
+vt 0.595550 0.302456
+vt 0.449673 0.326828
+vt 0.480612 0.326823
+vt 0.449765 0.354952
+vt 0.480773 0.354952
+vt 0.936048 0.768188
+vt 0.936053 0.746623
+vt 0.924192 0.740812
+vt 0.923121 0.760166
+vt 0.936018 0.819789
+vt 0.936059 0.797784
+vt 0.916592 0.805110
+vt 0.913699 0.821253
+vt 0.935973 0.782601
+vt 0.915423 0.782034
+vt 0.911752 0.319669
+vt 0.933272 0.316595
+vt 0.941824 0.333084
+vt 0.910614 0.334381
+vt 0.566800 0.257742
+vt 0.595621 0.257734
+vt 0.566790 0.204124
+vt 0.595682 0.204124
+vt 0.506526 0.274998
+vt 0.506548 0.257674
+vt 0.532519 0.257694
+vt 0.532485 0.275009
+vt 0.506620 0.220701
+vt 0.506734 0.204123
+vt 0.532625 0.204124
+vt 0.532558 0.220707
+vt 0.532559 0.238577
+vt 0.506530 0.302339
+vt 0.506519 0.286032
+vt 0.532490 0.286028
+vt 0.532482 0.302308
+vt 0.506529 0.326822
+vt 0.532468 0.326821
+vt 0.506639 0.354952
+vt 0.532541 0.354952
+vt 0.420373 0.176908
+vt 0.414725 0.374942
+vt 0.885913 0.762972
+vt 0.885325 0.783977
+vt 0.889616 0.328988
+vt 0.912643 0.364253
+vt 0.892080 0.360976
+vt 0.879460 0.743643
+vt 0.891324 0.803735
+vt 0.891345 0.819504
+vt 0.896713 0.317960
+vt 0.936077 0.838896
+vt 0.917882 0.833832
+vt 0.948365 0.733420
+vt 0.934622 0.732855
+vt 0.849376 0.815349
+vt 0.850748 0.805248
+vt 0.836471 0.804603
+vt 0.835136 0.812201
+vt 0.845468 0.793376
+vt 0.831510 0.796107
+vt 0.917673 0.409579
+vt 0.942118 0.402143
+vt 0.940634 0.420541
+vt 0.917720 0.427678
+vt 0.838529 0.771488
+vt 0.832166 0.765778
+vt 0.818658 0.776896
+vt 0.825597 0.780492
+vt 0.891695 0.833437
+vt 0.868327 0.735148
+vt 0.887944 0.727402
+vt 0.871512 0.724326
+vt 0.941792 0.356512
+vt 0.824181 0.797634
+vt 0.812448 0.795354
+vt 0.828406 0.817321
+vt 0.830746 0.786410
+vt 0.844654 0.780574
+vt 0.900278 0.405603
+vt 0.901378 0.423637
+vt 0.844856 0.823697
+vt 0.876501 0.831755
+vt 0.877480 0.819001
+vt 0.863616 0.818497
+vt 0.861307 0.830073
+vt 0.872376 0.787311
+vt 0.872238 0.768855
+vt 0.858562 0.774738
+vt 0.859427 0.790645
+vt 0.895628 0.374273
+vt 0.915135 0.377867
+vt 0.917627 0.391481
+vt 0.899177 0.387570
+vt 0.865460 0.753064
+vt 0.851461 0.762485
+vt 0.857000 0.744904
+vt 0.845674 0.754660
+vt 0.942698 0.370129
+vt 0.943603 0.383745
+vt 0.878174 0.804814
+vt 0.865024 0.805893
+vt 0.914557 0.725788
+vt 0.924213 0.719241
+vt 0.914994 0.703678
+vt 0.906472 0.711107
+vt 0.881044 0.356556
+vt 0.875706 0.338668
+vt 0.863509 0.352136
+vt 0.879002 0.362548
+vt 0.863138 0.381292
+vt 0.852273 0.373989
+vt 0.885267 0.719886
+vt 0.871271 0.716399
+vt 0.894062 0.694357
+vt 0.896674 0.686606
+vt 0.881207 0.690837
+vt 0.886620 0.697803
+vt 0.822979 0.016268
+vt 0.807221 0.016268
+vt 0.875816 0.016269
+vt 0.767140 0.911152
+vt 0.774189 0.910992
+vt 0.771025 0.901580
+vt 0.764041 0.893569
+vt 0.762619 0.936895
+vt 0.770492 0.925697
+vt 0.696701 0.941705
+vt 0.711877 0.936747
+vt 0.712850 0.911002
+vt 0.696555 0.911002
+vt 0.714237 0.884771
+vt 0.699642 0.883044
+vt 0.663963 0.911002
+vt 0.680259 0.911002
+vt 0.684668 0.883866
+vt 0.669298 0.887352
+vt 0.666683 0.936525
+vt 0.681635 0.941705
+vt 0.736641 0.940160
+vt 0.745745 0.941028
+vt 0.748883 0.911001
+vt 0.739015 0.911001
+vt 0.747331 0.888913
+vt 0.738188 0.889775
+vt 0.652548 0.923774
+vt 0.650728 0.911086
+vt 0.654009 0.898398
+vt 0.729146 0.911001
+vt 0.728658 0.888542
+vt 0.727561 0.938163
+vt 0.685829 0.695635
+vt 0.692503 0.712229
+vt 0.708990 0.708576
+vt 0.708432 0.689949
+vt 0.636358 0.838542
+vt 0.651216 0.838339
+vt 0.651688 0.827846
+vt 0.635893 0.827677
+vt 0.781184 0.780586
+vt 0.761434 0.786870
+vt 0.765163 0.797322
+vt 0.785169 0.791226
+vt 0.644587 0.767637
+vt 0.662889 0.772774
+vt 0.667608 0.758644
+vt 0.648575 0.752749
+vt 0.673889 0.744932
+vt 0.655645 0.733289
+vt 0.636687 0.810221
+vt 0.652656 0.811979
+vt 0.655557 0.797710
+vt 0.638034 0.794237
+vt 0.751425 0.706855
+vt 0.736307 0.719414
+vt 0.743897 0.740484
+vt 0.762033 0.731608
+vt 0.770097 0.809706
+vt 0.787648 0.803114
+vt 0.775207 0.821912
+vt 0.791133 0.816315
+vt 0.756045 0.773861
+vt 0.741140 0.776355
+vt 0.746963 0.789506
+vt 0.749903 0.756858
+vt 0.738081 0.763188
+vt 0.728583 0.733966
+vt 0.733420 0.750248
+vt 0.683428 0.721761
+vt 0.690265 0.735383
+vt 0.699037 0.717821
+vt 0.675902 0.773849
+vt 0.678758 0.763215
+vt 0.663860 0.828975
+vt 0.666038 0.813500
+vt 0.651369 0.848259
+vt 0.662989 0.848260
+vt 0.662721 0.839648
+vt 0.726155 0.711178
+vt 0.718851 0.717725
+vt 0.763232 0.827184
+vt 0.767474 0.837667
+vt 0.779325 0.835265
+vt 0.753212 0.799839
+vt 0.758294 0.814508
+vt 0.683588 0.751217
+vt 0.658905 0.785523
+vt 0.671987 0.788046
+vt 0.669398 0.798853
+vt 0.770171 0.848260
+vt 0.779396 0.848260
+vt 0.737140 0.805935
+vt 0.745139 0.819551
+vt 0.691125 0.756638
+vt 0.696225 0.747399
+vt 0.671483 0.841478
+vt 0.672536 0.832167
+vt 0.695283 0.790443
+vt 0.692294 0.778048
+vt 0.684106 0.807013
+vt 0.755272 0.840706
+vt 0.757876 0.848260
+vt 0.689617 0.767062
+vt 0.751837 0.830942
+vt 0.726011 0.777908
+vt 0.724135 0.790230
+vt 0.727747 0.767067
+vt 0.723221 0.747063
+vt 0.728335 0.757320
+vt 0.702554 0.734897
+vt 0.676496 0.818660
+vt 0.669902 0.848260
+vt 0.715282 0.734795
+vt 0.744649 0.834372
+vt 0.747224 0.843692
+vt 0.678439 0.843499
+vt 0.679462 0.835501
+vt 0.740023 0.822211
+vt 0.676559 0.848260
+vt 0.718747 0.798862
+vt 0.731506 0.809276
+vt 0.681201 0.821956
+vt 0.749698 0.848260
+vt 0.689595 0.809913
+vt 0.701454 0.798968
+vt 0.731965 0.694501
+vt 0.685748 0.848259
+vt 0.686221 0.838135
+vt 0.741199 0.848260
+vt 0.688336 0.824075
+vt 0.697257 0.814380
+vt 0.734432 0.824734
+vt 0.739082 0.837215
+vt 0.710682 0.811176
+vt 0.725362 0.813361
+vt 0.794502 0.834892
+vt 0.769187 0.749663
+vt 0.775611 0.765710
+vt 0.794901 0.848257
+vt 0.640929 0.781632
+vt 0.666521 0.709568
+vt 0.636356 0.848259
+vt 0.205395 0.840356
+vt 0.165057 0.839231
+vt 0.168249 0.792680
+vt 0.206812 0.794023
+vt 0.214392 0.891615
+vt 0.161589 0.882055
+vt 0.241265 0.839077
+vt 0.247916 0.875817
+vt 0.243291 0.795273
+vt 0.050187 0.844482
+vt 0.081566 0.837294
+vt 0.084989 0.865972
+vt 0.061577 0.879960
+vt 0.047164 0.795723
+vt 0.080136 0.794155
+vt 0.030751 0.849572
+vt 0.011363 0.854676
+vt 0.008122 0.795077
+vt 0.027453 0.795879
+vt 0.044980 0.890795
+vt 0.027199 0.901816
+vt 0.050209 0.754404
+vt 0.083344 0.757041
+vt 0.057188 0.711303
+vt 0.086190 0.724548
+vt 0.031763 0.751718
+vt 0.009998 0.749349
+vt 0.013882 0.699460
+vt 0.035870 0.704195
+vt 0.280653 0.747292
+vt 0.249910 0.749310
+vt 0.259406 0.709407
+vt 0.282503 0.708944
+vt 0.277433 0.794536
+vt 0.300327 0.744987
+vt 0.298944 0.794473
+vt 0.300463 0.703752
+vt 0.275598 0.840835
+vt 0.272406 0.880931
+vt 0.297897 0.842557
+vt 0.296112 0.884965
+vt 0.215427 0.747718
+vt 0.173187 0.745804
+vt 0.181086 0.695152
+vt 0.230402 0.702057
+vt 0.124974 0.748995
+vt 0.121499 0.706399
+vt 0.122778 0.792952
+vt 0.121636 0.837433
+vt 0.114850 0.872809
+vt 0.211767 0.938667
+vt 0.151460 0.924131
+vt 0.206881 0.967319
+vt 0.202444 0.993810
+vt 0.133578 0.975415
+vt 0.143009 0.950086
+vt 0.284332 0.935822
+vt 0.254612 0.922405
+vt 0.097049 0.903456
+vt 0.083305 0.923173
+vt 0.068619 0.942013
+vt 0.194143 0.656045
+vt 0.184361 0.577417
+vt 0.247489 0.577466
+vt 0.266383 0.646033
+vt 0.095483 0.657314
+vt 0.069552 0.635446
+vt 0.023577 0.623156
+vt 0.289968 0.643994
+vt 0.071392 0.577421
+vt 0.119669 0.577423
+vt 0.120835 0.534998
+vt 0.185223 0.534962
+vt 0.282127 0.577464
+vt 0.284898 0.535025
+vt 0.299459 0.284656
+vt 0.269410 0.300468
+vt 0.267320 0.274905
+vt 0.294776 0.271386
+vt 0.306484 0.250312
+vt 0.293315 0.242924
+vt 0.245931 0.535039
+vt 0.071962 0.534946
+vt 0.275823 0.248153
+vt 0.301489 0.253434
+vt 0.307265 0.286217
+vt 0.293325 0.304171
+vt 0.208695 0.372787
+vt 0.194848 0.354981
+vt 0.207736 0.335642
+vt 0.238048 0.352770
+vt 0.289297 0.329143
+vt 0.284195 0.358809
+vt 0.249789 0.357798
+vt 0.260662 0.326638
+vt 0.291825 0.210419
+vt 0.282910 0.178142
+vt 0.240092 0.219225
+vt 0.207156 0.229503
+vt 0.203883 0.206876
+vt 0.237038 0.193441
+vt 0.284744 0.054246
+vt 0.283530 0.018181
+vt 0.253997 0.479174
+vt 0.252661 0.512749
+vt 0.215378 0.512749
+vt 0.215164 0.479218
+vt 0.212078 0.054277
+vt 0.209691 0.018239
+vt 0.247220 0.018239
+vt 0.250975 0.054268
+vt 0.285805 0.479156
+vt 0.285667 0.512634
+vt 0.285068 0.404567
+vt 0.285942 0.441555
+vt 0.255333 0.441555
+vt 0.252561 0.404567
+vt 0.211458 0.128944
+vt 0.214464 0.091875
+vt 0.254730 0.091874
+vt 0.251290 0.128949
+vt 0.214951 0.441555
+vt 0.213861 0.404572
+vt 0.284433 0.128947
+vt 0.285957 0.091875
+vt 0.249199 0.274905
+vt 0.212908 0.274933
+vt 0.211924 0.254886
+vt 0.247827 0.250786
+vt 0.210380 0.317703
+vt 0.243254 0.323720
+vt 0.634500 0.156150
+vt 0.634082 0.122612
+vt 0.654909 0.122612
+vt 0.655078 0.156147
+vt 0.620451 0.217712
+vt 0.631999 0.209717
+vt 0.631977 0.231864
+vt 0.985614 0.217712
+vt 0.973899 0.231864
+vt 0.973876 0.209717
+vt 0.255597 0.215743
+vt 0.247850 0.179997
+vt 0.028247 0.577410
+vt 0.025045 0.534903
+vt 0.674703 0.200706
+vt 0.671910 0.232049
+vt 0.931173 0.200706
+vt 0.933965 0.232049
+vt 0.697013 0.172839
+vt 0.708058 0.163092
+vt 0.908862 0.172839
+vt 0.897817 0.163092
+vt 0.673508 0.108499
+vt 0.673582 0.095822
+vt 0.691950 0.095821
+vt 0.691886 0.108499
+vt 0.677624 0.156136
+vt 0.673434 0.122612
+vt 0.691822 0.122612
+vt 0.697044 0.156121
+vt 0.971375 0.156150
+vt 0.971794 0.122612
+vt 0.984917 0.122612
+vt 0.985209 0.156148
+vt 0.928252 0.156136
+vt 0.932441 0.122612
+vt 0.951042 0.122612
+vt 0.950589 0.156147
+vt 0.970997 0.095822
+vt 0.968881 0.054984
+vt 0.984631 0.054984
+vt 0.984867 0.095820
+vt 0.971395 0.108499
+vt 0.984892 0.108499
+vt 0.932368 0.108499
+vt 0.932294 0.095822
+vt 0.950965 0.095821
+vt 0.634480 0.108499
+vt 0.634879 0.095822
+vt 0.654938 0.095821
+vt 0.654923 0.108499
+vt 0.654936 0.054984
+vt 0.654925 0.016269
+vt 0.670270 0.016269
+vt 0.670948 0.054984
+vt 0.934928 0.054984
+vt 0.950969 0.054984
+vt 0.636994 0.054984
+vt 0.690377 0.054983
+vt 0.620779 0.156148
+vt 0.908832 0.156121
+vt 0.621056 0.095820
+vt 0.621248 0.054984
+vt 0.913926 0.095821
+vt 0.915498 0.054983
+vt 0.689838 0.016269
+vt 0.621036 0.108499
+vt 0.913990 0.108499
+vt 0.914054 0.122612
+vt 0.621016 0.122612
+vt 0.935606 0.016269
+vt 0.950999 0.016269
+vt 0.621289 0.016268
+vt 0.637047 0.016268
+vt 0.176090 0.220682
+vt 0.145191 0.220694
+vt 0.145087 0.204123
+vt 0.175901 0.204123
+vt 0.176179 0.257611
+vt 0.145241 0.257656
+vt 0.145210 0.238484
+vt 0.176125 0.238395
+vt 0.176168 0.302520
+vt 0.145242 0.302415
+vt 0.145255 0.286054
+vt 0.176196 0.286099
+vt 0.145244 0.274996
+vt 0.176147 0.274965
+vt 0.213159 0.292296
+vt 0.249624 0.292358
+vt 0.190858 0.203868
+vt 0.204472 0.190753
+vt 0.059422 0.286044
+vt 0.031066 0.286124
+vt 0.031049 0.275075
+vt 0.059417 0.275048
+vt 0.059492 0.354952
+vt 0.031128 0.354952
+vt 0.031124 0.326827
+vt 0.059475 0.326819
+vt 0.059279 0.238666
+vt 0.030929 0.238598
+vt 0.030921 0.220705
+vt 0.059276 0.220716
+vt 0.031084 0.302521
+vt 0.059440 0.302276
+vt 0.176146 0.326829
+vt 0.145236 0.326824
+vt 0.175964 0.354952
+vt 0.145141 0.354952
+vt 0.936052 0.597770
+vt 0.923354 0.589708
+vt 0.924484 0.570357
+vt 0.936057 0.576206
+vt 0.936019 0.649366
+vt 0.913751 0.650767
+vt 0.916692 0.634633
+vt 0.936061 0.627368
+vt 0.915592 0.611553
+vt 0.935975 0.612170
+vt 0.797433 0.319246
+vt 0.796272 0.333957
+vt 0.827484 0.332708
+vt 0.818957 0.316206
+vt 0.059362 0.257746
+vt 0.031009 0.257741
+vt 0.030934 0.204124
+vt 0.059305 0.204124
+vt 0.118260 0.275008
+vt 0.093911 0.275019
+vt 0.093876 0.257696
+vt 0.118252 0.257676
+vt 0.118222 0.220700
+vt 0.093831 0.220705
+vt 0.093754 0.204124
+vt 0.118173 0.204123
+vt 0.093831 0.238570
+vt 0.118261 0.302386
+vt 0.093919 0.302358
+vt 0.093909 0.286048
+vt 0.118265 0.286051
+vt 0.118262 0.326824
+vt 0.093936 0.326823
+vt 0.118215 0.354952
+vt 0.093852 0.354952
+vt 0.208452 0.175985
+vt 0.212772 0.376778
+vt 0.885489 0.613407
+vt 0.886139 0.592404
+vt 0.775283 0.328531
+vt 0.777696 0.360523
+vt 0.798255 0.363832
+vt 0.879743 0.573056
+vt 0.891403 0.648951
+vt 0.891428 0.633182
+vt 0.782396 0.317514
+vt 0.936077 0.668483
+vt 0.917897 0.663357
+vt 0.934937 0.562431
+vt 0.948678 0.563037
+vt 0.849446 0.644672
+vt 0.835215 0.641481
+vt 0.836574 0.633887
+vt 0.850848 0.634574
+vt 0.831637 0.625377
+vt 0.845604 0.622687
+vt 0.803215 0.409166
+vt 0.803234 0.427265
+vt 0.826158 0.420164
+vt 0.827672 0.401768
+vt 0.838730 0.600779
+vt 0.825771 0.609744
+vt 0.818842 0.606128
+vt 0.832383 0.595050
+vt 0.891712 0.662885
+vt 0.868635 0.564528
+vt 0.871852 0.553715
+vt 0.888276 0.556840
+vt 0.827416 0.356136
+vt 0.824304 0.626881
+vt 0.812578 0.624567
+vt 0.828470 0.646582
+vt 0.830902 0.615677
+vt 0.844827 0.609883
+vt 0.785826 0.405163
+vt 0.786898 0.423198
+vt 0.844902 0.653006
+vt 0.876523 0.661158
+vt 0.861333 0.659431
+vt 0.863677 0.647862
+vt 0.877540 0.648407
+vt 0.872530 0.616702
+vt 0.859570 0.619998
+vt 0.858753 0.604088
+vt 0.872446 0.598246
+vt 0.781225 0.373826
+vt 0.784753 0.387128
+vt 0.803196 0.391068
+vt 0.800726 0.377450
+vt 0.851688 0.591814
+vt 0.865716 0.582435
+vt 0.845924 0.583972
+vt 0.857280 0.574250
+vt 0.829185 0.383372
+vt 0.828300 0.369754
+vt 0.878275 0.634222
+vt 0.865123 0.635262
+vt 0.914893 0.555304
+vt 0.906852 0.540600
+vt 0.915395 0.533196
+vt 0.924568 0.548786
+vt 0.761358 0.338190
+vt 0.766667 0.356086
+vt 0.749140 0.351639
+vt 0.737870 0.373475
+vt 0.748724 0.380794
+vt 0.764617 0.362075
+vt 0.885620 0.549316
+vt 0.871635 0.545787
+vt 0.894491 0.523813
+vt 0.887040 0.527237
+vt 0.881647 0.520255
+vt 0.897126 0.516070
+vt 0.968828 0.016268
+vt 0.984580 0.016268
+vt 0.916038 0.016269
+vt 0.934523 0.917621
+vt 0.931424 0.935204
+vt 0.938408 0.927193
+vt 0.941572 0.917780
+vt 0.930002 0.891877
+vt 0.937875 0.903075
+vt 0.864084 0.887068
+vt 0.863938 0.917771
+vt 0.880234 0.917771
+vt 0.879260 0.892026
+vt 0.867026 0.945729
+vt 0.881621 0.944002
+vt 0.831347 0.917772
+vt 0.836681 0.941421
+vt 0.852052 0.944907
+vt 0.847642 0.917771
+vt 0.834066 0.892248
+vt 0.849018 0.887068
+vt 0.904024 0.888613
+vt 0.906398 0.917771
+vt 0.916266 0.917771
+vt 0.913129 0.887745
+vt 0.905572 0.938997
+vt 0.914714 0.939860
+vt 0.819931 0.904999
+vt 0.818111 0.917687
+vt 0.821392 0.930376
+vt 0.896042 0.940231
+vt 0.896530 0.917771
+vt 0.894944 0.890609
+vt 0.686042 0.524352
+vt 0.708647 0.518689
+vt 0.709177 0.537312
+vt 0.692687 0.540948
+vt 0.636372 0.667162
+vt 0.635921 0.656300
+vt 0.651714 0.656493
+vt 0.651227 0.666984
+vt 0.781285 0.609428
+vt 0.785249 0.620097
+vt 0.765233 0.626167
+vt 0.761520 0.615688
+vt 0.644711 0.596297
+vt 0.648718 0.581418
+vt 0.667739 0.587337
+vt 0.663002 0.601458
+vt 0.655822 0.561957
+vt 0.674036 0.573634
+vt 0.636733 0.638857
+vt 0.638119 0.622878
+vt 0.655630 0.626375
+vt 0.652694 0.640638
+vt 0.751631 0.535644
+vt 0.762210 0.560416
+vt 0.744045 0.569271
+vt 0.736483 0.548184
+vt 0.787716 0.631988
+vt 0.770153 0.638555
+vt 0.791176 0.645197
+vt 0.775239 0.650769
+vt 0.756154 0.602668
+vt 0.747050 0.618300
+vt 0.741245 0.605142
+vt 0.750033 0.585655
+vt 0.738203 0.591970
+vt 0.733559 0.579024
+vt 0.728733 0.562733
+vt 0.683603 0.550467
+vt 0.699215 0.546547
+vt 0.690416 0.564106
+vt 0.678881 0.591921
+vt 0.676012 0.602550
+vt 0.666074 0.642176
+vt 0.663882 0.657641
+vt 0.651365 0.677015
+vt 0.662728 0.668313
+vt 0.662980 0.677015
+vt 0.726341 0.539931
+vt 0.719028 0.546474
+vt 0.779342 0.664126
+vt 0.767486 0.666511
+vt 0.763261 0.656022
+vt 0.758344 0.643339
+vt 0.753283 0.628664
+vt 0.683726 0.579931
+vt 0.658998 0.614197
+vt 0.672082 0.616741
+vt 0.669471 0.627536
+vt 0.779389 0.677016
+vt 0.770165 0.677015
+vt 0.745182 0.648362
+vt 0.737201 0.634733
+vt 0.696399 0.576131
+vt 0.691285 0.585364
+vt 0.672552 0.660852
+vt 0.671485 0.670160
+vt 0.692397 0.606771
+vt 0.695369 0.619169
+vt 0.684166 0.635721
+vt 0.757870 0.677015
+vt 0.755280 0.669527
+vt 0.689760 0.595785
+vt 0.751861 0.659762
+vt 0.724212 0.618997
+vt 0.726110 0.606671
+vt 0.727889 0.595831
+vt 0.728493 0.586086
+vt 0.723396 0.575823
+vt 0.702738 0.563637
+vt 0.676524 0.647357
+vt 0.669891 0.677015
+vt 0.715467 0.563548
+vt 0.747228 0.672502
+vt 0.744669 0.663180
+vt 0.679473 0.664199
+vt 0.678437 0.672191
+vt 0.740064 0.651011
+vt 0.676547 0.677015
+vt 0.731566 0.638069
+vt 0.718813 0.627622
+vt 0.681227 0.650664
+vt 0.749692 0.677015
+vt 0.689654 0.638630
+vt 0.701529 0.627703
+vt 0.732176 0.523263
+vt 0.685735 0.677015
+vt 0.686228 0.666838
+vt 0.741198 0.677015
+vt 0.688358 0.652787
+vt 0.697308 0.643104
+vt 0.734468 0.653528
+vt 0.739084 0.666015
+vt 0.710741 0.639927
+vt 0.725417 0.642145
+vt 0.794526 0.663780
+vt 0.769330 0.578484
+vt 0.775733 0.594543
+vt 0.794904 0.677014
+vt 0.641034 0.610282
+vt 0.666728 0.538248
+vt 0.636356 0.677015
+vn 0.9457 0.1443 0.2913
+vn 0.9564 -0.0041 0.2922
+vn 0.9998 -0.0209 -0.0009
+vn 0.9824 0.1864 0.0134
+vn 0.7379 0.6737 0.0405
+vn 0.7078 0.6423 0.2941
+vn 0.6460 0.4611 0.6084
+vn 0.7695 0.1073 0.6296
+vn 0.7886 0.0331 0.6140
+vn 0.3103 0.2935 -0.9042
+vn 0.3025 0.7212 -0.6232
+vn 0.6054 0.6169 -0.5030
+vn 0.7379 0.2250 -0.6362
+vn 0.7562 -0.0103 -0.6543
+vn 0.3308 0.0001 -0.9437
+vn 0.1084 0.3109 -0.9442
+vn 0.0989 0.0136 -0.9950
+vn -0.0000 0.0197 -0.9998
+vn -0.0000 0.3126 -0.9499
+vn -0.0000 0.7558 -0.6548
+vn 0.1472 0.7442 -0.6515
+vn 0.3550 -0.2096 -0.9110
+vn 0.7477 -0.1850 -0.6378
+vn 0.6791 -0.4538 -0.5770
+vn 0.3752 -0.5647 -0.7350
+vn 0.1368 -0.2014 -0.9699
+vn 0.1695 -0.6011 -0.7810
+vn 0.0000 -0.6130 -0.7901
+vn -0.0000 -0.2004 -0.9797
+vn 0.4474 -0.0538 0.8927
+vn 0.4742 -0.5231 0.7082
+vn 0.7731 -0.4655 0.4308
+vn 0.8083 -0.0705 0.5845
+vn 0.4476 0.0625 0.8920
+vn 0.1322 -0.0587 0.9895
+vn 0.1444 0.0607 0.9877
+vn -0.0000 0.0525 0.9986
+vn 0.0000 -0.0698 0.9976
+vn 0.0000 -0.6245 0.7810
+vn 0.2144 -0.6358 0.7415
+vn 0.4047 0.1590 0.9005
+vn 0.3492 0.5807 0.7354
+vn 0.1784 0.2024 0.9629
+vn 0.2000 0.6209 0.7580
+vn 0.0000 0.6376 0.7704
+vn -0.0000 0.1969 0.9804
+vn 0.9553 -0.1362 0.2625
+vn 0.8333 -0.5293 0.1596
+vn 0.8217 -0.5659 -0.0678
+vn 0.9850 -0.1721 -0.0131
+vn 0.9458 -0.1792 -0.2708
+vn 0.7735 -0.5442 -0.3250
+vn 0.9657 -0.0170 -0.2589
+vn 0.9520 0.1879 -0.2416
+vn 0.7174 0.6660 -0.2046
+vn 0.2950 0.9058 0.3042
+vn 0.3086 0.9496 0.0553
+vn 0.1702 0.9347 0.3120
+vn 0.1370 0.9891 0.0545
+vn 0.0000 0.9989 0.0475
+vn 0.0000 0.9489 0.3155
+vn 0.2964 0.9341 -0.1988
+vn 0.1395 0.9681 -0.2083
+vn 0.0000 0.9774 -0.2113
+vn 0.5914 -0.8002 -0.0998
+vn 0.4555 -0.8719 0.1795
+vn 0.6394 -0.6842 0.3507
+vn 0.8795 -0.4694 -0.0788
+vn 0.4438 -0.7827 -0.4363
+vn 0.1549 -0.8154 -0.5578
+vn 0.0000 -0.8224 -0.5689
+vn 0.2065 -0.9492 0.2376
+vn -0.0000 -0.9727 0.2319
+vn 0.6646 -0.5276 -0.5291
+vn 0.2417 -0.5411 -0.8054
+vn 0.7131 0.6934 0.1032
+vn 0.5830 0.4427 -0.6813
+vn 0.3650 -0.6772 0.6388
+vn -0.0000 -0.7727 0.6348
+vn 0.0000 0.2392 0.9710
+vn 0.3422 0.2291 0.9113
+vn 0.2187 0.9685 0.1193
+vn 0.2776 0.7794 -0.5617
+vn 0.0000 0.4232 0.9060
+vn 0.2215 0.4915 0.8423
+vn 0.5299 0.4783 0.7003
+vn 0.3187 0.1528 -0.9355
+vn 0.2344 0.7167 0.6568
+vn 0.2099 0.4105 -0.8874
+vn 0.3673 -0.9301 0.0098
+vn 0.3974 -0.5924 -0.7008
+vn 0.1794 -0.6195 -0.7642
+vn 0.0690 -0.9969 -0.0385
+vn 0.1877 0.1073 -0.9763
+vn 0.2476 0.0854 -0.9651
+vn 0.4933 -0.2459 -0.8344
+vn 0.2022 -0.1020 -0.9740
+vn 0.2329 0.2954 0.9266
+vn 0.0000 0.3022 0.9532
+vn -0.0000 0.1792 0.9838
+vn 0.2403 0.1796 0.9539
+vn 0.2128 0.2478 0.9452
+vn 0.4914 -0.2255 0.8412
+vn 0.1337 -0.5254 0.8403
+vn 0.1148 0.2277 0.9669
+vn 0.2362 0.0566 0.9700
+vn 0.0000 0.0526 0.9986
+vn -0.0009 -0.0926 0.9957
+vn 0.2385 -0.0982 0.9662
+vn 0.7220 0.1360 -0.6784
+vn 0.9918 0.1212 0.0408
+vn 0.9923 0.0130 0.1231
+vn 0.7610 0.0535 -0.6465
+vn 0.6859 0.0936 0.7216
+vn 0.6979 -0.1956 0.6890
+vn 0.2849 0.1291 -0.9498
+vn 0.2636 0.0932 -0.9601
+vn 0.2253 -0.1212 -0.9667
+vn 0.6874 -0.1083 -0.7181
+vn 0.7076 0.0146 -0.7065
+vn 0.2536 0.0037 -0.9673
+vn 0.9995 -0.0294 0.0078
+vn 0.6908 0.0535 0.7211
+vn 0.6725 0.0801 0.7358
+vn 0.9981 0.0555 0.0252
+vn 0.2430 0.0914 0.9657
+vn -0.0000 0.0953 0.9955
+vn 0.0000 0.0740 0.9973
+vn 0.2426 0.0741 0.9673
+vn 0.2022 0.9739 0.1031
+vn 0.2013 0.6974 0.6878
+vn 0.1541 0.6819 0.7150
+vn 0.1655 0.9817 0.0947
+vn 0.3004 0.0419 -0.9529
+vn 0.1688 0.0258 -0.9853
+vn 0.4500 -0.1523 0.8799
+vn -0.4454 -0.1944 0.8740
+vn -0.3460 -0.2779 0.8962
+vn 0.3766 -0.1964 0.9053
+vn 0.5997 -0.3336 0.7274
+vn 0.8694 -0.0087 -0.4940
+vn 0.0000 0.3057 -0.9521
+vn 0.0000 0.1113 -0.9938
+vn 0.2453 0.2787 0.9285
+vn 0.0000 -0.1176 -0.9931
+vn 0.0000 0.0149 -0.9999
+vn -0.0000 0.1493 -0.9888
+vn 0.0000 0.0659 -0.9978
+vn 0.6091 0.0343 0.7924
+vn 0.0000 -0.0920 -0.9958
+vn 0.0000 0.1404 -0.9901
+vn 0.0000 -0.4846 -0.8747
+vn 0.1067 -0.4160 0.9031
+vn 0.3116 -0.0248 -0.9499
+vn -0.0013 -0.6103 0.7922
+vn 0.0003 -0.9575 0.2883
+vn -0.0006 -0.9977 -0.0685
+vn -0.5755 -0.7952 -0.1911
+vn -0.5898 -0.6462 0.4843
+vn -0.0011 -0.1368 -0.9906
+vn -0.1764 -0.3704 -0.9120
+vn -0.0020 -0.7436 -0.6687
+vn -0.9340 -0.1822 0.3072
+vn -0.9184 0.0606 -0.3909
+vn -0.9107 0.0462 -0.4104
+vn -0.9365 -0.1814 0.3002
+vn -0.9426 -0.1215 0.3112
+vn -0.9450 -0.1377 -0.2966
+vn -0.9243 -0.0652 -0.3762
+vn -0.9228 -0.2105 0.3226
+vn 0.8756 0.0396 -0.4815
+vn 0.9476 -0.0151 0.3190
+vn 0.9181 -0.0664 0.3906
+vn 0.9077 0.0723 -0.4133
+vn -0.4433 -0.1404 -0.8853
+vn 0.3698 -0.0259 -0.9287
+vn 0.3708 0.1432 -0.9176
+vn -0.4292 0.0769 -0.8999
+vn 0.8919 0.1157 -0.4372
+vn 0.9256 -0.1284 0.3562
+vn 0.9305 -0.2256 0.2887
+vn 0.8784 -0.1012 -0.4671
+vn 0.8901 0.1775 -0.4199
+vn 0.9257 -0.0826 0.3690
+vn -0.3939 0.2181 -0.8929
+vn -0.4115 0.2799 -0.8674
+vn 0.3324 0.2377 -0.9127
+vn 0.3702 -0.2797 0.8858
+vn -0.3684 -0.3290 0.8695
+vn -0.3734 -0.3396 0.8633
+vn 0.3699 -0.3096 0.8760
+vn -0.3218 -0.2828 0.9036
+vn -0.9240 -0.1780 0.3384
+vn -0.9034 -0.0051 0.4289
+vn -0.1555 0.0783 0.9847
+vn 0.2807 -0.0015 -0.9598
+vn -0.4512 0.0172 -0.8923
+vn 0.4510 -0.2961 0.8420
+vn -0.9203 -0.0430 -0.3889
+vn -0.9785 0.0388 -0.2025
+vn 0.1337 0.2725 -0.9528
+vn -0.6002 0.0760 -0.7962
+vn 0.6684 0.1792 0.7219
+vn 0.9807 0.1591 0.1132
+vn 0.0231 -0.5921 0.8055
+vn -0.0441 -0.9976 -0.0530
+vn -0.0785 -0.9958 -0.0464
+vn -0.0514 -0.6426 0.7645
+vn 0.1031 0.6834 0.7227
+vn 0.0614 0.1922 0.9794
+vn -0.0142 0.1514 0.9884
+vn 0.0418 0.7022 0.7108
+vn 0.0286 0.0423 -0.9987
+vn 0.1078 0.7277 -0.6773
+vn 0.0901 0.7629 -0.6402
+vn 0.0343 0.0455 -0.9984
+vn 0.1349 0.9851 0.1063
+vn 0.0795 0.9895 0.1207
+vn 0.2886 0.7054 -0.6474
+vn 0.2213 0.7031 -0.6758
+vn 0.1543 0.8126 -0.5621
+vn 0.1374 0.9816 0.1329
+vn 0.3013 0.9452 0.1258
+vn 0.1981 0.8835 -0.4245
+vn 0.0229 -0.9997 -0.0021
+vn 0.0623 -0.6655 -0.7438
+vn 0.0341 -0.7440 -0.6674
+vn 0.1430 -0.9897 0.0080
+vn 0.0423 0.1045 0.9936
+vn 0.0253 -0.6320 0.7746
+vn 0.0240 -0.7308 0.6822
+vn -0.3127 0.2099 0.9264
+vn 0.0965 0.0398 -0.9945
+vn -0.1350 0.1050 -0.9853
+vn -0.0256 -0.6368 -0.7706
+vn -0.0322 -0.6542 -0.7556
+vn 0.1349 0.8453 0.5169
+vn -0.4932 0.4930 0.7168
+vn -0.0139 0.8416 0.5400
+vn 0.0750 0.8493 -0.5225
+vn -0.1172 0.0807 -0.9898
+vn 0.2518 0.9644 0.0807
+vn -0.1514 -0.7066 -0.6913
+vn 0.0599 -0.9980 0.0190
+vn 0.1047 0.7466 0.6570
+vn 0.0280 0.9910 0.1306
+vn -0.0336 0.7148 0.6986
+vn 0.0289 0.7181 0.6953
+vn 0.0847 0.9874 0.1334
+vn -0.1332 -0.6247 0.7694
+vn -0.1064 -0.9942 -0.0166
+vn -0.0407 -0.9991 0.0079
+vn -0.0547 -0.6278 0.7764
+vn -0.0227 0.1091 0.9938
+vn 0.0379 0.0500 -0.9980
+vn 0.0584 0.7850 -0.6168
+vn 0.0999 0.7937 -0.6001
+vn 0.0656 0.0439 -0.9969
+vn -0.0380 -0.6635 -0.7472
+vn 0.0085 -0.6713 -0.7411
+vn 0.8732 -0.4872 0.0139
+vn 0.1845 0.8730 0.4514
+vn 0.2209 0.9735 0.0600
+vn -0.5726 -0.6425 0.5092
+vn -0.1516 -0.9884 -0.0104
+vn 0.1681 -0.8946 0.4139
+vn 0.3284 0.3520 0.8765
+vn 0.1938 0.8999 -0.3906
+vn 0.0779 0.1056 -0.9914
+vn 0.2088 0.0236 -0.9777
+vn 0.4326 0.8074 -0.4012
+vn 0.8096 0.4726 -0.3482
+vn 0.6046 -0.1712 -0.7779
+vn 0.4070 0.9114 0.0607
+vn 0.9199 0.3892 0.0477
+vn -0.3275 -0.9444 -0.0292
+vn -0.1998 -0.8212 -0.5345
+vn 0.2486 -0.8576 -0.4502
+vn 0.4146 -0.9085 0.0525
+vn 0.0541 0.2120 0.9758
+vn -0.2886 -0.7432 0.6036
+vn 0.1971 -0.7858 0.5863
+vn 0.5629 -0.0268 0.8261
+vn -0.0910 -0.8166 -0.5699
+vn 0.5147 0.8181 0.2567
+vn 0.2374 -0.8666 -0.4388
+vn 0.9324 -0.3612 0.0109
+vn 0.7483 0.4975 0.4388
+vn 0.3372 0.8276 0.4488
+vn -0.1555 -0.8122 -0.5622
+vn 0.0736 0.0760 -0.9944
+vn 0.1485 0.0722 -0.9863
+vn -0.1638 -0.8029 -0.5731
+vn 0.3115 0.9481 0.0636
+vn 0.3176 0.8353 0.4488
+vn 0.3268 0.8416 0.4299
+vn 0.3667 0.9284 0.0598
+vn -0.0652 -0.7833 0.6183
+vn -0.1876 -0.9821 -0.0192
+vn -0.2699 -0.9624 -0.0318
+vn -0.1672 -0.7777 0.6060
+vn 0.2008 0.1620 0.9661
+vn 0.1350 0.2102 0.9683
+vn 0.2863 0.8648 -0.4125
+vn 0.3527 0.8371 -0.4183
+vn -0.5104 0.6254 0.5902
+vn -0.7359 -0.6521 0.1822
+vn -0.5788 -0.7442 0.3334
+vn -0.4153 0.5623 0.7151
+vn 0.3722 -0.5937 -0.7135
+vn 0.7782 -0.6218 -0.0880
+vn 0.0267 -0.7229 0.6905
+vn 0.5714 0.7000 -0.4283
+vn 0.1233 0.3691 0.9212
+vn 0.8710 0.4712 0.1392
+vn 0.8376 0.2166 -0.5015
+vn -0.0000 -1.0000 0.0000
+vn 0.0084 -0.6750 -0.7378
+vn 0.3680 -0.6369 -0.6774
+vn 0.6015 -0.6121 -0.5133
+vn -0.6355 -0.6986 -0.3287
+vn -0.3370 -0.7295 -0.5952
+vn -0.7034 -0.7107 -0.0097
+vn -0.5972 -0.8019 0.0184
+vn 0.6442 -0.7370 -0.2048
+vn 0.6648 -0.7399 -0.1029
+vn 0.6664 -0.7454 0.0181
+vn 0.6517 -0.7303 0.2050
+vn -0.5592 -0.6963 0.4499
+vn -0.6826 -0.7042 0.1955
+vn -0.6484 -0.7443 0.1597
+vn -0.6932 -0.7206 0.0148
+vn 0.7022 -0.6799 -0.2114
+vn 0.6342 -0.7655 -0.1091
+vn -0.2498 -0.6440 0.7231
+vn 0.1061 -0.6663 0.7381
+vn 0.4440 -0.6813 0.5820
+vn 0.6185 -0.7625 -0.1899
+vn -0.6115 -0.7763 0.1532
+vn 0.6837 0.0752 0.7259
+vn 0.1525 0.1246 0.9804
+vn 0.4903 0.1374 -0.8606
+vn 0.7599 0.1599 -0.6301
+vn -0.9665 0.0230 0.2556
+vn -0.9782 0.0452 0.2028
+vn 0.9493 0.0983 -0.2986
+vn 0.9839 0.0914 -0.1536
+vn 0.9960 0.0812 0.0373
+vn 0.9159 0.1392 -0.3765
+vn 0.9780 0.0775 -0.1938
+vn -0.7453 0.1106 0.6575
+vn -0.9495 0.1270 0.2870
+vn -0.9970 0.0745 -0.0194
+vn -0.8740 0.0598 -0.4823
+vn -0.9951 0.0798 0.0585
+vn -0.8303 0.5511 0.0824
+vn -0.8523 0.3910 0.3476
+vn -0.9916 0.1283 0.0146
+vn -0.8484 0.5290 -0.0195
+vn -0.7014 0.4470 0.5552
+vn -0.8576 0.4754 0.1962
+vn 0.9409 0.0844 0.3281
+vn 0.8080 0.4997 0.3121
+vn 0.4611 0.4221 0.7805
+vn 0.8317 0.4977 -0.2460
+vn 0.8603 0.4813 -0.1678
+vn 0.7603 0.2592 -0.5956
+vn 0.8765 0.3184 -0.3611
+vn 0.0027 0.0640 -0.9979
+vn 0.0179 0.2134 -0.9768
+vn 0.5328 0.2307 -0.8142
+vn -0.3109 0.0989 0.9453
+vn -0.2355 0.3923 0.8892
+vn -0.9029 0.1928 -0.3842
+vn -0.5381 0.2055 -0.8174
+vn -0.5082 0.0300 -0.8607
+vn -0.9301 0.2315 0.2851
+vn -0.9798 0.1938 -0.0499
+vn 0.8834 0.4680 0.0259
+vn 0.9585 0.0708 -0.2762
+vn 0.8740 0.4463 -0.1921
+vn 0.9188 0.3598 -0.1622
+vn -0.8756 0.2043 0.4377
+vn -0.9977 0.0637 -0.0225
+vn 0.4477 0.8941 0.0123
+vn 0.4095 0.8844 0.2238
+vn 0.4740 0.2525 -0.8436
+vn 0.7825 0.3019 -0.5445
+vn 0.3908 0.8872 0.2453
+vn 0.4131 0.9101 -0.0329
+vn 0.7671 0.6409 -0.0280
+vn -0.5579 0.2025 -0.8048
+vn -0.0554 0.2166 -0.9747
+vn 0.4242 0.8999 -0.1010
+vn -0.9151 0.1009 -0.3904
+vn -0.3681 0.9119 0.1818
+vn -0.4525 0.6615 0.5981
+vn -0.3940 0.9187 -0.0283
+vn -0.4085 0.8532 0.3243
+vn -0.5208 0.8521 0.0525
+vn 0.2601 0.7859 0.5609
+vn 0.8501 0.4447 -0.2822
+vn -0.1194 0.7620 0.6365
+vn -0.8841 0.1773 -0.4324
+vn -0.4165 0.3095 -0.8548
+vn 0.3278 0.3994 -0.8562
+vn 0.6951 0.4915 -0.5247
+vn -0.9970 0.0755 -0.0137
+vn -0.1212 0.4521 -0.8837
+vn -0.1949 0.4563 0.8682
+vn -0.7707 0.2211 0.5976
+vn 0.8312 0.5333 -0.1575
+vn 0.6322 0.7536 0.1800
+vn 0.2893 0.7521 0.5922
+vn -0.9457 0.1443 0.2913
+vn -0.9824 0.1864 0.0134
+vn -0.9998 -0.0209 -0.0009
+vn -0.9564 -0.0041 0.2922
+vn -0.7078 0.6423 0.2941
+vn -0.7379 0.6737 0.0405
+vn -0.7695 0.1073 0.6296
+vn -0.6460 0.4611 0.6084
+vn -0.7886 0.0331 0.6140
+vn -0.3103 0.2935 -0.9042
+vn -0.7379 0.2250 -0.6362
+vn -0.6054 0.6169 -0.5030
+vn -0.3025 0.7212 -0.6232
+vn -0.3308 0.0001 -0.9437
+vn -0.7562 -0.0103 -0.6543
+vn -0.1084 0.3109 -0.9442
+vn -0.0989 0.0136 -0.9950
+vn -0.1472 0.7442 -0.6515
+vn -0.3550 -0.2096 -0.9110
+vn -0.7477 -0.1850 -0.6378
+vn -0.3752 -0.5647 -0.7350
+vn -0.6791 -0.4538 -0.5770
+vn -0.1368 -0.2014 -0.9699
+vn -0.1695 -0.6011 -0.7810
+vn -0.4474 -0.0538 0.8927
+vn -0.8083 -0.0705 0.5845
+vn -0.7731 -0.4655 0.4308
+vn -0.4742 -0.5231 0.7082
+vn -0.4476 0.0625 0.8920
+vn -0.1322 -0.0587 0.9895
+vn -0.1444 0.0607 0.9877
+vn -0.2144 -0.6358 0.7415
+vn -0.4047 0.1590 0.9005
+vn -0.3492 0.5807 0.7354
+vn -0.1784 0.2024 0.9629
+vn -0.2000 0.6209 0.7580
+vn -0.9553 -0.1362 0.2625
+vn -0.9850 -0.1721 -0.0131
+vn -0.8217 -0.5659 -0.0678
+vn -0.8333 -0.5293 0.1596
+vn -0.9458 -0.1792 -0.2708
+vn -0.7735 -0.5442 -0.3250
+vn -0.9657 -0.0170 -0.2589
+vn -0.9520 0.1879 -0.2416
+vn -0.7174 0.6660 -0.2046
+vn -0.2950 0.9058 0.3042
+vn -0.3086 0.9496 0.0553
+vn -0.1702 0.9347 0.3120
+vn -0.1370 0.9891 0.0545
+vn -0.2964 0.9341 -0.1988
+vn -0.1395 0.9681 -0.2083
+vn -0.5914 -0.8002 -0.0998
+vn -0.8795 -0.4694 -0.0788
+vn -0.6394 -0.6842 0.3507
+vn -0.4555 -0.8719 0.1795
+vn -0.4438 -0.7827 -0.4363
+vn -0.1549 -0.8154 -0.5578
+vn -0.2065 -0.9492 0.2376
+vn -0.2417 -0.5411 -0.8054
+vn -0.6646 -0.5276 -0.5291
+vn -0.5830 0.4427 -0.6813
+vn -0.7131 0.6934 0.1032
+vn -0.3650 -0.6772 0.6388
+vn -0.3422 0.2291 0.9113
+vn -0.2776 0.7794 -0.5617
+vn -0.2187 0.9685 0.1193
+vn -0.2215 0.4915 0.8423
+vn -0.5299 0.4783 0.7003
+vn -0.3187 0.1528 -0.9355
+vn -0.2344 0.7167 0.6568
+vn -0.2099 0.4105 -0.8874
+vn -0.3673 -0.9301 0.0098
+vn -0.0690 -0.9969 -0.0385
+vn -0.1794 -0.6195 -0.7642
+vn -0.3974 -0.5924 -0.7008
+vn -0.1877 0.1073 -0.9763
+vn -0.2022 -0.1020 -0.9740
+vn -0.4933 -0.2459 -0.8344
+vn -0.2476 0.0854 -0.9651
+vn -0.2329 0.2954 0.9266
+vn -0.2403 0.1796 0.9539
+vn -0.2128 0.2478 0.9452
+vn -0.1148 0.2277 0.9669
+vn -0.1337 -0.5254 0.8403
+vn -0.4914 -0.2255 0.8412
+vn -0.2364 0.0565 0.9700
+vn -0.2399 -0.1022 0.9654
+vn -0.7225 0.1357 -0.6780
+vn -0.7618 0.0546 -0.6455
+vn -0.9917 0.0127 0.1276
+vn -0.9918 0.1202 0.0423
+vn -0.6966 -0.1992 0.6893
+vn -0.6855 0.0928 0.7222
+vn -0.2849 0.1291 -0.9498
+vn -0.2631 0.0936 -0.9602
+vn -0.2253 -0.1212 -0.9667
+vn -0.2536 0.0037 -0.9673
+vn -0.7077 0.0144 -0.7064
+vn -0.6874 -0.1083 -0.7181
+vn -0.9995 -0.0294 0.0078
+vn -0.9982 0.0549 0.0255
+vn -0.6726 0.0797 0.7357
+vn -0.6908 0.0535 0.7211
+vn -0.2430 0.0914 0.9657
+vn -0.2426 0.0740 0.9673
+vn -0.2022 0.9739 0.1031
+vn -0.1655 0.9817 0.0947
+vn -0.1541 0.6819 0.7150
+vn -0.2013 0.6974 0.6878
+vn -0.1688 0.0258 -0.9853
+vn -0.3004 0.0419 -0.9529
+vn -0.4369 -0.1528 0.8864
+vn -0.3610 -0.1963 0.9117
+vn 0.3613 -0.2783 0.8900
+vn 0.4588 -0.1943 0.8670
+vn -0.5930 -0.3361 0.7317
+vn -0.8740 -0.0068 -0.4859
+vn -0.2453 0.2787 0.9285
+vn -0.6091 0.0343 0.7924
+vn -0.1059 -0.4199 0.9014
+vn -0.3165 -0.0232 -0.9483
+vn 0.5913 -0.6474 0.4808
+vn 0.5748 -0.7942 -0.1971
+vn 0.1734 -0.3703 -0.9126
+vn 0.9391 -0.1828 0.2909
+vn 0.9414 -0.1820 0.2838
+vn 0.9035 0.0456 -0.4262
+vn 0.9115 0.0601 -0.4068
+vn 0.9472 -0.1220 0.2966
+vn 0.9282 -0.2111 0.3065
+vn 0.9176 -0.0657 -0.3922
+vn 0.9397 -0.1373 -0.3132
+vn -0.8826 0.0408 -0.4683
+vn -0.9147 0.0729 -0.3974
+vn -0.9113 -0.0659 0.4065
+vn -0.9426 -0.0146 0.3336
+vn 0.4306 -0.1368 -0.8921
+vn 0.4136 0.0768 -0.9072
+vn -0.3866 0.1436 -0.9110
+vn -0.3825 -0.0232 -0.9236
+vn -0.8993 0.1163 -0.4216
+vn -0.8859 -0.1006 -0.4528
+vn -0.9258 -0.2249 0.3039
+vn -0.9193 -0.1278 0.3722
+vn -0.8971 0.1781 -0.4043
+vn -0.9193 -0.0821 0.3850
+vn 0.3966 0.2797 -0.8743
+vn 0.3785 0.2178 -0.8996
+vn -0.3480 0.2379 -0.9068
+vn -0.3550 -0.2796 0.8921
+vn -0.3548 -0.3094 0.8823
+vn 0.3881 -0.3399 0.8567
+vn 0.3832 -0.3294 0.8629
+vn 0.3361 -0.2834 0.8982
+vn 0.1673 0.0823 0.9825
+vn 0.9087 -0.0107 0.4173
+vn 0.9291 -0.1794 0.3233
+vn 0.4369 0.0163 -0.8994
+vn -0.2959 -0.0015 -0.9552
+vn -0.4374 -0.2958 0.8492
+vn 0.9138 -0.0443 -0.4037
+vn 0.9765 0.0369 -0.2121
+vn 0.5910 0.0741 -0.8033
+vn -0.1439 0.2747 -0.9507
+vn -0.9780 0.1679 0.1240
+vn -0.6588 0.1851 0.7292
+vn -0.0231 -0.5921 0.8055
+vn 0.0514 -0.6426 0.7645
+vn 0.0785 -0.9958 -0.0464
+vn 0.0441 -0.9976 -0.0530
+vn -0.1031 0.6834 0.7227
+vn -0.0417 0.7022 0.7107
+vn 0.0142 0.1514 0.9884
+vn -0.0614 0.1922 0.9794
+vn -0.0286 0.0423 -0.9987
+vn -0.0343 0.0455 -0.9984
+vn -0.0901 0.7629 -0.6402
+vn -0.1078 0.7277 -0.6773
+vn -0.0795 0.9895 0.1207
+vn -0.1349 0.9851 0.1063
+vn -0.2213 0.7031 -0.6758
+vn -0.2886 0.7054 -0.6474
+vn -0.1543 0.8126 -0.5621
+vn -0.1981 0.8835 -0.4245
+vn -0.3013 0.9452 0.1258
+vn -0.1374 0.9816 0.1329
+vn -0.0229 -0.9997 -0.0021
+vn -0.1430 -0.9897 0.0080
+vn -0.0341 -0.7440 -0.6674
+vn -0.0623 -0.6655 -0.7438
+vn -0.0423 0.1045 0.9936
+vn 0.3127 0.2099 0.9264
+vn -0.0240 -0.7308 0.6822
+vn -0.0253 -0.6320 0.7746
+vn 0.1350 0.1050 -0.9853
+vn -0.0965 0.0398 -0.9945
+vn 0.0256 -0.6368 -0.7706
+vn 0.0322 -0.6542 -0.7556
+vn -0.1349 0.8453 0.5169
+vn 0.0139 0.8416 0.5400
+vn 0.4932 0.4930 0.7168
+vn 0.1172 0.0807 -0.9898
+vn -0.0750 0.8493 -0.5225
+vn -0.2518 0.9644 0.0807
+vn -0.0599 -0.9980 0.0190
+vn 0.1514 -0.7066 -0.6913
+vn -0.1047 0.7466 0.6570
+vn -0.0280 0.9910 0.1306
+vn -0.0847 0.9874 0.1334
+vn -0.0289 0.7181 0.6953
+vn 0.0336 0.7148 0.6986
+vn 0.1332 -0.6247 0.7694
+vn 0.0547 -0.6278 0.7764
+vn 0.0407 -0.9991 0.0079
+vn 0.1064 -0.9942 -0.0166
+vn 0.0227 0.1091 0.9938
+vn -0.0379 0.0500 -0.9980
+vn -0.0656 0.0439 -0.9969
+vn -0.0999 0.7937 -0.6001
+vn -0.0584 0.7850 -0.6168
+vn 0.0380 -0.6635 -0.7472
+vn -0.0085 -0.6713 -0.7411
+vn -0.8732 -0.4872 0.0139
+vn -0.2209 0.9735 0.0600
+vn -0.1845 0.8730 0.4514
+vn 0.5726 -0.6425 0.5092
+vn -0.1681 -0.8946 0.4139
+vn 0.1516 -0.9884 -0.0104
+vn -0.3284 0.3520 0.8765
+vn -0.0779 0.1056 -0.9914
+vn -0.1938 0.8999 -0.3906
+vn -0.2088 0.0236 -0.9777
+vn -0.6045 -0.1712 -0.7779
+vn -0.8096 0.4726 -0.3482
+vn -0.4326 0.8074 -0.4012
+vn -0.9199 0.3892 0.0477
+vn -0.4070 0.9114 0.0607
+vn 0.3275 -0.9444 -0.0292
+vn -0.4146 -0.9085 0.0526
+vn -0.2486 -0.8576 -0.4502
+vn 0.1998 -0.8212 -0.5345
+vn -0.0541 0.2120 0.9758
+vn -0.5629 -0.0268 0.8261
+vn -0.1971 -0.7858 0.5863
+vn 0.2886 -0.7432 0.6036
+vn 0.0910 -0.8166 -0.5699
+vn -0.2374 -0.8666 -0.4388
+vn -0.5147 0.8181 0.2567
+vn -0.9324 -0.3612 0.0109
+vn -0.7483 0.4975 0.4388
+vn -0.3372 0.8276 0.4487
+vn 0.1555 -0.8122 -0.5622
+vn 0.1638 -0.8029 -0.5731
+vn -0.1485 0.0722 -0.9863
+vn -0.0736 0.0760 -0.9944
+vn -0.3115 0.9481 0.0636
+vn -0.3667 0.9284 0.0598
+vn -0.3268 0.8416 0.4299
+vn -0.3176 0.8353 0.4488
+vn 0.0652 -0.7833 0.6183
+vn 0.1672 -0.7777 0.6060
+vn 0.2699 -0.9624 -0.0318
+vn 0.1876 -0.9821 -0.0192
+vn -0.1350 0.2102 0.9683
+vn -0.2008 0.1620 0.9661
+vn -0.2863 0.8648 -0.4125
+vn -0.3527 0.8371 -0.4183
+vn 0.5104 0.6254 0.5902
+vn 0.4153 0.5623 0.7151
+vn 0.5788 -0.7442 0.3334
+vn 0.7359 -0.6521 0.1822
+vn -0.0267 -0.7229 0.6905
+vn -0.7782 -0.6218 -0.0880
+vn -0.3722 -0.5937 -0.7135
+vn -0.5714 0.7000 -0.4283
+vn -0.1233 0.3691 0.9212
+vn -0.8710 0.4712 0.1392
+vn -0.8425 0.2212 -0.4912
+vn -0.6016 -0.6121 -0.5133
+vn -0.3680 -0.6369 -0.6774
+vn -0.0084 -0.6750 -0.7378
+vn 0.6355 -0.6986 -0.3287
+vn 0.3370 -0.7295 -0.5952
+vn 0.7034 -0.7107 -0.0097
+vn 0.5971 -0.8019 0.0184
+vn -0.6648 -0.7399 -0.1029
+vn -0.6442 -0.7370 -0.2047
+vn -0.6517 -0.7302 0.2050
+vn -0.6664 -0.7454 0.0181
+vn 0.5592 -0.6963 0.4499
+vn 0.6826 -0.7042 0.1954
+vn 0.6484 -0.7443 0.1597
+vn 0.6931 -0.7206 0.0148
+vn -0.6342 -0.7655 -0.1091
+vn -0.7022 -0.6799 -0.2114
+vn 0.2498 -0.6440 0.7231
+vn -0.1061 -0.6663 0.7381
+vn -0.4440 -0.6813 0.5820
+vn -0.6185 -0.7625 -0.1899
+vn 0.6115 -0.7763 0.1532
+vn -0.1525 0.1246 0.9804
+vn -0.6837 0.0753 0.7259
+vn -0.7599 0.1599 -0.6301
+vn -0.4904 0.1374 -0.8606
+vn 0.9782 0.0451 0.2028
+vn 0.9665 0.0229 0.2556
+vn -0.9839 0.0914 -0.1535
+vn -0.9493 0.0983 -0.2986
+vn -0.9960 0.0812 0.0373
+vn -0.9780 0.0775 -0.1937
+vn -0.9159 0.1393 -0.3765
+vn 0.9495 0.1269 0.2870
+vn 0.7453 0.1105 0.6575
+vn 0.9970 0.0744 -0.0194
+vn 0.8740 0.0597 -0.4823
+vn 0.9951 0.0798 0.0585
+vn 0.8523 0.3909 0.3475
+vn 0.8304 0.5511 0.0824
+vn 0.9916 0.1283 0.0146
+vn 0.8484 0.5290 -0.0195
+vn 0.8577 0.4753 0.1961
+vn 0.7014 0.4469 0.5552
+vn -0.9409 0.0844 0.3281
+vn -0.4611 0.4221 0.7805
+vn -0.8080 0.4997 0.3121
+vn -0.8603 0.4813 -0.1678
+vn -0.8317 0.4977 -0.2460
+vn -0.8765 0.3184 -0.3610
+vn -0.7604 0.2592 -0.5955
+vn -0.0027 0.0640 -0.9979
+vn -0.5328 0.2307 -0.8142
+vn -0.0179 0.2134 -0.9768
+vn 0.3109 0.0989 0.9453
+vn 0.2355 0.3923 0.8892
+vn 0.5083 0.0300 -0.8607
+vn 0.5382 0.2055 -0.8174
+vn 0.9029 0.1928 -0.3841
+vn 0.9798 0.1938 -0.0499
+vn 0.9302 0.2314 0.2851
+vn -0.8834 0.4680 0.0259
+vn -0.9585 0.0708 -0.2762
+vn -0.8740 0.4463 -0.1920
+vn -0.9188 0.3598 -0.1622
+vn 0.9977 0.0636 -0.0225
+vn 0.8756 0.2043 0.4376
+vn -0.4095 0.8845 0.2238
+vn -0.4477 0.8941 0.0123
+vn -0.7826 0.3019 -0.5445
+vn -0.4740 0.2525 -0.8436
+vn -0.4131 0.9101 -0.0329
+vn -0.3908 0.8872 0.2454
+vn -0.7671 0.6409 -0.0280
+vn 0.0554 0.2166 -0.9747
+vn 0.5579 0.2025 -0.8048
+vn -0.4242 0.8999 -0.1010
+vn 0.9151 0.1009 -0.3904
+vn 0.4525 0.6614 0.5981
+vn 0.3681 0.9118 0.1818
+vn 0.3940 0.9187 -0.0283
+vn 0.5208 0.8521 0.0525
+vn 0.4086 0.8532 0.3243
+vn -0.2601 0.7859 0.5609
+vn -0.8501 0.4447 -0.2822
+vn 0.1194 0.7620 0.6365
+vn 0.4148 0.3089 -0.8559
+vn 0.8842 0.1771 -0.4323
+vn -0.6931 0.4946 -0.5244
+vn -0.3279 0.4006 -0.8556
+vn 0.9973 0.0714 -0.0155
+vn 0.1210 0.4544 -0.8825
+vn 0.7698 0.2210 0.5987
+vn 0.1922 0.4608 0.8664
+vn -0.8281 0.5387 -0.1555
+vn -0.6279 0.7573 0.1795
+vn -0.2868 0.7541 0.5909
+usemtl skin
+s 1
+f 1/1/1 27/2/2 41/3/3 30/4/4
+f 1/1/1 30/4/4 40/5/5 16/6/6
+f 1/1/1 16/6/6 36/7/7 15/8/8
+f 1/1/1 15/8/8 39/9/9 27/2/2
+f 2/10/10 23/11/11 35/12/12 14/13/13
+f 2/10/10 14/13/13 38/14/14 25/15/15
+f 65/16/16 77/17/17 380/18/18 353/19/19
+f 65/16/16 353/19/19 378/20/20 75/21/21
+f 3/22/22 25/15/15 38/14/14 19/23/23
+f 3/22/22 19/23/23 33/24/24 18/25/25
+f 66/26/26 73/27/27 373/28/28 354/29/29
+f 66/26/26 354/29/29 380/18/18 77/17/17
+f 4/30/30 20/31/31 34/32/32 21/33/33
+f 4/30/30 21/33/33 39/9/9 26/34/34
+f 67/35/35 78/36/36 381/37/37 356/38/38
+f 67/35/35 356/38/38 375/39/39 74/40/40
+f 5/41/41 26/34/34 39/9/9 15/8/8
+f 5/41/41 15/8/8 36/7/7 24/42/42
+f 68/43/43 76/44/44 379/45/45 357/46/46
+f 68/43/43 357/46/46 381/37/37 78/36/36
+f 6/47/47 13/48/48 37/49/49 29/50/50
+f 6/47/47 29/50/50 41/3/3 27/2/2
+f 6/47/47 27/2/2 39/9/9 21/33/33
+f 6/47/47 21/33/33 34/32/32 13/48/48
+f 7/51/51 17/52/52 33/24/24 19/23/23
+f 7/51/51 19/23/23 38/14/14 28/53/53
+f 7/51/51 28/53/53 41/3/3 29/50/50
+f 7/51/51 29/50/50 37/49/49 17/52/52
+f 8/54/54 28/53/53 38/14/14 14/13/13
+f 8/54/54 14/13/13 35/12/12 22/55/55
+f 8/54/54 22/55/55 40/5/5 30/4/4
+f 8/54/54 30/4/4 41/3/3 28/53/53
+f 9/56/56 16/6/6 40/5/5 31/57/57
+f 69/58/58 79/59/59 383/60/60 362/61/61
+f 69/62/58 362/63/61 379/45/45 76/44/44
+f 9/64/56 24/42/42 36/7/7 16/6/6
+f 10/65/62 22/55/55 35/12/12 23/11/11
+f 70/66/63 75/21/21 378/20/20 363/67/64
+f 70/66/63 363/67/64 383/60/60 79/59/59
+f 10/65/62 31/57/57 40/5/5 22/55/55
+f 32/68/65 12/69/66 44/70/67 43/71/68
+f 11/72/69 18/25/25 33/24/24 17/52/52
+f 11/72/69 17/52/52 37/49/49 32/68/65
+f 71/73/70 366/74/71 373/28/28 73/27/27
+f 12/69/66 32/68/65 37/49/49 13/48/48
+f 12/69/66 13/48/48 34/32/32 20/31/31
+f 72/75/72 74/40/40 375/39/39 367/76/73
+f 71/73/70 11/72/69 42/77/74 80/78/75
+f 42/77/74 43/71/68 46/79/76 45/80/77
+f 81/81/78 384/82/79 389/83/80 83/84/81
+f 11/72/69 32/68/65 43/71/68 42/77/74
+f 72/75/72 367/76/73 384/82/79 81/81/78
+f 45/85/77 46/86/76 49/87/82 48/88/83
+f 83/89/81 389/90/80 394/91/84 85/92/85
+f 43/71/68 44/70/67 47/93/86 46/79/76
+f 80/78/75 42/77/74 45/80/77 82/94/87
+f 46/86/76 47/95/86 50/96/88 49/87/82
+f 82/97/87 45/85/77 48/88/83 84/98/89
+f 169/99/90 165/100/91 133/101/92 134/102/93
+f 93/103/94 61/104/95 51/105/96 86/106/97
+f 92/107/98 417/108/99 399/109/100 87/110/101
+f 168/111/102 167/112/103 135/113/104 136/114/105
+f 741/115/106 735/116/107 404/117/108 89/118/109
+f 739/119/110 736/120/111 55/121/112 54/122/113
+f 736/123/111 738/124/114 56/125/115 55/126/112
+f 740/127/116 739/119/110 54/122/113 88/128/117
+f 753/129/118 748/130/119 59/131/120 90/132/121
+f 750/133/122 747/134/123 57/135/124 58/136/125
+f 748/130/119 750/137/122 58/138/125 59/131/120
+f 752/139/126 749/140/127 409/141/128 91/142/129
+f 163/143/130 164/144/131 132/145/132 131/146/133
+f 85/92/85 394/91/84 417/108/99 92/107/98
+f 84/98/89 48/88/83 61/104/95 93/103/94
+f 165/100/91 166/147/134 138/148/135 133/101/92
+f 119/149/136 106/150/137 95/151/138 113/152/139
+f 55/153/112 56/154/115 111/155/140
+f 55/156/112 121/157/141 54/158/113
+f 395/159/142 84/98/89 93/103/94 416/160/143
+f 50/96/88 85/92/85 92/107/98 60/161/144
+f 747/134/123 752/139/126 91/142/129 57/135/124
+f 751/162/145 753/129/118 90/132/121 413/163/146
+f 737/164/147 740/127/116 88/128/117 405/165/148
+f 738/124/114 741/115/106 89/118/109 56/125/115
+f 60/161/144 92/107/98 87/110/101 53/166/149
+f 416/160/143 93/103/94 86/106/97 400/167/150
+f 390/168/151 82/97/87 84/98/89 395/159/142
+f 385/169/152 80/78/75 82/94/87 390/170/151
+f 47/95/86 83/89/81 85/92/85 50/96/88
+f 12/69/66 72/75/72 81/81/78 44/70/67
+f 44/70/67 81/81/78 83/84/81 47/93/86
+f 366/74/71 71/73/70 80/78/75 385/169/152
+f 12/69/66 20/31/31 74/40/40 72/75/72
+f 11/72/69 71/73/70 73/27/27 18/25/25
+f 10/65/62 70/66/63 79/59/59 31/57/57
+f 10/65/62 23/11/11 75/21/21 70/66/63
+f 9/64/56 69/62/58 76/44/44 24/42/42
+f 9/56/56 31/57/57 79/59/59 69/58/58
+f 5/41/41 68/43/43 78/36/36 26/34/34
+f 5/41/41 24/42/42 76/44/44 68/43/43
+f 4/30/30 67/35/35 74/40/40 20/31/31
+f 4/30/30 26/34/34 78/36/36 67/35/35
+f 3/22/22 66/26/26 77/17/17 25/15/15
+f 3/22/22 18/25/25 73/27/27 66/26/26
+f 2/10/10 65/16/16 75/21/21 23/11/11
+f 2/10/10 25/15/15 77/17/17 65/16/16
+f 62/171/153 56/154/115 89/172/109
+f 64/173/154 88/174/117 54/158/113
+f 404/175/108 451/176/155 62/171/153 89/172/109
+f 482/177/156 421/178/157 63/179/158 120/180/159
+f 405/181/148 88/174/117 64/173/154 452/182/160
+f 110/183/161 63/184/158 421/185/157 471/186/162
+f 797/187/163 791/188/164 98/189/165 124/190/166
+f 129/191/167 108/192/168 94/193/169 122/194/170
+f 128/195/171 107/196/172 97/197/173 123/198/174
+f 118/199/175 109/200/176 96/201/177 112/202/178
+f 125/203/179 101/204/180 105/205/181 127/206/182
+f 796/207/183 793/208/184 101/204/180 125/203/179
+f 114/209/185 795/210/186 100/211/187
+f 794/212/188 792/213/189 99/214/190 115/215/191
+f 103/216/192 126/217/193 216/218/194 327/219/195
+f 114/209/185 100/211/187 104/220/196 116/221/197
+f 115/215/191 99/214/190 103/216/192 117/222/198
+f 124/190/166 98/189/165 102/223/199 126/217/193
+f 110/183/161 64/173/154 109/200/176 118/199/175
+f 121/157/141 55/156/112 107/196/172 128/195/171
+f 120/180/159 63/179/158 108/192/168 129/191/167
+f 111/155/140 62/171/153 106/150/137 119/149/136
+f 55/153/112 111/155/140 119/149/136 107/224/172
+f 63/184/158 110/183/161 118/199/175 108/225/168
+f 101/226/180 115/215/191 117/222/198 105/227/181
+f 98/228/165 114/209/185 116/221/197 102/229/199
+f 126/217/193 102/223/199 220/230/200 216/218/194
+f 793/231/184 794/212/188 115/215/191 101/226/180
+f 791/232/164 795/210/186 114/209/185 98/228/165
+f 108/225/168 118/199/175 112/202/178 94/233/169
+f 64/173/154 110/183/161 471/186/162 452/182/160
+f 107/224/172 119/149/136 113/152/139 97/234/173
+f 116/221/197 104/220/196 221/235/201 218/236/202
+f 62/171/153 120/180/159 129/191/167 106/150/137
+f 64/173/154 121/157/141 128/195/171 109/200/176
+f 99/214/190 124/190/166 126/217/193 103/216/192
+f 105/227/181 117/222/198 217/237/203 219/238/204
+f 796/207/183 125/203/179 100/211/187
+f 100/211/187 125/203/179 127/206/182 104/220/196
+f 109/200/176 128/195/171 123/198/174 96/201/177
+f 106/150/137 129/191/167 122/194/170 95/151/138
+f 792/213/189 797/187/163 124/190/166 99/214/190
+f 451/176/155 482/177/156 120/180/159 62/171/153
+f 62/171/153 111/155/140 56/154/115
+f 64/173/154 54/158/113 121/157/141
+f 781/239/205 780/240/206 143/241/207 144/242/208
+f 779/243/209 775/244/210 145/245/211 141/246/212
+f 776/247/213 777/248/214 139/249/215 147/250/216
+f 777/248/214 778/251/217 140/252/218 139/249/215
+f 166/147/134 170/253/219 130/254/220 138/148/135
+f 164/144/131 168/111/102 136/114/105 132/145/132
+f 170/253/219 163/143/130 131/146/133 130/254/220
+f 167/112/103 169/255/90 134/256/93 135/113/104
+f 765/257/221 761/258/222 148/259/223 137/260/224
+f 764/261/225 763/262/226 150/263/227 151/264/228
+f 762/265/229 759/266/230 152/267/231 153/268/232
+f 763/262/226 760/269/233 155/270/234 150/263/227
+f 778/251/217 779/243/209 141/246/212 140/252/218
+f 782/271/235 776/247/213 147/250/216 142/272/236
+f 775/244/210 781/239/205 144/242/208 145/245/211
+f 780/273/206 782/271/235 142/272/236 143/274/207
+f 149/275/237 153/276/232 177/277/238 173/278/239
+f 155/279/234 137/280/224 171/281/240 179/282/241
+f 137/280/224 148/283/223 172/284/242 171/281/240
+f 151/285/228 150/286/227 174/287/243 175/288/244
+f 760/269/233 765/257/221 137/260/224 155/270/234
+f 766/289/245 762/265/229 153/268/232 149/290/237
+f 759/266/230 764/291/225 151/292/228 152/267/231
+f 761/258/222 766/289/245 149/290/237 148/259/223
+f 727/293/246 724/294/247 162/295/248 160/296/249
+f 725/297/250 722/298/251 159/299/252 156/300/253
+f 162/295/248 724/294/247 146/301/254
+f 726/302/255 723/303/256 161/304/257 158/305/258
+f 721/306/259 726/302/255 158/305/258 157/307/260
+f 725/297/250 156/300/253 146/301/254
+f 722/308/251 721/306/259 157/307/260 159/309/252
+f 723/303/256 727/293/246 160/296/249 161/304/257
+f 53/166/149 52/310/261 169/255/90 167/112/103
+f 48/88/83 49/87/82 163/143/130 170/253/219
+f 50/96/88 60/161/144 168/111/102 164/144/131
+f 61/104/95 48/88/83 170/253/219 166/147/134
+f 51/105/96 61/104/95 166/147/134 165/100/91
+f 49/87/82 50/96/88 164/144/131 163/143/130
+f 60/161/144 53/166/149 167/112/103 168/111/102
+f 52/311/261 51/105/96 165/100/91 169/99/90
+f 172/284/242 173/278/239 181/312/262 180/313/263
+f 176/314/264 175/288/244 183/315/265 184/316/266
+f 173/278/239 177/277/238 185/317/267 181/312/262
+f 179/282/241 171/281/240 154/318/268 187/319/269
+f 152/320/231 151/285/228 175/288/244 176/314/264
+f 148/283/223 149/275/237 173/278/239 172/284/242
+f 150/321/227 155/279/234 179/282/241 174/322/243
+f 153/276/232 152/323/231 176/324/264 177/277/238
+f 703/325/270 702/326/271 178/327/272 195/328/273
+f 702/326/271 699/329/274 188/330/275 178/327/272
+f 700/331/276 697/332/277 190/333/278 191/334/279
+f 701/335/280 698/336/281 192/337/282 193/338/283
+f 174/322/243 179/282/241 187/319/269 182/339/284
+f 184/340/266 185/317/267 205/341/285 206/342/286
+f 175/288/244 174/287/243 182/343/284 183/315/265
+f 171/281/240 172/284/242 180/313/263 154/318/268
+f 194/344/287 193/338/283 192/337/282 191/345/279
+f 195/328/273 194/344/287 191/345/279 190/346/278
+f 178/327/272 188/330/275 194/344/287 195/328/273
+f 188/330/275 189/347/288 193/338/283 194/344/287
+f 704/348/289 701/335/280 193/338/283 189/347/288
+f 698/349/281 700/331/276 191/334/279 192/350/282
+f 699/329/274 704/348/289 189/347/288 188/330/275
+f 697/351/277 703/325/270 195/328/273 190/346/278
+f 710/352/290 708/353/291 201/354/292 196/355/293
+f 712/356/294 709/357/295 202/358/296 199/359/297
+f 711/360/298 705/361/299 186/362/300 198/363/301
+f 709/357/295 706/364/302 197/365/303 202/358/296
+f 706/364/302 711/366/298 198/367/301 197/365/303
+f 705/361/299 710/368/290 196/369/293 186/362/300
+f 707/370/304 712/356/294 199/359/297 200/371/305
+f 708/353/291 707/370/304 200/371/305 201/354/292
+f 203/372/306 204/373/307 208/374/308 207/375/309
+f 176/314/264 184/316/266 206/376/286 204/377/307
+f 185/317/267 177/277/238 203/372/306 205/341/285
+f 177/277/238 176/324/264 204/373/307 203/372/306
+f 208/378/308 210/379/310 214/380/311 212/381/312
+f 204/377/307 206/376/286 210/379/310 208/378/308
+f 205/341/285 203/372/306 207/375/309 209/382/313
+f 206/342/286 205/341/285 209/382/313 210/383/310
+f 211/384/314 212/385/312 214/386/311 213/387/315
+f 209/382/313 207/375/309 211/384/314 213/387/315
+f 210/383/310 209/382/313 213/387/315 214/386/311
+f 207/375/309 208/374/308 212/385/312 211/384/314
+f 104/220/196 127/206/182 215/388/316 221/235/201
+f 127/206/182 105/205/181 219/389/204 215/388/316
+f 102/229/199 116/221/197 218/236/202 220/390/200
+f 117/222/198 103/216/192 327/219/195 217/237/203
+f 241/391/317 229/392/318 225/393/319 240/394/320
+f 242/395/321 224/396/322 229/392/318 241/391/317
+f 248/397/323 226/398/324 230/399/317 247/400/317
+f 247/400/317 230/399/317 228/401/325 246/402/326
+f 239/403/317 233/404/317 232/405/327 238/406/328
+f 237/407/329 231/408/330 233/404/317 239/403/317
+f 309/409/331 235/410/332 236/411/317 308/412/317
+f 308/412/317 236/411/317 234/413/333 307/414/334
+f 222/415/335 237/407/329 239/403/317 227/416/336
+f 227/416/336 239/403/317 238/406/328 223/417/337
+f 235/410/332 242/395/321 241/391/317 236/411/317
+f 236/411/317 241/391/317 240/394/320 234/413/333
+f 230/399/317 245/418/317 244/419/338 228/401/325
+f 226/398/324 243/420/339 245/418/317 230/399/317
+f 233/404/317 247/400/317 246/402/326 232/405/327
+f 231/408/330 248/397/323 247/400/317 233/404/317
+f 223/421/337 250/422/340 254/423/341 227/424/336
+f 225/425/319 252/426/342 263/427/343 240/428/320
+f 243/429/339 265/430/344 311/431/345 309/432/331
+f 228/433/325 255/434/346 267/435/347 246/436/326
+f 246/436/326 267/435/347 258/437/348 232/438/327
+f 234/439/333 259/440/349 310/441/350 307/442/334
+f 237/443/329 261/444/351 257/445/352 231/446/330
+f 240/428/320 263/427/343 259/440/349 234/439/333
+f 309/432/331 311/431/345 260/447/353 235/448/332
+f 235/448/332 260/447/353 264/449/354 242/450/321
+f 253/451/355 273/452/356 284/453/357 265/430/344
+f 268/454/358 287/455/359 273/452/356 253/451/355
+f 261/444/351 280/456/360 276/457/361 257/445/352
+f 262/458/362 281/459/363 270/460/364 250/422/340
+f 255/434/346 274/461/365 286/462/366 267/435/347
+f 263/427/343 282/463/367 278/464/368 259/440/349
+f 256/465/369 275/466/370 272/467/371 252/426/342
+f 249/468/372 269/469/373 280/456/360 261/444/351
+f 264/449/354 283/470/374 271/471/375 251/472/376
+f 257/445/352 276/457/361 287/455/359 268/454/358
+f 311/431/345 313/473/377 279/474/378 260/447/353
+f 258/437/348 277/475/379 281/459/363 262/458/362
+f 252/426/342 272/467/371 282/463/367 263/427/343
+f 266/476/380 285/477/381 274/461/365 255/434/346
+f 310/441/350 312/478/382 285/477/381 266/476/380
+f 251/472/376 271/471/375 275/479/370 256/480/369
+f 267/435/347 286/462/366 277/475/379 258/437/348
+f 260/447/353 279/474/378 283/470/374 264/449/354
+f 313/473/377 315/481/383 298/482/384 279/474/378
+f 277/475/379 296/483/385 300/484/386 281/459/363
+f 272/467/371 291/485/387 301/486/388 282/463/367
+f 285/477/381 304/487/389 293/488/390 274/461/365
+f 312/478/382 314/489/391 304/487/389 285/477/381
+f 271/471/375 290/490/392 294/491/393 275/479/370
+f 286/462/366 305/492/394 296/483/385 277/475/379
+f 279/474/378 298/482/384 302/493/395 283/470/374
+f 273/452/356 292/494/396 303/495/397 284/453/357
+f 287/455/359 306/496/398 292/494/396 273/452/356
+f 280/456/360 299/497/399 295/498/400 276/457/361
+f 281/459/363 300/484/386 289/499/401 270/460/364
+f 274/461/365 293/488/390 305/492/394 286/462/366
+f 282/463/367 301/486/388 297/500/402 278/464/368
+f 275/466/370 294/501/393 291/485/387 272/467/371
+f 269/469/373 288/502/403 299/497/399 280/456/360
+f 283/470/374 302/493/395 290/490/392 271/471/375
+f 276/457/361 295/498/400 306/496/398 287/455/359
+f 290/490/392 302/493/395 322/503/404 319/504/405
+f 301/486/388 291/485/387 317/505/406 316/506/407
+f 302/493/395 298/482/384 323/507/408 322/503/404
+f 291/485/387 294/501/393 318/508/409 317/505/406
+f 315/481/383 303/495/397 325/509/410 324/510/411
+f 297/500/402 301/486/388 316/506/407 321/511/412
+f 294/491/393 290/490/392 319/504/405 318/512/409
+f 314/489/391 297/500/402 321/511/412 320/513/413
+f 303/495/397 304/487/389 326/514/414 325/509/410
+f 269/469/373 270/460/364 289/499/401 288/502/403
+f 300/484/386 296/483/385 295/498/400 299/497/399
+f 306/496/398 295/498/400 296/483/385 305/492/394
+f 305/492/394 293/488/390 292/494/396 306/496/398
+f 303/495/397 292/494/396 293/488/390 304/487/389
+f 304/487/389 314/489/391 320/513/413 326/514/414
+f 298/482/384 315/481/383 324/510/411 323/507/408
+f 278/464/368 297/500/402 314/489/391 312/478/382
+f 284/453/357 303/495/397 315/481/383 313/473/377
+f 259/440/349 278/464/368 312/478/382 310/441/350
+f 265/430/344 284/453/357 313/473/377 311/431/345
+f 227/424/336 254/423/341 249/468/372 222/515/335
+f 245/418/317 308/412/317 307/414/334 244/419/338
+f 243/420/339 309/409/331 308/412/317 245/418/317
+f 221/516/201 215/517/316 316/506/407 317/505/406
+f 318/512/409 319/504/405 221/518/201
+f 221/516/201 317/505/406 318/508/409
+f 219/519/204 217/520/203 320/513/413 321/511/412
+f 220/521/200 218/522/202 322/503/404 323/507/408
+f 215/517/316 219/519/204 321/511/412 316/506/407
+f 218/522/202 221/518/201 319/504/405 322/503/404
+f 327/523/195 216/524/194 324/510/411 325/509/410
+f 325/509/410 326/514/414 327/523/195
+f 217/520/203 327/523/195 326/514/414 320/513/413
+f 216/524/194 220/521/200 323/507/408 324/510/411
+f 222/515/335 249/468/372 261/444/351 237/443/329
+f 242/450/321 264/449/354 251/472/376 224/525/322
+f 248/526/323 268/454/358 253/451/355 226/527/324
+f 224/525/322 251/472/376 256/480/369 229/528/318
+f 231/446/330 257/445/352 268/454/358 248/526/323
+f 307/442/334 310/441/350 266/476/380 244/529/338
+f 232/438/327 258/437/348 262/458/362 238/530/328
+f 244/529/338 266/476/380 255/434/346 228/433/325
+f 226/527/324 253/451/355 265/430/344 243/429/339
+f 229/531/318 256/465/369 252/426/342 225/425/319
+f 238/530/328 262/458/362 250/422/340 223/421/337
+f 299/497/399 288/502/403 289/499/401 300/484/386
+f 250/422/340 270/460/364 254/423/341
+f 254/423/341 269/469/373 249/468/372
+f 269/469/373 254/423/341 270/460/364
+f 328/532/415 361/533/416 382/534/417 358/535/418
+f 328/532/415 343/536/419 377/537/420 361/533/416
+f 328/532/415 342/538/421 371/539/422 343/536/419
+f 328/532/415 358/535/418 376/540/423 342/538/421
+f 329/541/424 341/542/425 370/543/426 350/544/427
+f 329/541/424 352/545/428 374/546/429 341/542/425
+f 422/547/430 353/548/19 380/549/18 434/550/431
+f 422/547/430 432/551/432 378/552/20 353/548/19
+f 330/553/433 346/554/434 374/546/429 352/545/428
+f 330/553/433 345/555/435 368/556/436 346/554/434
+f 423/557/437 354/558/29 373/559/28 430/560/438
+f 423/557/437 434/550/431 380/549/18 354/558/29
+f 331/561/439 348/562/440 369/563/441 347/564/442
+f 331/561/439 355/565/443 376/540/423 348/562/440
+f 424/566/444 356/38/38 381/37/37 435/567/445
+f 424/566/444 431/568/446 375/39/39 356/38/38
+f 332/569/447 342/538/421 376/540/423 355/565/443
+f 332/569/447 351/570/448 371/539/422 342/538/421
+f 425/571/449 357/46/46 379/45/45 433/572/450
+f 425/571/449 435/567/445 381/37/37 357/46/46
+f 333/573/451 360/574/452 372/575/453 340/576/454
+f 333/573/451 358/535/418 382/534/417 360/574/452
+f 333/573/451 348/562/440 376/540/423 358/535/418
+f 333/573/451 340/576/454 369/563/441 348/562/440
+f 334/577/455 346/554/434 368/556/436 344/578/456
+f 334/577/455 359/579/457 374/546/429 346/554/434
+f 334/577/455 360/574/452 382/534/417 359/579/457
+f 334/577/455 344/578/456 372/575/453 360/574/452
+f 335/580/458 341/542/425 374/546/429 359/579/457
+f 335/580/458 349/581/459 370/543/426 341/542/425
+f 335/580/458 361/533/416 377/537/420 349/581/459
+f 335/580/458 359/579/457 382/534/417 361/533/416
+f 336/582/460 364/583/461 377/537/420 343/536/419
+f 426/584/462 362/585/61 383/586/60 436/587/463
+f 426/588/462 433/572/450 379/45/45 362/63/61
+f 336/589/460 343/536/419 371/539/422 351/570/448
+f 337/590/464 350/544/427 370/543/426 349/581/459
+f 427/591/465 363/592/64 378/552/20 432/551/432
+f 427/591/465 436/587/463 383/586/60 363/592/64
+f 337/590/464 349/581/459 377/537/420 364/583/461
+f 365/593/466 387/594/467 388/595/468 339/596/469
+f 338/597/470 344/578/456 368/556/436 345/555/435
+f 338/597/470 365/593/466 372/575/453 344/578/456
+f 428/598/471 430/560/438 373/559/28 366/599/71
+f 339/596/469 340/576/454 372/575/453 365/593/466
+f 339/596/469 347/564/442 369/563/441 340/576/454
+f 429/600/472 367/76/73 375/39/39 431/568/446
+f 428/598/471 437/601/473 386/602/474 338/597/470
+f 386/602/474 391/603/475 392/604/476 387/594/467
+f 438/605/477 440/606/478 389/83/80 384/82/79
+f 338/597/470 386/602/474 387/594/467 365/593/466
+f 429/600/472 438/605/477 384/82/79 367/76/73
+f 391/607/475 396/608/479 397/609/480 392/610/476
+f 440/611/478 442/612/481 394/91/84 389/90/80
+f 387/594/467 392/604/476 393/613/482 388/595/468
+f 437/601/473 439/614/483 391/603/475 386/602/474
+f 392/610/476 397/609/480 398/615/484 393/616/482
+f 439/617/483 441/618/485 396/608/479 391/607/475
+f 530/619/486 495/620/487 494/621/488 526/622/489
+f 450/623/490 443/624/491 401/625/492 415/626/493
+f 449/627/494 444/628/495 399/109/100 417/108/99
+f 529/629/496 497/630/497 496/631/498 528/632/499
+f 746/633/500 446/634/501 404/117/108 735/116/107
+f 744/635/502 406/636/503 407/637/504 742/638/505
+f 742/639/505 407/640/504 408/641/506 743/642/507
+f 745/643/508 445/644/509 406/636/503 744/635/502
+f 758/645/510 447/646/511 412/647/512 755/648/513
+f 756/649/514 411/650/515 410/651/516 754/652/517
+f 755/648/513 412/647/512 411/653/515 756/654/514
+f 757/655/518 448/656/519 409/141/128 749/140/127
+f 524/657/520 492/658/521 493/659/522 525/660/523
+f 442/612/481 449/627/494 417/108/99 394/91/84
+f 441/618/485 450/623/490 415/626/493 396/608/479
+f 526/622/489 494/621/488 499/661/524 527/662/525
+f 479/663/526 473/664/527 454/665/528 465/666/529
+f 407/667/504 470/668/530 408/669/506
+f 407/670/504 406/671/503 481/672/531
+f 395/159/142 416/160/143 450/623/490 441/618/485
+f 398/615/484 414/673/532 449/627/494 442/612/481
+f 754/652/517 410/651/516 448/656/519 757/655/518
+f 751/162/145 413/163/146 447/646/511 758/645/510
+f 737/164/147 405/165/148 445/644/509 745/643/508
+f 743/642/507 408/641/506 446/634/501 746/633/500
+f 414/673/532 403/674/533 444/628/495 449/627/494
+f 416/160/143 400/167/150 443/624/491 450/623/490
+f 390/168/151 395/159/142 441/618/485 439/617/483
+f 385/675/152 390/676/151 439/614/483 437/601/473
+f 393/616/482 398/615/484 442/612/481 440/611/478
+f 339/596/469 388/595/468 438/605/477 429/600/472
+f 388/595/468 393/613/482 440/606/478 438/605/477
+f 366/599/71 385/675/152 437/601/473 428/598/471
+f 339/596/469 429/600/472 431/568/446 347/564/442
+f 338/597/470 345/555/435 430/560/438 428/598/471
+f 337/590/464 364/583/461 436/587/463 427/591/465
+f 337/590/464 427/591/465 432/551/432 350/544/427
+f 336/589/460 351/570/448 433/572/450 426/588/462
+f 336/582/460 426/584/462 436/587/463 364/583/461
+f 332/569/447 355/565/443 435/567/445 425/571/449
+f 332/569/447 425/571/449 433/572/450 351/570/448
+f 331/561/439 347/564/442 431/568/446 424/566/444
+f 331/561/439 424/566/444 435/567/445 355/565/443
+f 330/553/433 352/545/428 434/550/431 423/557/437
+f 330/553/433 423/557/437 430/560/438 345/555/435
+f 329/541/424 350/544/427 432/551/432 422/547/430
+f 329/541/424 422/547/430 434/550/431 352/545/428
+f 418/677/534 446/678/501 408/669/506
+f 420/679/535 406/671/503 445/680/509
+f 404/175/108 446/678/501 418/677/534 451/176/155
+f 482/177/156 480/681/536 419/682/537 421/178/157
+f 405/181/148 452/182/160 420/679/535 445/680/509
+f 469/683/538 471/186/162 421/185/157 419/684/537
+f 804/685/539 485/686/540 457/687/541 798/688/542
+f 490/689/543 483/690/544 453/691/545 467/692/546
+f 489/693/547 484/694/548 456/695/549 466/696/550
+f 478/697/551 472/698/552 455/699/553 468/700/554
+f 486/701/555 488/702/556 464/703/557 460/704/558
+f 803/705/559 486/701/555 460/704/558 800/706/560
+f 802/707/561 474/708/562 459/709/563
+f 801/710/564 475/711/565 458/712/566 799/713/567
+f 462/714/568 688/715/569 577/716/570 487/717/571
+f 474/708/562 476/718/572 463/719/573 459/709/563
+f 475/711/565 477/720/574 462/714/568 458/712/566
+f 485/686/540 487/717/571 461/721/575 457/687/541
+f 469/683/538 478/697/551 468/700/554 420/679/535
+f 481/672/531 489/693/547 466/696/550 407/670/504
+f 480/681/536 490/689/543 467/692/546 419/682/537
+f 470/668/530 479/663/526 465/666/529 418/677/534
+f 407/667/504 466/722/550 479/663/526 470/668/530
+f 419/684/537 467/723/546 478/697/551 469/683/538
+f 460/724/558 464/725/557 477/720/574 475/711/565
+f 457/726/541 461/727/575 476/718/572 474/708/562
+f 487/717/571 577/716/570 581/728/576 461/721/575
+f 800/729/560 460/724/558 475/711/565 801/710/564
+f 798/730/542 457/726/541 474/708/562 802/707/561
+f 467/723/546 453/731/545 472/698/552 478/697/551
+f 420/679/535 452/182/160 471/186/162 469/683/538
+f 466/722/550 456/732/549 473/664/527 479/663/526
+f 476/718/572 579/733/577 582/734/578 463/719/573
+f 418/677/534 465/666/529 490/689/543 480/681/536
+f 420/679/535 468/700/554 489/693/547 481/672/531
+f 458/712/566 462/714/568 487/717/571 485/686/540
+f 464/725/557 580/735/579 578/736/580 477/720/574
+f 459/709/563 486/701/555 803/705/559
+f 459/709/563 463/719/573 488/702/556 486/701/555
+f 468/700/554 455/699/553 484/694/548 489/693/547
+f 465/666/529 454/665/528 483/690/544 490/689/543
+f 799/713/567 458/712/566 485/686/540 804/685/539
+f 451/176/155 418/677/534 480/681/536 482/177/156
+f 418/677/534 408/669/506 470/668/530
+f 420/679/535 481/672/531 406/671/503
+f 789/737/581 505/738/582 504/739/583 788/740/584
+f 787/741/585 502/742/586 506/743/587 783/744/588
+f 784/745/589 508/746/590 500/747/591 785/748/592
+f 785/748/592 500/747/591 501/749/593 786/750/594
+f 527/662/525 499/661/524 491/751/595 531/752/596
+f 525/660/523 493/659/522 497/630/497 529/629/496
+f 531/752/596 491/751/595 492/658/521 524/657/520
+f 528/632/499 496/631/498 495/753/487 530/754/486
+f 773/755/597 498/756/598 509/757/599 769/758/600
+f 772/759/601 512/760/602 511/761/603 771/762/604
+f 770/763/605 514/764/606 513/765/607 767/766/608
+f 771/762/604 511/761/603 516/767/609 768/768/610
+f 786/750/594 501/749/593 502/742/586 787/741/585
+f 790/769/611 503/770/612 508/746/590 784/745/589
+f 783/744/588 506/743/587 505/738/582 789/737/581
+f 788/771/584 504/772/583 503/770/612 790/769/611
+f 510/773/613 534/774/614 538/775/615 514/776/606
+f 516/777/609 540/778/616 532/779/617 498/780/598
+f 498/780/598 532/779/617 533/781/618 509/782/599
+f 512/783/602 536/784/619 535/785/620 511/786/603
+f 768/768/610 516/767/609 498/756/598 773/755/597
+f 774/787/621 510/788/613 514/764/606 770/763/605
+f 767/766/608 513/765/607 512/789/602 772/790/601
+f 769/758/600 509/757/599 510/788/613 774/787/621
+f 734/791/622 521/792/623 523/793/624 731/794/625
+f 732/795/626 517/796/627 520/797/628 729/798/629
+f 731/794/625 523/793/624 507/799/630
+f 733/800/631 519/801/632 522/802/633 730/803/634
+f 728/804/635 518/805/636 519/801/632 733/800/631
+f 507/799/630 517/796/627 732/795/626
+f 729/806/629 520/807/628 518/805/636 728/804/635
+f 730/803/634 522/802/633 521/792/623 734/791/622
+f 403/674/533 528/632/499 530/754/486 402/808/637
+f 396/608/479 531/752/596 524/657/520 397/609/480
+f 398/615/484 525/660/523 529/629/496 414/673/532
+f 415/626/493 527/662/525 531/752/596 396/608/479
+f 401/625/492 526/622/489 527/662/525 415/626/493
+f 397/609/480 524/657/520 525/660/523 398/615/484
+f 414/673/532 529/629/496 528/632/499 403/674/533
+f 402/809/637 530/619/486 526/622/489 401/625/492
+f 533/781/618 541/810/638 542/811/639 534/774/614
+f 537/812/640 545/813/641 544/814/642 536/784/619
+f 534/774/614 542/811/639 546/815/643 538/775/615
+f 540/778/616 548/816/644 515/817/645 532/779/617
+f 513/818/607 537/812/640 536/784/619 512/783/602
+f 509/782/599 533/781/618 534/774/614 510/773/613
+f 511/819/603 535/820/620 540/778/616 516/777/609
+f 514/776/606 538/775/615 537/821/640 513/822/607
+f 695/823/646 556/824/647 539/825/648 694/826/649
+f 694/826/649 539/825/648 549/827/650 691/828/651
+f 692/829/652 552/830/653 551/831/654 689/832/655
+f 693/833/656 554/834/657 553/835/658 690/836/659
+f 535/820/620 543/837/660 548/816/644 540/778/616
+f 545/838/641 567/839/661 566/840/662 546/815/643
+f 536/784/619 544/814/642 543/841/660 535/785/620
+f 532/779/617 515/817/645 541/810/638 533/781/618
+f 555/842/663 552/843/653 553/835/658 554/834/657
+f 556/824/647 551/844/654 552/843/653 555/842/663
+f 539/825/648 556/824/647 555/842/663 549/827/650
+f 549/827/650 555/842/663 554/834/657 550/845/664
+f 696/846/665 550/845/664 554/834/657 693/833/656
+f 690/847/659 553/848/658 552/830/653 692/829/652
+f 691/828/651 549/827/650 550/845/664 696/846/665
+f 689/849/655 551/844/654 556/824/647 695/823/646
+f 718/850/666 557/851/667 562/852/668 716/853/669
+f 720/854/670 560/855/671 563/856/672 717/857/673
+f 719/858/674 559/859/675 547/860/676 713/861/677
+f 717/857/673 563/856/672 558/862/678 714/863/679
+f 714/863/679 558/862/678 559/864/675 719/865/674
+f 713/861/677 547/860/676 557/866/667 718/867/666
+f 715/868/680 561/869/681 560/855/671 720/854/670
+f 716/853/669 562/852/668 561/869/681 715/868/680
+f 564/870/682 568/871/683 569/872/684 565/873/685
+f 537/812/640 565/874/685 567/875/661 545/813/641
+f 546/815/643 566/840/662 564/870/682 538/775/615
+f 538/775/615 564/870/682 565/873/685 537/821/640
+f 569/876/684 573/877/686 575/878/687 571/879/688
+f 565/874/685 569/876/684 571/879/688 567/875/661
+f 566/840/662 570/880/689 568/871/683 564/870/682
+f 567/839/661 571/881/688 570/880/689 566/840/662
+f 572/882/690 574/883/691 575/884/687 573/885/686
+f 570/880/689 574/883/691 572/882/690 568/871/683
+f 571/881/688 575/884/687 574/883/691 570/880/689
+f 568/871/683 572/882/690 573/885/686 569/872/684
+f 463/719/573 582/734/578 576/886/692 488/702/556
+f 488/702/556 576/886/692 580/887/579 464/703/557
+f 461/727/575 581/888/576 579/733/577 476/718/572
+f 477/720/574 578/736/580 688/715/569 462/714/568
+f 602/889/317 601/890/693 586/891/694 590/892/695
+f 603/893/696 602/889/317 590/892/695 585/894/697
+f 609/895/698 608/896/317 591/897/317 587/898/699
+f 608/896/317 607/899/700 589/900/701 591/897/317
+f 600/901/317 599/902/702 593/903/703 594/904/317
+f 598/905/704 600/901/317 594/904/317 592/906/705
+f 670/907/706 669/908/317 597/909/317 596/910/707
+f 669/908/317 668/911/708 595/912/709 597/909/317
+f 583/913/710 588/914/711 600/901/317 598/905/704
+f 588/914/711 584/915/712 599/902/702 600/901/317
+f 596/910/707 597/909/317 602/889/317 603/893/696
+f 597/909/317 595/912/709 601/890/693 602/889/317
+f 591/897/317 589/900/701 605/916/713 606/917/317
+f 587/898/699 591/897/317 606/917/317 604/918/714
+f 594/904/317 593/903/703 607/899/700 608/896/317
+f 592/906/705 594/904/317 608/896/317 609/895/698
+f 584/919/712 588/920/711 615/921/715 611/922/716
+f 586/923/694 601/924/693 624/925/717 613/926/718
+f 604/927/714 670/928/706 672/929/719 626/930/720
+f 589/931/701 607/932/700 628/933/721 616/934/722
+f 607/932/700 593/935/703 619/936/723 628/933/721
+f 595/937/709 668/938/708 671/939/724 620/940/725
+f 598/941/704 592/942/705 618/943/726 622/944/727
+f 601/924/693 595/937/709 620/940/725 624/925/717
+f 670/928/706 596/945/707 621/946/728 672/929/719
+f 596/945/707 603/947/696 625/948/729 621/946/728
+f 614/949/730 626/930/720 645/950/731 634/951/732
+f 629/952/733 614/949/730 634/951/732 648/953/734
+f 622/944/727 618/943/726 637/954/735 641/955/736
+f 623/956/737 611/922/716 631/957/738 642/958/739
+f 616/934/722 628/933/721 647/959/740 635/960/741
+f 624/925/717 620/940/725 639/961/742 643/962/743
+f 617/963/744 613/926/718 633/964/745 636/965/746
+f 610/966/747 622/944/727 641/955/736 630/967/748
+f 625/948/729 612/968/749 632/969/750 644/970/751
+f 618/943/726 629/952/733 648/953/734 637/954/735
+f 672/929/719 621/946/728 640/971/752 674/972/753
+f 619/936/723 623/956/737 642/958/739 638/973/754
+f 613/926/718 624/925/717 643/962/743 633/964/745
+f 627/974/755 616/934/722 635/960/741 646/975/756
+f 671/939/724 627/974/755 646/975/756 673/976/757
+f 612/968/749 617/977/744 636/978/746 632/969/750
+f 628/933/721 619/936/723 638/973/754 647/959/740
+f 621/946/728 625/948/729 644/970/751 640/971/752
+f 674/972/753 640/971/752 659/979/758 676/980/759
+f 638/973/754 642/958/739 661/981/760 657/982/761
+f 633/964/745 643/962/743 662/983/762 652/984/763
+f 646/975/756 635/960/741 654/985/764 665/986/765
+f 673/976/757 646/975/756 665/986/765 675/987/766
+f 632/969/750 636/978/746 655/988/767 651/989/768
+f 647/959/740 638/973/754 657/982/761 666/990/769
+f 640/971/752 644/970/751 663/991/770 659/979/758
+f 634/951/732 645/950/731 664/992/771 653/993/772
+f 648/953/734 634/951/732 653/993/772 667/994/773
+f 641/955/736 637/954/735 656/995/774 660/996/775
+f 642/958/739 631/957/738 650/997/776 661/981/760
+f 635/960/741 647/959/740 666/990/769 654/985/764
+f 643/962/743 639/961/742 658/998/777 662/983/762
+f 636/965/746 633/964/745 652/984/763 655/999/767
+f 630/967/748 641/955/736 660/996/775 649/1000/778
+f 644/970/751 632/969/750 651/989/768 663/991/770
+f 637/954/735 648/953/734 667/994/773 656/995/774
+f 651/989/768 680/1001/779 683/1002/780 663/991/770
+f 662/983/762 677/1003/781 678/1004/782 652/984/763
+f 663/991/770 683/1002/780 684/1005/783 659/979/758
+f 652/984/763 678/1004/782 679/1006/784 655/999/767
+f 676/980/759 685/1007/785 686/1008/786 664/992/771
+f 658/998/777 682/1009/787 677/1003/781 662/983/762
+f 655/988/767 679/1010/784 680/1001/779 651/989/768
+f 675/987/766 681/1011/788 682/1009/787 658/998/777
+f 664/992/771 686/1008/786 687/1012/789 665/986/765
+f 630/967/748 649/1000/778 650/997/776 631/957/738
+f 661/981/760 660/996/775 656/995/774 657/982/761
+f 667/994/773 666/990/769 657/982/761 656/995/774
+f 666/990/769 667/994/773 653/993/772 654/985/764
+f 664/992/771 665/986/765 654/985/764 653/993/772
+f 665/986/765 687/1012/789 681/1011/788 675/987/766
+f 659/979/758 684/1005/783 685/1007/785 676/980/759
+f 639/961/742 673/976/757 675/987/766 658/998/777
+f 645/950/731 674/972/753 676/980/759 664/992/771
+f 620/940/725 671/939/724 673/976/757 639/961/742
+f 626/930/720 672/929/719 674/972/753 645/950/731
+f 588/920/711 583/1013/710 610/966/747 615/921/715
+f 606/917/317 605/916/713 668/911/708 669/908/317
+f 604/918/714 606/917/317 669/908/317 670/907/706
+f 582/1014/578 678/1004/782 677/1003/781 576/1015/692
+f 679/1010/784 582/1016/578 680/1001/779
+f 582/1014/578 679/1006/784 678/1004/782
+f 580/1017/579 682/1009/787 681/1011/788 578/1018/580
+f 581/1019/576 684/1005/783 683/1002/780 579/1020/577
+f 576/1015/692 677/1003/781 682/1009/787 580/1017/579
+f 579/1020/577 683/1002/780 680/1001/779 582/1016/578
+f 688/1021/569 686/1008/786 685/1007/785 577/1022/570
+f 686/1008/786 688/1021/569 687/1012/789
+f 578/1018/580 681/1011/788 687/1012/789 688/1021/569
+f 577/1022/570 685/1007/785 684/1005/783 581/1019/576
+f 583/1013/710 598/941/704 622/944/727 610/966/747
+f 603/947/696 585/1023/697 612/968/749 625/948/729
+f 609/1024/698 587/1025/699 614/949/730 629/952/733
+f 585/1023/697 590/1026/695 617/977/744 612/968/749
+f 592/942/705 609/1024/698 629/952/733 618/943/726
+f 668/938/708 605/1027/713 627/974/755 671/939/724
+f 593/935/703 599/1028/702 623/956/737 619/936/723
+f 605/1027/713 589/931/701 616/934/722 627/974/755
+f 587/1025/699 604/927/714 626/930/720 614/949/730
+f 590/1029/695 586/923/694 613/926/718 617/963/744
+f 599/1028/702 584/919/712 611/922/716 623/956/737
+f 660/996/775 661/981/760 650/997/776 649/1000/778
+f 611/922/716 615/921/715 631/957/738
+f 615/921/715 610/966/747 630/967/748
+f 630/967/748 631/957/738 615/921/715
+f 557/851/667 689/849/655 695/823/646 562/852/668
+f 560/855/671 691/828/651 696/846/665 563/856/672
+f 559/859/675 690/847/659 692/829/652 547/860/676
+f 563/856/672 696/846/665 693/833/656 558/862/678
+f 558/862/678 693/833/656 690/836/659 559/864/675
+f 547/860/676 692/829/652 689/832/655 557/866/667
+f 561/869/681 694/826/649 691/828/651 560/855/671
+f 562/852/668 695/823/646 694/826/649 561/869/681
+f 196/355/293 201/354/292 703/325/270 697/351/277
+f 199/359/297 202/358/296 704/348/289 699/329/274
+f 198/363/301 186/362/300 700/331/276 698/349/281
+f 202/358/296 197/365/303 701/335/280 704/348/289
+f 197/365/303 198/367/301 698/336/281 701/335/280
+f 186/362/300 196/369/293 697/332/277 700/331/276
+f 200/371/305 199/359/297 699/329/274 702/326/271
+f 201/354/292 200/371/305 702/326/271 703/325/270
+f 187/319/269 154/318/268 707/370/304 708/353/291
+f 154/318/268 180/313/263 712/356/294 707/370/304
+f 183/315/265 182/343/284 710/368/290 705/361/299
+f 185/317/267 184/340/266 711/366/298 706/364/302
+f 181/312/262 185/317/267 706/364/302 709/357/295
+f 184/316/266 183/315/265 705/361/299 711/360/298
+f 180/313/263 181/312/262 709/357/295 712/356/294
+f 182/339/284 187/319/269 708/353/291 710/352/290
+f 548/816/644 716/853/669 715/868/680 515/817/645
+f 515/817/645 715/868/680 720/854/670 541/810/638
+f 544/814/642 713/861/677 718/867/666 543/841/660
+f 546/815/643 714/863/679 719/865/674 545/838/641
+f 542/811/639 717/857/673 714/863/679 546/815/643
+f 545/813/641 719/858/674 713/861/677 544/814/642
+f 541/810/638 720/854/670 717/857/673 542/811/639
+f 543/837/660 718/850/666 716/853/669 548/816/644
+f 139/249/215 140/252/218 727/293/246 723/303/256
+f 143/274/207 142/272/236 721/306/259 722/308/251
+f 145/245/211 144/242/208 725/297/250
+f 142/272/236 147/250/216 726/302/255 721/306/259
+f 147/250/216 139/249/215 723/303/256 726/302/255
+f 141/246/212 145/245/211 724/294/247
+f 144/242/208 143/241/207 722/298/251 725/297/250
+f 140/252/218 141/246/212 724/294/247 727/293/246
+f 500/747/591 730/803/634 734/791/622 501/749/593
+f 504/772/583 729/806/629 728/804/635 503/770/612
+f 505/738/582 506/743/587 732/795/626
+f 503/770/612 728/804/635 733/800/631 508/746/590
+f 508/746/590 733/800/631 730/803/634 500/747/591
+f 502/742/586 731/794/625 506/743/587
+f 505/738/582 732/795/626 729/798/629 504/739/583
+f 501/749/593 734/791/622 731/794/625 502/742/586
+f 410/651/516 743/642/507 746/633/500 448/656/519
+f 413/163/146 737/164/147 745/643/508 447/646/511
+f 447/646/511 745/643/508 744/635/502 412/647/512
+f 411/650/515 742/639/505 743/642/507 410/651/516
+f 412/647/512 744/635/502 742/638/505 411/653/515
+f 448/656/519 746/633/500 735/116/107 409/141/128
+f 57/135/124 91/142/129 741/115/106 738/124/114
+f 413/163/146 90/132/121 740/127/116 737/164/147
+f 90/132/121 59/131/120 739/119/110 740/127/116
+f 58/136/125 57/135/124 738/124/114 736/123/111
+f 59/131/120 58/138/125 736/120/111 739/119/110
+f 91/142/129 409/141/128 735/116/107 741/115/106
+f 400/167/150 751/162/145 758/645/510 443/624/491
+f 403/674/533 754/652/517 757/655/518 444/628/495
+f 444/628/495 757/655/518 749/140/127 399/109/100
+f 401/625/492 755/648/513 756/654/514 402/809/637
+f 402/808/637 756/649/514 754/652/517 403/674/533
+f 443/624/491 758/645/510 755/648/513 401/625/492
+f 400/167/150 86/106/97 753/129/118 751/162/145
+f 53/166/149 87/110/101 752/139/126 747/134/123
+f 87/110/101 399/109/100 749/140/127 752/139/126
+f 51/105/96 52/311/261 750/137/122 748/130/119
+f 52/310/261 53/166/149 747/134/123 750/133/122
+f 86/106/97 51/105/96 748/130/119 753/129/118
+f 160/296/249 162/295/248 766/289/245 761/258/222
+f 156/300/253 159/299/252 764/291/225 759/266/230
+f 162/295/248 146/301/254 762/265/229 766/289/245
+f 158/305/258 161/304/257 765/257/221 760/269/233
+f 157/307/260 158/305/258 760/269/233 763/262/226
+f 146/301/254 156/300/253 759/266/230 762/265/229
+f 159/309/252 157/307/260 763/262/226 764/261/225
+f 161/304/257 160/296/249 761/258/222 765/257/221
+f 521/792/623 769/758/600 774/787/621 523/793/624
+f 517/796/627 767/766/608 772/790/601 520/797/628
+f 523/793/624 774/787/621 770/763/605 507/799/630
+f 519/801/632 768/768/610 773/755/597 522/802/633
+f 518/805/636 771/762/604 768/768/610 519/801/632
+f 507/799/630 770/763/605 767/766/608 517/796/627
+f 520/807/628 772/759/601 771/762/604 518/805/636
+f 522/802/633 773/755/597 769/758/600 521/792/623
+f 134/102/93 133/101/92 782/271/235 780/273/206
+f 136/114/105 135/113/104 781/239/205 775/244/210
+f 133/101/92 138/148/135 776/247/213 782/271/235
+f 131/146/133 132/145/132 779/243/209 778/251/217
+f 130/254/220 131/146/133 778/251/217 777/248/214
+f 138/148/135 130/254/220 777/248/214 776/247/213
+f 132/145/132 136/114/105 775/244/210 779/243/209
+f 135/113/104 134/256/93 780/240/206 781/239/205
+f 495/620/487 788/771/584 790/769/611 494/621/488
+f 497/630/497 783/744/588 789/737/581 496/631/498
+f 494/621/488 790/769/611 784/745/589 499/661/524
+f 492/658/521 786/750/594 787/741/585 493/659/522
+f 491/751/595 785/748/592 786/750/594 492/658/521
+f 499/661/524 784/745/589 785/748/592 491/751/595
+f 493/659/522 787/741/585 783/744/588 497/630/497
+f 496/631/498 789/737/581 788/740/584 495/753/487
+f 506/743/587 507/799/630 732/795/626
+f 145/245/211 146/301/254 724/294/247
+f 506/743/587 731/794/625 507/799/630
+f 145/245/211 725/297/250 146/301/254
+f 95/151/138 122/194/170 797/187/163 792/213/189
+f 96/201/177 123/198/174 796/207/183
+f 94/233/169 112/202/178 795/210/186 791/232/164
+f 97/234/173 113/152/139 794/212/188 793/231/184
+f 113/152/139 95/151/138 792/213/189 794/212/188
+f 112/202/178 96/201/177 795/210/186
+f 123/198/174 97/197/173 793/208/184 796/207/183
+f 122/194/170 94/193/169 791/188/164 797/187/163
+f 454/665/528 799/713/567 804/685/539 483/690/544
+f 484/694/548 455/699/553 803/705/559
+f 453/731/545 798/730/542 802/707/561 472/698/552
+f 456/732/549 800/729/560 801/710/564 473/664/527
+f 473/664/527 801/710/564 799/713/567 454/665/528
+f 472/698/552 802/707/561 455/699/553
+f 484/694/548 803/705/559 800/706/560 456/695/549
+f 483/690/544 804/685/539 798/688/542 453/691/545
+f 455/699/553 459/709/563 803/705/559
+f 96/201/177 100/211/187 795/210/186
+f 455/699/553 802/707/561 459/709/563
+f 96/201/177 796/207/183 100/211/187
diff --git a/examples/models/resources/models/obj/character_diffuse.png b/examples/models/resources/models/obj/character_diffuse.png
new file mode 100644
index 000000000..0fae9d894
Binary files /dev/null and b/examples/models/resources/models/obj/character_diffuse.png differ
diff --git a/examples/models/resources/raylib_logo.png b/examples/models/resources/raylib_logo.png
new file mode 100644
index 000000000..15bbaa2f4
Binary files /dev/null and b/examples/models/resources/raylib_logo.png differ
diff --git a/examples/models/resources/skillbot.png b/examples/models/resources/skillbot.png
new file mode 100644
index 000000000..537f13383
Binary files /dev/null and b/examples/models/resources/skillbot.png differ
diff --git a/examples/others/easings_testbed.c b/examples/others/easings_testbed.c
index b3ff8a8df..fa4a599ee 100644
--- a/examples/others/easings_testbed.c
+++ b/examples/others/easings_testbed.c
@@ -221,7 +221,7 @@ int main(void)
}
-// NoEase function, used when "no easing" is selected for any axis
+// NoEase function, used when "no easing" is selected for any axis
// It just ignores all parameters besides b
static float NoEase(float t, float b, float c, float d)
{
diff --git a/examples/others/web_basic_window.c b/examples/others/web_basic_window.c
index f85c6e4f6..217c47fbc 100644
--- a/examples/others/web_basic_window.c
+++ b/examples/others/web_basic_window.c
@@ -36,7 +36,7 @@ void UpdateDrawFrame(void); // Update and Draw one frame
//----------------------------------------------------------------------------------
// Program main entry point
//----------------------------------------------------------------------------------
-int main()
+int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
diff --git a/examples/shaders/raygui.h b/examples/shaders/raygui.h
new file mode 100644
index 000000000..88fe5cc5b
--- /dev/null
+++ b/examples/shaders/raygui.h
@@ -0,0 +1,5987 @@
+/*******************************************************************************************
+*
+* raygui v4.5-dev - A simple and easy-to-use immediate-mode gui library
+*
+* DESCRIPTION:
+* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also
+* available as a standalone library, as long as input and drawing functions are provided
+*
+* FEATURES:
+* - Immediate-mode gui, minimal retained data
+* - +25 controls provided (basic and advanced)
+* - Styling system for colors, font and metrics
+* - Icons supported, embedded as a 1-bit icons pack
+* - Standalone mode option (custom input/graphics backend)
+* - Multiple support tools provided for raygui development
+*
+* POSSIBLE IMPROVEMENTS:
+* - Better standalone mode API for easy plug of custom backends
+* - Externalize required inputs, allow user easier customization
+*
+* LIMITATIONS:
+* - No editable multi-line word-wraped text box supported
+* - No auto-layout mechanism, up to the user to define controls position and size
+* - Standalone mode requires library modification and some user work to plug another backend
+*
+* NOTES:
+* - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for
+* font atlas recs and glyphs, freeing that memory is (usually) up to the user,
+* no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads
+* by default any previously loaded font (texture, recs, glyphs)
+* - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions
+*
+* CONTROLS PROVIDED:
+* # Container/separators Controls
+* - WindowBox --> StatusBar, Panel
+* - GroupBox --> Line
+* - Line
+* - Panel --> StatusBar
+* - ScrollPanel --> StatusBar
+* - TabBar --> Button
+*
+* # Basic Controls
+* - Label
+* - LabelButton --> Label
+* - Button
+* - Toggle
+* - ToggleGroup --> Toggle
+* - ToggleSlider
+* - CheckBox
+* - ComboBox
+* - DropdownBox
+* - TextBox
+* - ValueBox --> TextBox
+* - Spinner --> Button, ValueBox
+* - Slider
+* - SliderBar --> Slider
+* - ProgressBar
+* - StatusBar
+* - DummyRec
+* - Grid
+*
+* # Advance Controls
+* - ListView
+* - ColorPicker --> ColorPanel, ColorBarHue
+* - MessageBox --> Window, Label, Button
+* - TextInputBox --> Window, Label, TextBox, Button
+*
+* It also provides a set of functions for styling the controls based on its properties (size, color)
+*
+*
+* RAYGUI STYLE (guiStyle):
+* raygui uses a global data array for all gui style properties (allocated on data segment by default),
+* when a new style is loaded, it is loaded over the global style... but a default gui style could always be
+* recovered with GuiLoadStyleDefault() function, that overwrites the current style to the default one
+*
+* The global style array size is fixed and depends on the number of controls and properties:
+*
+* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)];
+*
+* guiStyle size is by default: 16*(16 + 8) = 384 int = 384*4 bytes = 1536 bytes = 1.5 KB
+*
+* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style
+* used for all controls, when any of those base values is set, it is automatically populated to all
+* controls, so, specific control values overwriting generic style should be set after base values
+*
+* After the first BASE set we have the EXTENDED properties (by default guiStyle[16..23]), those
+* properties are actually common to all controls and can not be overwritten individually (like BASE ones)
+* Some of those properties are: TEXT_SIZE, TEXT_SPACING, LINE_COLOR, BACKGROUND_COLOR
+*
+* Custom control properties can be defined using the EXTENDED properties for each independent control.
+*
+* TOOL: rGuiStyler is a visual tool to customize raygui style: github.com/raysan5/rguistyler
+*
+*
+* RAYGUI ICONS (guiIcons):
+* raygui could use a global array containing icons data (allocated on data segment by default),
+* a custom icons set could be loaded over this array using GuiLoadIcons(), but loaded icons set
+* must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS will be loaded
+*
+* Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon
+* requires 8 integers (16*16/32) to be stored in memory.
+*
+* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set
+*
+* The global icons array size is fixed and depends on the number of icons and size:
+*
+* static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS];
+*
+* guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB
+*
+* TOOL: rGuiIcons is a visual tool to customize/create raygui icons: github.com/raysan5/rguiicons
+*
+* RAYGUI LAYOUT:
+* raygui currently does not provide an auto-layout mechanism like other libraries,
+* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it
+*
+* TOOL: rGuiLayout is a visual tool to create raygui layouts: github.com/raysan5/rguilayout
+*
+* CONFIGURATION:
+* #define RAYGUI_IMPLEMENTATION
+* 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
+*
+* #define RAYGUI_STANDALONE
+* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined
+* internally in the library and input management and drawing functions must be provided by
+* the user (check library implementation for further details)
+*
+* #define RAYGUI_NO_ICONS
+* Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB)
+*
+* #define RAYGUI_CUSTOM_ICONS
+* Includes custom ricons.h header defining a set of custom icons,
+* this file can be generated using rGuiIcons tool
+*
+* #define RAYGUI_DEBUG_RECS_BOUNDS
+* Draw control bounds rectangles for debug
+*
+* #define RAYGUI_DEBUG_TEXT_BOUNDS
+* Draw text bounds rectangles for debug
+*
+* VERSIONS HISTORY:
+* 5.0 (xx-Nov-2025) ADDED: Support up to 32 controls (v500)
+* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
+* ADDED: GuiValueBoxFloat()
+* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
+* ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH
+* ADDED: GuiLoadIconsFromMemory()
+* ADDED: Multiple new icons
+* REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties
+* REMOVED: GuiSliderPro(), functionality was redundant
+* REVIEWED: Controls using text labels to use LABEL properties
+* REVIEWED: Replaced sprintf() by snprintf() for more safety
+* REVIEWED: GuiTabBar(), close tab with mouse middle button
+* REVIEWED: GuiScrollPanel(), scroll speed proportional to content
+* REVIEWED: GuiDropdownBox(), support roll up and hidden arrow
+* REVIEWED: GuiTextBox(), cursor position initialization
+* REVIEWED: GuiSliderPro(), control value change check
+* REVIEWED: GuiGrid(), simplified implementation
+* REVIEWED: GuiIconText(), increase buffer size and reviewed padding
+* REVIEWED: GuiDrawText(), improved wrap mode drawing
+* REVIEWED: GuiScrollBar(), minor tweaks
+* REVIEWED: GuiProgressBar(), improved borders computing
+* REVIEWED: GuiTextBox(), multiple improvements: autocursor and more
+* REVIEWED: Functions descriptions, removed wrong return value reference
+* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion
+*
+* 4.0 (12-Sep-2023) ADDED: GuiToggleSlider()
+* ADDED: GuiColorPickerHSV() and GuiColorPanelHSV()
+* ADDED: Multiple new icons, mostly compiler related
+* ADDED: New DEFAULT properties: TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE
+* ADDED: New enum values: GuiTextAlignment, GuiTextAlignmentVertical, GuiTextWrapMode
+* ADDED: Support loading styles with custom font charset from external file
+* REDESIGNED: GuiTextBox(), support mouse cursor positioning
+* REDESIGNED: GuiDrawText(), support multiline and word-wrap modes (read only)
+* REDESIGNED: GuiProgressBar() to be more visual, progress affects border color
+* REDESIGNED: Global alpha consideration moved to GuiDrawRectangle() and GuiDrawText()
+* REDESIGNED: GuiScrollPanel(), get parameters by reference and return result value
+* REDESIGNED: GuiToggleGroup(), get parameters by reference and return result value
+* REDESIGNED: GuiComboBox(), get parameters by reference and return result value
+* REDESIGNED: GuiCheckBox(), get parameters by reference and return result value
+* REDESIGNED: GuiSlider(), get parameters by reference and return result value
+* REDESIGNED: GuiSliderBar(), get parameters by reference and return result value
+* REDESIGNED: GuiProgressBar(), get parameters by reference and return result value
+* REDESIGNED: GuiListView(), get parameters by reference and return result value
+* REDESIGNED: GuiColorPicker(), get parameters by reference and return result value
+* REDESIGNED: GuiColorPanel(), get parameters by reference and return result value
+* REDESIGNED: GuiColorBarAlpha(), get parameters by reference and return result value
+* REDESIGNED: GuiColorBarHue(), get parameters by reference and return result value
+* REDESIGNED: GuiGrid(), get parameters by reference and return result value
+* REDESIGNED: GuiGrid(), added extra parameter
+* REDESIGNED: GuiListViewEx(), change parameters order
+* REDESIGNED: All controls return result as int value
+* REVIEWED: GuiScrollPanel() to avoid smallish scroll-bars
+* REVIEWED: All examples and specially controls_test_suite
+* RENAMED: gui_file_dialog module to gui_window_file_dialog
+* UPDATED: All styles to include ISO-8859-15 charset (as much as possible)
+*
+* 3.6 (10-May-2023) ADDED: New icon: SAND_TIMER
+* ADDED: GuiLoadStyleFromMemory() (binary only)
+* REVIEWED: GuiScrollBar() horizontal movement key
+* REVIEWED: GuiTextBox() crash on cursor movement
+* REVIEWED: GuiTextBox(), additional inputs support
+* REVIEWED: GuiLabelButton(), avoid text cut
+* REVIEWED: GuiTextInputBox(), password input
+* REVIEWED: Local GetCodepointNext(), aligned with raylib
+* REDESIGNED: GuiSlider*()/GuiScrollBar() to support out-of-bounds
+*
+* 3.5 (20-Apr-2023) ADDED: GuiTabBar(), based on GuiToggle()
+* ADDED: Helper functions to split text in separate lines
+* ADDED: Multiple new icons, useful for code editing tools
+* REMOVED: Unneeded icon editing functions
+* REMOVED: GuiTextBoxMulti(), very limited and broken
+* REMOVED: MeasureTextEx() dependency, logic directly implemented
+* REMOVED: DrawTextEx() dependency, logic directly implemented
+* REVIEWED: GuiScrollBar(), improve mouse-click behaviour
+* REVIEWED: Library header info, more info, better organized
+* REDESIGNED: GuiTextBox() to support cursor movement
+* REDESIGNED: GuiDrawText() to divide drawing by lines
+*
+* 3.2 (22-May-2022) RENAMED: Some enum values, for unification, avoiding prefixes
+* REMOVED: GuiScrollBar(), only internal
+* REDESIGNED: GuiPanel() to support text parameter
+* REDESIGNED: GuiScrollPanel() to support text parameter
+* REDESIGNED: GuiColorPicker() to support text parameter
+* REDESIGNED: GuiColorPanel() to support text parameter
+* REDESIGNED: GuiColorBarAlpha() to support text parameter
+* REDESIGNED: GuiColorBarHue() to support text parameter
+* REDESIGNED: GuiTextInputBox() to support password
+*
+* 3.1 (12-Jan-2022) REVIEWED: Default style for consistency (aligned with rGuiLayout v2.5 tool)
+* REVIEWED: GuiLoadStyle() to support compressed font atlas image data and unload previous textures
+* REVIEWED: External icons usage logic
+* REVIEWED: GuiLine() for centered alignment when including text
+* RENAMED: Multiple controls properties definitions to prepend RAYGUI_
+* RENAMED: RICON_ references to RAYGUI_ICON_ for library consistency
+* Projects updated and multiple tweaks
+*
+* 3.0 (04-Nov-2021) Integrated ricons data to avoid external file
+* REDESIGNED: GuiTextBoxMulti()
+* REMOVED: GuiImageButton*()
+* Multiple minor tweaks and bugs corrected
+*
+* 2.9 (17-Mar-2021) REMOVED: Tooltip API
+* 2.8 (03-May-2020) Centralized rectangles drawing to GuiDrawRectangle()
+* 2.7 (20-Feb-2020) ADDED: Possible tooltips API
+* 2.6 (09-Sep-2019) ADDED: GuiTextInputBox()
+* REDESIGNED: GuiListView*(), GuiDropdownBox(), GuiSlider*(), GuiProgressBar(), GuiMessageBox()
+* REVIEWED: GuiTextBox(), GuiSpinner(), GuiValueBox(), GuiLoadStyle()
+* Replaced property INNER_PADDING by TEXT_PADDING, renamed some properties
+* ADDED: 8 new custom styles ready to use
+* Multiple minor tweaks and bugs corrected
+*
+* 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner()
+* 2.3 (29-Apr-2019) ADDED: rIcons auxiliar library and support for it, multiple controls reviewed
+* Refactor all controls drawing mechanism to use control state
+* 2.2 (05-Feb-2019) ADDED: GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed Gui*Ex() controls
+* 2.1 (26-Dec-2018) REDESIGNED: GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string
+* REDESIGNED: Style system (breaking change)
+* 2.0 (08-Nov-2018) ADDED: Support controls guiLock and custom fonts
+* REVIEWED: GuiComboBox(), GuiListView()...
+* 1.9 (09-Oct-2018) REVIEWED: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()...
+* 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout
+* 1.5 (21-Jun-2017) Working in an improved styles system
+* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones)
+* 1.3 (12-Jun-2017) Complete redesign of style system
+* 1.1 (01-Jun-2017) Complete review of the library
+* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria
+* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria
+* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria
+*
+* DEPENDENCIES:
+* raylib 5.6-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing
+*
+* STANDALONE MODE:
+* By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled
+* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs
+*
+* The following functions should be redefined for a custom backend:
+*
+* - Vector2 GetMousePosition(void);
+* - float GetMouseWheelMove(void);
+* - bool IsMouseButtonDown(int button);
+* - bool IsMouseButtonPressed(int button);
+* - bool IsMouseButtonReleased(int button);
+* - bool IsKeyDown(int key);
+* - bool IsKeyPressed(int key);
+* - int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox()
+*
+* - void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle()
+* - void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker()
+*
+* - Font GetFontDefault(void); // -- GuiLoadStyleDefault()
+* - Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle()
+* - Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image
+* - void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization)
+* - char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data
+* - void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data
+* - const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs
+* - int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list
+* - void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list
+* - unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle()
+*
+* CONTRIBUTORS:
+* Ramon Santamaria: Supervision, review, redesign, update and maintenance
+* Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019)
+* Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018)
+* Adria Arranz: Testing and implementation of additional controls (2018)
+* Jordi Jorba: Testing and implementation of additional controls (2018)
+* Albert Martos: Review and testing of the library (2015)
+* Ian Eito: Review and testing of the library (2015)
+* Kevin Gato: Initial implementation of basic components (2014)
+* Daniel Nicolas: Initial implementation of basic components (2014)
+*
+*
+* 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 RAYGUI_H
+#define RAYGUI_H
+
+#define RAYGUI_VERSION_MAJOR 4
+#define RAYGUI_VERSION_MINOR 5
+#define RAYGUI_VERSION_PATCH 0
+#define RAYGUI_VERSION "5.0-dev"
+
+#if !defined(RAYGUI_STANDALONE)
+ #include "raylib.h"
+#endif
+
+// 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)
+ #define RAYGUIAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
+ #elif defined(USE_LIBTYPE_SHARED)
+ #define RAYGUIAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
+ #endif
+#endif
+
+// Function specifiers definition
+#ifndef RAYGUIAPI
+ #define RAYGUIAPI // Functions defined as 'extern' by default (implicit specifiers)
+#endif
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+// Simple log system to avoid printf() calls if required
+// NOTE: Avoiding those calls, also avoids const strings memory usage
+#define RAYGUI_SUPPORT_LOG_INFO
+#if defined(RAYGUI_SUPPORT_LOG_INFO)
+ #define RAYGUI_LOG(...) printf(__VA_ARGS__)
+#else
+ #define RAYGUI_LOG(...)
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+// NOTE: Some types are required for RAYGUI_STANDALONE usage
+//----------------------------------------------------------------------------------
+#if defined(RAYGUI_STANDALONE)
+ #ifndef __cplusplus
+ // Boolean type
+ #ifndef true
+ typedef enum { false, true } bool;
+ #endif
+ #endif
+
+ // Vector2 type
+ typedef struct Vector2 {
+ float x;
+ float y;
+ } Vector2;
+
+ // Vector3 type // -- ConvertHSVtoRGB(), ConvertRGBtoHSV()
+ typedef struct Vector3 {
+ float x;
+ float y;
+ float z;
+ } Vector3;
+
+ // Color type, RGBA (32bit)
+ typedef struct Color {
+ unsigned char r;
+ unsigned char g;
+ unsigned char b;
+ unsigned char a;
+ } Color;
+
+ // Rectangle type
+ typedef struct Rectangle {
+ float x;
+ float y;
+ float width;
+ float height;
+ } Rectangle;
+
+ // TODO: Texture2D type is very coupled to raylib, required by Font type
+ // It should be redesigned to be provided by user
+ typedef struct Texture {
+ unsigned int id; // OpenGL texture id
+ int width; // Texture base width
+ int height; // Texture base height
+ int mipmaps; // Mipmap levels, 1 by default
+ int format; // Data format (PixelFormat type)
+ } Texture;
+
+ // Texture2D, same as Texture
+ typedef Texture Texture2D;
+
+ // Image, pixel data stored in CPU memory (RAM)
+ typedef struct Image {
+ void *data; // Image raw data
+ int width; // Image base width
+ int height; // Image base height
+ int mipmaps; // Mipmap levels, 1 by default
+ int format; // Data format (PixelFormat type)
+ } Image;
+
+ // GlyphInfo, font characters glyphs info
+ typedef struct GlyphInfo {
+ int value; // Character value (Unicode)
+ int offsetX; // Character offset X when drawing
+ int offsetY; // Character offset Y when drawing
+ int advanceX; // Character advance position X
+ Image image; // Character image data
+ } GlyphInfo;
+
+ // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle()
+ // It should be redesigned to be provided by user
+ typedef struct Font {
+ int baseSize; // Base size (default chars height)
+ int glyphCount; // Number of glyph characters
+ int glyphPadding; // Padding around the glyph characters
+ Texture2D texture; // Texture atlas containing the glyphs
+ Rectangle *recs; // Rectangles in texture for the glyphs
+ GlyphInfo *glyphs; // Glyphs info data
+ } Font;
+#endif
+
+// Style property
+// NOTE: Used when exporting style as code for convenience
+typedef struct GuiStyleProp {
+ unsigned short controlId; // Control identifier
+ unsigned short propertyId; // Property identifier
+ int propertyValue; // Property value
+} GuiStyleProp;
+
+/*
+// Controls text style -NOT USED-
+// NOTE: Text style is defined by control
+typedef struct GuiTextStyle {
+ unsigned int size;
+ int charSpacing;
+ int lineSpacing;
+ int alignmentH;
+ int alignmentV;
+ int padding;
+} GuiTextStyle;
+*/
+
+// Gui control state
+typedef enum {
+ STATE_NORMAL = 0,
+ STATE_FOCUSED,
+ STATE_PRESSED,
+ STATE_DISABLED
+} GuiState;
+
+// Gui control text alignment
+typedef enum {
+ TEXT_ALIGN_LEFT = 0,
+ TEXT_ALIGN_CENTER,
+ TEXT_ALIGN_RIGHT
+} GuiTextAlignment;
+
+// Gui control text alignment vertical
+// NOTE: Text vertical position inside the text bounds
+typedef enum {
+ TEXT_ALIGN_TOP = 0,
+ TEXT_ALIGN_MIDDLE,
+ TEXT_ALIGN_BOTTOM
+} GuiTextAlignmentVertical;
+
+// Gui control text wrap mode
+// NOTE: Useful for multiline text
+typedef enum {
+ TEXT_WRAP_NONE = 0,
+ TEXT_WRAP_CHAR,
+ TEXT_WRAP_WORD
+} GuiTextWrapMode;
+
+// Gui controls
+typedef enum {
+ // Default -> populates to all controls when set
+ DEFAULT = 0,
+
+ // Basic controls
+ LABEL, // Used also for: LABELBUTTON
+ BUTTON,
+ TOGGLE, // Used also for: TOGGLEGROUP
+ SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER
+ PROGRESSBAR,
+ CHECKBOX,
+ COMBOBOX,
+ DROPDOWNBOX,
+ TEXTBOX, // Used also for: TEXTBOXMULTI
+ VALUEBOX,
+ CONTROL11,
+ LISTVIEW,
+ COLORPICKER,
+ SCROLLBAR,
+ STATUSBAR
+} GuiControl;
+
+// Gui base properties for every control
+// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties)
+typedef enum {
+ BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL
+ BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL
+ TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL
+ BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED
+ BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED
+ TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED
+ BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED
+ BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED
+ TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED
+ BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED
+ BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED
+ TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED
+ BORDER_WIDTH = 12, // Control border size, 0 for no border
+ //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls
+ //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls
+ //TEXT_LINE_SPACING, // Control text spacing between lines -> GLOBAL for all controls
+ TEXT_PADDING = 13, // Control text padding, not considering border
+ TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding)
+ //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls
+} GuiControlProperty;
+
+// TODO: Which text styling properties should be global or per-control?
+// At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while
+// TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and
+// should be configured by user as needed while defining the UI layout
+
+// Gui extended properties depend on control
+// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties)
+//----------------------------------------------------------------------------------
+// DEFAULT extended properties
+// NOTE: Those properties are common to all controls or global
+// WARNING: We only have 8 slots for those properties by default!!! -> New global control: TEXT?
+typedef enum {
+ TEXT_SIZE = 16, // Text size (glyphs max height)
+ TEXT_SPACING, // Text spacing between glyphs
+ LINE_COLOR, // Line control color
+ BACKGROUND_COLOR, // Background color
+ TEXT_LINE_SPACING, // Text spacing between lines
+ TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding)
+ TEXT_WRAP_MODE // Text wrap-mode inside text bounds
+ //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline
+ //TEXT_DECORATION_THICK // Text decoration line thickness
+} GuiDefaultProperty;
+
+// Other possible text properties:
+// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change
+// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING...
+
+// Label
+//typedef enum { } GuiLabelProperty;
+
+// Button/Spinner
+//typedef enum { } GuiButtonProperty;
+
+// Toggle/ToggleGroup
+typedef enum {
+ GROUP_PADDING = 16, // ToggleGroup separation between toggles
+} GuiToggleProperty;
+
+// Slider/SliderBar
+typedef enum {
+ SLIDER_WIDTH = 16, // Slider size of internal bar
+ SLIDER_PADDING // Slider/SliderBar internal bar padding
+} GuiSliderProperty;
+
+// ProgressBar
+typedef enum {
+ PROGRESS_PADDING = 16, // ProgressBar internal padding
+} GuiProgressBarProperty;
+
+// ScrollBar
+typedef enum {
+ ARROWS_SIZE = 16, // ScrollBar arrows size
+ ARROWS_VISIBLE, // ScrollBar arrows visible
+ SCROLL_SLIDER_PADDING, // ScrollBar slider internal padding
+ SCROLL_SLIDER_SIZE, // ScrollBar slider size
+ SCROLL_PADDING, // ScrollBar scroll padding from arrows
+ SCROLL_SPEED, // ScrollBar scrolling speed
+} GuiScrollBarProperty;
+
+// CheckBox
+typedef enum {
+ CHECK_PADDING = 16 // CheckBox internal check padding
+} GuiCheckBoxProperty;
+
+// ComboBox
+typedef enum {
+ COMBO_BUTTON_WIDTH = 16, // ComboBox right button width
+ COMBO_BUTTON_SPACING // ComboBox button separation
+} GuiComboBoxProperty;
+
+// DropdownBox
+typedef enum {
+ ARROW_PADDING = 16, // DropdownBox arrow separation from border and items
+ DROPDOWN_ITEMS_SPACING, // DropdownBox items separation
+ DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden
+ DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down)
+} GuiDropdownBoxProperty;
+
+// TextBox/TextBoxMulti/ValueBox/Spinner
+typedef enum {
+ TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable
+} GuiTextBoxProperty;
+
+// ValueBox/Spinner
+typedef enum {
+ SPINNER_BUTTON_WIDTH = 16, // Spinner left/right buttons width
+ SPINNER_BUTTON_SPACING, // Spinner buttons separation
+} GuiValueBoxProperty;
+
+// Control11
+//typedef enum { } GuiControl11Property;
+
+// ListView
+typedef enum {
+ LIST_ITEMS_HEIGHT = 16, // ListView items height
+ LIST_ITEMS_SPACING, // ListView items separation
+ SCROLLBAR_WIDTH, // ListView scrollbar size (usually width)
+ SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE)
+ LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state
+ LIST_ITEMS_BORDER_WIDTH // ListView items border width
+} GuiListViewProperty;
+
+// ColorPicker
+typedef enum {
+ COLOR_SELECTOR_SIZE = 16,
+ HUEBAR_WIDTH, // ColorPicker right hue bar width
+ HUEBAR_PADDING, // ColorPicker right hue bar separation from panel
+ HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height
+ HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow
+} GuiColorPickerProperty;
+
+#define SCROLLBAR_LEFT_SIDE 0
+#define SCROLLBAR_RIGHT_SIDE 1
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+// ...
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+
+#if defined(__cplusplus)
+extern "C" { // Prevents name mangling of functions
+#endif
+
+// Global gui state control functions
+RAYGUIAPI void GuiEnable(void); // Enable gui controls (global state)
+RAYGUIAPI void GuiDisable(void); // Disable gui controls (global state)
+RAYGUIAPI void GuiLock(void); // Lock gui controls (global state)
+RAYGUIAPI void GuiUnlock(void); // Unlock gui controls (global state)
+RAYGUIAPI bool GuiIsLocked(void); // Check if gui is locked (global state)
+RAYGUIAPI void GuiSetAlpha(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f
+RAYGUIAPI void GuiSetState(int state); // Set gui state (global state)
+RAYGUIAPI int GuiGetState(void); // Get gui state (global state)
+
+// Font set/get functions
+RAYGUIAPI void GuiSetFont(Font font); // Set gui custom font (global state)
+RAYGUIAPI Font GuiGetFont(void); // Get gui custom font (global state)
+
+// Style set/get functions
+RAYGUIAPI void GuiSetStyle(int control, int property, int value); // Set one style property
+RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style property
+
+// Styles loading functions
+RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs)
+RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style
+
+// Tooltips management functions
+RAYGUIAPI void GuiEnableTooltip(void); // Enable gui tooltips (global state)
+RAYGUIAPI void GuiDisableTooltip(void); // Disable gui tooltips (global state)
+RAYGUIAPI void GuiSetTooltip(const char *tooltip); // Set tooltip string
+
+// Icons functionality
+RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended (if supported)
+#if !defined(RAYGUI_NO_ICONS)
+RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size
+RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer
+RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data
+RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position
+#endif
+
+// Utility functions
+RAYGUIAPI int GuiGetTextWidth(const char *text); // Get text width considering gui style and icon size (if required)
+
+// Controls
+//----------------------------------------------------------------------------------------------------------
+// Container/separator controls, useful for controls organization
+RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); // Window Box control, shows a window that can be closed
+RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name
+RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text
+RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls
+RAYGUIAPI int GuiTabBar(Rectangle bounds, const char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1
+RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control
+
+// Basic controls set
+RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control
+RAYGUIAPI int GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked
+RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, returns true when clicked
+RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control
+RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control
+RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control
+RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked); // Check Box control, returns true when active
+RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control
+
+RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control
+RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control
+RAYGUIAPI int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers
+RAYGUIAPI int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode); // Value box control for float values
+RAYGUIAPI int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text
+
+RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control
+RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control
+RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control
+RAYGUIAPI int GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text
+RAYGUIAPI int GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders
+RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control
+
+// Advance controls set
+RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control
+RAYGUIAPI int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters
+RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message
+RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret
+RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls)
+RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control
+RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control
+RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control
+RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls)
+RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV()
+//----------------------------------------------------------------------------------------------------------
+
+#if !defined(RAYGUI_NO_ICONS)
+
+#if !defined(RAYGUI_CUSTOM_ICONS)
+//----------------------------------------------------------------------------------
+// Icons enumeration
+//----------------------------------------------------------------------------------
+typedef enum {
+ ICON_NONE = 0,
+ ICON_FOLDER_FILE_OPEN = 1,
+ ICON_FILE_SAVE_CLASSIC = 2,
+ ICON_FOLDER_OPEN = 3,
+ ICON_FOLDER_SAVE = 4,
+ ICON_FILE_OPEN = 5,
+ ICON_FILE_SAVE = 6,
+ ICON_FILE_EXPORT = 7,
+ ICON_FILE_ADD = 8,
+ ICON_FILE_DELETE = 9,
+ ICON_FILETYPE_TEXT = 10,
+ ICON_FILETYPE_AUDIO = 11,
+ ICON_FILETYPE_IMAGE = 12,
+ ICON_FILETYPE_PLAY = 13,
+ ICON_FILETYPE_VIDEO = 14,
+ ICON_FILETYPE_INFO = 15,
+ ICON_FILE_COPY = 16,
+ ICON_FILE_CUT = 17,
+ ICON_FILE_PASTE = 18,
+ ICON_CURSOR_HAND = 19,
+ ICON_CURSOR_POINTER = 20,
+ ICON_CURSOR_CLASSIC = 21,
+ ICON_PENCIL = 22,
+ ICON_PENCIL_BIG = 23,
+ ICON_BRUSH_CLASSIC = 24,
+ ICON_BRUSH_PAINTER = 25,
+ ICON_WATER_DROP = 26,
+ ICON_COLOR_PICKER = 27,
+ ICON_RUBBER = 28,
+ ICON_COLOR_BUCKET = 29,
+ ICON_TEXT_T = 30,
+ ICON_TEXT_A = 31,
+ ICON_SCALE = 32,
+ ICON_RESIZE = 33,
+ ICON_FILTER_POINT = 34,
+ ICON_FILTER_BILINEAR = 35,
+ ICON_CROP = 36,
+ ICON_CROP_ALPHA = 37,
+ ICON_SQUARE_TOGGLE = 38,
+ ICON_SYMMETRY = 39,
+ ICON_SYMMETRY_HORIZONTAL = 40,
+ ICON_SYMMETRY_VERTICAL = 41,
+ ICON_LENS = 42,
+ ICON_LENS_BIG = 43,
+ ICON_EYE_ON = 44,
+ ICON_EYE_OFF = 45,
+ ICON_FILTER_TOP = 46,
+ ICON_FILTER = 47,
+ ICON_TARGET_POINT = 48,
+ ICON_TARGET_SMALL = 49,
+ ICON_TARGET_BIG = 50,
+ ICON_TARGET_MOVE = 51,
+ ICON_CURSOR_MOVE = 52,
+ ICON_CURSOR_SCALE = 53,
+ ICON_CURSOR_SCALE_RIGHT = 54,
+ ICON_CURSOR_SCALE_LEFT = 55,
+ ICON_UNDO = 56,
+ ICON_REDO = 57,
+ ICON_REREDO = 58,
+ ICON_MUTATE = 59,
+ ICON_ROTATE = 60,
+ ICON_REPEAT = 61,
+ ICON_SHUFFLE = 62,
+ ICON_EMPTYBOX = 63,
+ ICON_TARGET = 64,
+ ICON_TARGET_SMALL_FILL = 65,
+ ICON_TARGET_BIG_FILL = 66,
+ ICON_TARGET_MOVE_FILL = 67,
+ ICON_CURSOR_MOVE_FILL = 68,
+ ICON_CURSOR_SCALE_FILL = 69,
+ ICON_CURSOR_SCALE_RIGHT_FILL = 70,
+ ICON_CURSOR_SCALE_LEFT_FILL = 71,
+ ICON_UNDO_FILL = 72,
+ ICON_REDO_FILL = 73,
+ ICON_REREDO_FILL = 74,
+ ICON_MUTATE_FILL = 75,
+ ICON_ROTATE_FILL = 76,
+ ICON_REPEAT_FILL = 77,
+ ICON_SHUFFLE_FILL = 78,
+ ICON_EMPTYBOX_SMALL = 79,
+ ICON_BOX = 80,
+ ICON_BOX_TOP = 81,
+ ICON_BOX_TOP_RIGHT = 82,
+ ICON_BOX_RIGHT = 83,
+ ICON_BOX_BOTTOM_RIGHT = 84,
+ ICON_BOX_BOTTOM = 85,
+ ICON_BOX_BOTTOM_LEFT = 86,
+ ICON_BOX_LEFT = 87,
+ ICON_BOX_TOP_LEFT = 88,
+ ICON_BOX_CENTER = 89,
+ ICON_BOX_CIRCLE_MASK = 90,
+ ICON_POT = 91,
+ ICON_ALPHA_MULTIPLY = 92,
+ ICON_ALPHA_CLEAR = 93,
+ ICON_DITHERING = 94,
+ ICON_MIPMAPS = 95,
+ ICON_BOX_GRID = 96,
+ ICON_GRID = 97,
+ ICON_BOX_CORNERS_SMALL = 98,
+ ICON_BOX_CORNERS_BIG = 99,
+ ICON_FOUR_BOXES = 100,
+ ICON_GRID_FILL = 101,
+ ICON_BOX_MULTISIZE = 102,
+ ICON_ZOOM_SMALL = 103,
+ ICON_ZOOM_MEDIUM = 104,
+ ICON_ZOOM_BIG = 105,
+ ICON_ZOOM_ALL = 106,
+ ICON_ZOOM_CENTER = 107,
+ ICON_BOX_DOTS_SMALL = 108,
+ ICON_BOX_DOTS_BIG = 109,
+ ICON_BOX_CONCENTRIC = 110,
+ ICON_BOX_GRID_BIG = 111,
+ ICON_OK_TICK = 112,
+ ICON_CROSS = 113,
+ ICON_ARROW_LEFT = 114,
+ ICON_ARROW_RIGHT = 115,
+ ICON_ARROW_DOWN = 116,
+ ICON_ARROW_UP = 117,
+ ICON_ARROW_LEFT_FILL = 118,
+ ICON_ARROW_RIGHT_FILL = 119,
+ ICON_ARROW_DOWN_FILL = 120,
+ ICON_ARROW_UP_FILL = 121,
+ ICON_AUDIO = 122,
+ ICON_FX = 123,
+ ICON_WAVE = 124,
+ ICON_WAVE_SINUS = 125,
+ ICON_WAVE_SQUARE = 126,
+ ICON_WAVE_TRIANGULAR = 127,
+ ICON_CROSS_SMALL = 128,
+ ICON_PLAYER_PREVIOUS = 129,
+ ICON_PLAYER_PLAY_BACK = 130,
+ ICON_PLAYER_PLAY = 131,
+ ICON_PLAYER_PAUSE = 132,
+ ICON_PLAYER_STOP = 133,
+ ICON_PLAYER_NEXT = 134,
+ ICON_PLAYER_RECORD = 135,
+ ICON_MAGNET = 136,
+ ICON_LOCK_CLOSE = 137,
+ ICON_LOCK_OPEN = 138,
+ ICON_CLOCK = 139,
+ ICON_TOOLS = 140,
+ ICON_GEAR = 141,
+ ICON_GEAR_BIG = 142,
+ ICON_BIN = 143,
+ ICON_HAND_POINTER = 144,
+ ICON_LASER = 145,
+ ICON_COIN = 146,
+ ICON_EXPLOSION = 147,
+ ICON_1UP = 148,
+ ICON_PLAYER = 149,
+ ICON_PLAYER_JUMP = 150,
+ ICON_KEY = 151,
+ ICON_DEMON = 152,
+ ICON_TEXT_POPUP = 153,
+ ICON_GEAR_EX = 154,
+ ICON_CRACK = 155,
+ ICON_CRACK_POINTS = 156,
+ ICON_STAR = 157,
+ ICON_DOOR = 158,
+ ICON_EXIT = 159,
+ ICON_MODE_2D = 160,
+ ICON_MODE_3D = 161,
+ ICON_CUBE = 162,
+ ICON_CUBE_FACE_TOP = 163,
+ ICON_CUBE_FACE_LEFT = 164,
+ ICON_CUBE_FACE_FRONT = 165,
+ ICON_CUBE_FACE_BOTTOM = 166,
+ ICON_CUBE_FACE_RIGHT = 167,
+ ICON_CUBE_FACE_BACK = 168,
+ ICON_CAMERA = 169,
+ ICON_SPECIAL = 170,
+ ICON_LINK_NET = 171,
+ ICON_LINK_BOXES = 172,
+ ICON_LINK_MULTI = 173,
+ ICON_LINK = 174,
+ ICON_LINK_BROKE = 175,
+ ICON_TEXT_NOTES = 176,
+ ICON_NOTEBOOK = 177,
+ ICON_SUITCASE = 178,
+ ICON_SUITCASE_ZIP = 179,
+ ICON_MAILBOX = 180,
+ ICON_MONITOR = 181,
+ ICON_PRINTER = 182,
+ ICON_PHOTO_CAMERA = 183,
+ ICON_PHOTO_CAMERA_FLASH = 184,
+ ICON_HOUSE = 185,
+ ICON_HEART = 186,
+ ICON_CORNER = 187,
+ ICON_VERTICAL_BARS = 188,
+ ICON_VERTICAL_BARS_FILL = 189,
+ ICON_LIFE_BARS = 190,
+ ICON_INFO = 191,
+ ICON_CROSSLINE = 192,
+ ICON_HELP = 193,
+ ICON_FILETYPE_ALPHA = 194,
+ ICON_FILETYPE_HOME = 195,
+ ICON_LAYERS_VISIBLE = 196,
+ ICON_LAYERS = 197,
+ ICON_WINDOW = 198,
+ ICON_HIDPI = 199,
+ ICON_FILETYPE_BINARY = 200,
+ ICON_HEX = 201,
+ ICON_SHIELD = 202,
+ ICON_FILE_NEW = 203,
+ ICON_FOLDER_ADD = 204,
+ ICON_ALARM = 205,
+ ICON_CPU = 206,
+ ICON_ROM = 207,
+ ICON_STEP_OVER = 208,
+ ICON_STEP_INTO = 209,
+ ICON_STEP_OUT = 210,
+ ICON_RESTART = 211,
+ ICON_BREAKPOINT_ON = 212,
+ ICON_BREAKPOINT_OFF = 213,
+ ICON_BURGER_MENU = 214,
+ ICON_CASE_SENSITIVE = 215,
+ ICON_REG_EXP = 216,
+ ICON_FOLDER = 217,
+ ICON_FILE = 218,
+ ICON_SAND_TIMER = 219,
+ ICON_WARNING = 220,
+ ICON_HELP_BOX = 221,
+ ICON_INFO_BOX = 222,
+ ICON_PRIORITY = 223,
+ ICON_LAYERS_ISO = 224,
+ ICON_LAYERS2 = 225,
+ ICON_MLAYERS = 226,
+ ICON_MAPS = 227,
+ ICON_HOT = 228,
+ ICON_LABEL = 229,
+ ICON_NAME_ID = 230,
+ ICON_SLICING = 231,
+ ICON_MANUAL_CONTROL = 232,
+ ICON_COLLISION = 233,
+ ICON_CIRCLE_ADD = 234,
+ ICON_CIRCLE_ADD_FILL = 235,
+ ICON_CIRCLE_WARNING = 236,
+ ICON_CIRCLE_WARNING_FILL = 237,
+ ICON_BOX_MORE = 238,
+ ICON_BOX_MORE_FILL = 239,
+ ICON_BOX_MINUS = 240,
+ ICON_BOX_MINUS_FILL = 241,
+ ICON_UNION = 242,
+ ICON_INTERSECTION = 243,
+ ICON_DIFFERENCE = 244,
+ ICON_SPHERE = 245,
+ ICON_CYLINDER = 246,
+ ICON_CONE = 247,
+ ICON_ELLIPSOID = 248,
+ ICON_CAPSULE = 249,
+ ICON_250 = 250,
+ ICON_251 = 251,
+ ICON_252 = 252,
+ ICON_253 = 253,
+ ICON_254 = 254,
+ ICON_255 = 255
+} GuiIconName;
+#endif
+
+#endif
+
+#if defined(__cplusplus)
+} // Prevents name mangling of functions
+#endif
+
+#endif // RAYGUI_H
+
+/***********************************************************************************
+*
+* RAYGUI IMPLEMENTATION
+*
+************************************************************************************/
+
+#if defined(RAYGUI_IMPLEMENTATION)
+
+#include // required for: isspace() [GuiTextBox()]
+#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
+#include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include // Required for: roundf() [GuiColorPicker()]
+
+// Allow custom memory allocators
+#if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE)
+ #if !defined(RAYGUI_MALLOC) || !defined(RAYGUI_CALLOC) || !defined(RAYGUI_FREE)
+ #error "RAYGUI: if RAYGUI_MALLOC, RAYGUI_CALLOC, or RAYGUI_FREE is customized, all three must be customized"
+ #endif
+#else
+ #include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()]
+
+ #define RAYGUI_MALLOC(sz) malloc(sz)
+ #define RAYGUI_CALLOC(n,sz) calloc(n,sz)
+ #define RAYGUI_FREE(p) free(p)
+#endif
+
+#ifdef __cplusplus
+ #define RAYGUI_CLITERAL(name) name
+#else
+ #define RAYGUI_CLITERAL(name) (name)
+#endif
+
+// Check if two rectangles are equal, used to validate a slider bounds as an id
+#ifndef CHECK_BOUNDS_ID
+ #define CHECK_BOUNDS_ID(src, dst) (((int)src.x == (int)dst.x) && ((int)src.y == (int)dst.y) && ((int)src.width == (int)dst.width) && ((int)src.height == (int)dst.height))
+#endif
+
+#if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS)
+
+// Embedded icons, no external file provided
+#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared)
+#define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons
+#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id
+
+// Icons data is defined by bit array (every bit represents one pixel)
+// Those arrays are stored as unsigned int data arrays, so,
+// every array element defines 32 pixels (bits) of information
+// One icon is defined by 8 int, (8 int * 32 bit = 256 bit = 16*16 pixels)
+// NOTE: Number of elemens depend on RAYGUI_ICON_SIZE (by default 16x16 pixels)
+#define RAYGUI_ICON_DATA_ELEMENTS (RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32)
+
+//----------------------------------------------------------------------------------
+// Icons data for all gui possible icons (allocated on data segment by default)
+//
+// NOTE 1: Every icon is codified in binary form, using 1 bit per pixel, so,
+// every 16x16 icon requires 8 integers (16*16/32) to be stored
+//
+// NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(),
+// but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS
+//
+// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB
+//----------------------------------------------------------------------------------
+static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE
+ 0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // ICON_FOLDER_FILE_OPEN
+ 0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // ICON_FILE_SAVE_CLASSIC
+ 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // ICON_FOLDER_OPEN
+ 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // ICON_FOLDER_SAVE
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // ICON_FILE_OPEN
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // ICON_FILE_SAVE
+ 0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // ICON_FILE_EXPORT
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // ICON_FILE_ADD
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // ICON_FILE_DELETE
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_FILETYPE_TEXT
+ 0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // ICON_FILETYPE_AUDIO
+ 0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // ICON_FILETYPE_IMAGE
+ 0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PLAY
+ 0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // ICON_FILETYPE_VIDEO
+ 0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // ICON_FILETYPE_INFO
+ 0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // ICON_FILE_COPY
+ 0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // ICON_FILE_CUT
+ 0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // ICON_FILE_PASTE
+ 0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_CURSOR_HAND
+ 0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // ICON_CURSOR_POINTER
+ 0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // ICON_CURSOR_CLASSIC
+ 0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // ICON_PENCIL
+ 0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // ICON_PENCIL_BIG
+ 0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // ICON_BRUSH_CLASSIC
+ 0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // ICON_BRUSH_PAINTER
+ 0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // ICON_WATER_DROP
+ 0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // ICON_COLOR_PICKER
+ 0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // ICON_RUBBER
+ 0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // ICON_COLOR_BUCKET
+ 0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // ICON_TEXT_T
+ 0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // ICON_TEXT_A
+ 0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // ICON_SCALE
+ 0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // ICON_RESIZE
+ 0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_POINT
+ 0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_BILINEAR
+ 0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // ICON_CROP
+ 0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // ICON_CROP_ALPHA
+ 0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // ICON_SQUARE_TOGGLE
+ 0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // ICON_SYMMETRY
+ 0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // ICON_SYMMETRY_HORIZONTAL
+ 0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // ICON_SYMMETRY_VERTICAL
+ 0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // ICON_LENS
+ 0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // ICON_LENS_BIG
+ 0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // ICON_EYE_ON
+ 0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // ICON_EYE_OFF
+ 0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // ICON_FILTER_TOP
+ 0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // ICON_FILTER
+ 0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_POINT
+ 0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL
+ 0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG
+ 0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // ICON_TARGET_MOVE
+ 0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // ICON_CURSOR_MOVE
+ 0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // ICON_CURSOR_SCALE
+ 0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // ICON_CURSOR_SCALE_RIGHT
+ 0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // ICON_CURSOR_SCALE_LEFT
+ 0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO
+ 0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO
+ 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // ICON_REREDO
+ 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // ICON_MUTATE
+ 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // ICON_ROTATE
+ 0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // ICON_REPEAT
+ 0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // ICON_SHUFFLE
+ 0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // ICON_EMPTYBOX
+ 0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // ICON_TARGET
+ 0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL_FILL
+ 0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG_FILL
+ 0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // ICON_TARGET_MOVE_FILL
+ 0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // ICON_CURSOR_MOVE_FILL
+ 0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // ICON_CURSOR_SCALE_FILL
+ 0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // ICON_CURSOR_SCALE_RIGHT_FILL
+ 0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // ICON_CURSOR_SCALE_LEFT_FILL
+ 0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO_FILL
+ 0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO_FILL
+ 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // ICON_REREDO_FILL
+ 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // ICON_MUTATE_FILL
+ 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // ICON_ROTATE_FILL
+ 0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // ICON_REPEAT_FILL
+ 0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // ICON_SHUFFLE_FILL
+ 0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // ICON_EMPTYBOX_SMALL
+ 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX
+ 0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP
+ 0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_RIGHT
+ 0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_RIGHT
+ 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // ICON_BOX_BOTTOM_RIGHT
+ 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // ICON_BOX_BOTTOM
+ 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // ICON_BOX_BOTTOM_LEFT
+ 0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_LEFT
+ 0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_LEFT
+ 0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_CENTER
+ 0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // ICON_BOX_CIRCLE_MASK
+ 0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // ICON_POT
+ 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // ICON_ALPHA_MULTIPLY
+ 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // ICON_ALPHA_CLEAR
+ 0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // ICON_DITHERING
+ 0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // ICON_MIPMAPS
+ 0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // ICON_BOX_GRID
+ 0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // ICON_GRID
+ 0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // ICON_BOX_CORNERS_SMALL
+ 0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // ICON_BOX_CORNERS_BIG
+ 0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // ICON_FOUR_BOXES
+ 0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // ICON_GRID_FILL
+ 0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // ICON_BOX_MULTISIZE
+ 0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_SMALL
+ 0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_MEDIUM
+ 0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // ICON_ZOOM_BIG
+ 0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // ICON_ZOOM_ALL
+ 0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // ICON_ZOOM_CENTER
+ 0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // ICON_BOX_DOTS_SMALL
+ 0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // ICON_BOX_DOTS_BIG
+ 0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // ICON_BOX_CONCENTRIC
+ 0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // ICON_BOX_GRID_BIG
+ 0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // ICON_OK_TICK
+ 0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // ICON_CROSS
+ 0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // ICON_ARROW_LEFT
+ 0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // ICON_ARROW_RIGHT
+ 0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // ICON_ARROW_DOWN
+ 0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP
+ 0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // ICON_ARROW_LEFT_FILL
+ 0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // ICON_ARROW_RIGHT_FILL
+ 0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // ICON_ARROW_DOWN_FILL
+ 0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP_FILL
+ 0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // ICON_AUDIO
+ 0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // ICON_FX
+ 0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // ICON_WAVE
+ 0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // ICON_WAVE_SINUS
+ 0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // ICON_WAVE_SQUARE
+ 0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // ICON_WAVE_TRIANGULAR
+ 0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // ICON_CROSS_SMALL
+ 0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // ICON_PLAYER_PREVIOUS
+ 0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // ICON_PLAYER_PLAY_BACK
+ 0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // ICON_PLAYER_PLAY
+ 0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // ICON_PLAYER_PAUSE
+ 0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // ICON_PLAYER_STOP
+ 0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // ICON_PLAYER_NEXT
+ 0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // ICON_PLAYER_RECORD
+ 0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // ICON_MAGNET
+ 0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_CLOSE
+ 0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_OPEN
+ 0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // ICON_CLOCK
+ 0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // ICON_TOOLS
+ 0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // ICON_GEAR
+ 0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // ICON_GEAR_BIG
+ 0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // ICON_BIN
+ 0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // ICON_HAND_POINTER
+ 0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // ICON_LASER
+ 0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // ICON_COIN
+ 0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // ICON_EXPLOSION
+ 0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // ICON_1UP
+ 0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // ICON_PLAYER
+ 0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // ICON_PLAYER_JUMP
+ 0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // ICON_KEY
+ 0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // ICON_DEMON
+ 0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // ICON_TEXT_POPUP
+ 0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // ICON_GEAR_EX
+ 0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK
+ 0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK_POINTS
+ 0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // ICON_STAR
+ 0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // ICON_DOOR
+ 0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // ICON_EXIT
+ 0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // ICON_MODE_2D
+ 0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // ICON_MODE_3D
+ 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE
+ 0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_TOP
+ 0x7fe00000, 0x50386030, 0x47c2483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // ICON_CUBE_FACE_LEFT
+ 0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // ICON_CUBE_FACE_FRONT
+ 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3bf27be2, 0x0bfe1bfa, 0x000007fe, // ICON_CUBE_FACE_BOTTOM
+ 0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // ICON_CUBE_FACE_RIGHT
+ 0x7fe00000, 0x6fe85ff0, 0x781e77e4, 0x7be27be2, 0x7be27be2, 0x24127be2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_BACK
+ 0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // ICON_CAMERA
+ 0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // ICON_SPECIAL
+ 0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // ICON_LINK_NET
+ 0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // ICON_LINK_BOXES
+ 0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // ICON_LINK_MULTI
+ 0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // ICON_LINK
+ 0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // ICON_LINK_BROKE
+ 0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_TEXT_NOTES
+ 0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // ICON_NOTEBOOK
+ 0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // ICON_SUITCASE
+ 0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // ICON_SUITCASE_ZIP
+ 0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // ICON_MAILBOX
+ 0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // ICON_MONITOR
+ 0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // ICON_PRINTER
+ 0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA
+ 0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA_FLASH
+ 0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // ICON_HOUSE
+ 0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // ICON_HEART
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // ICON_CORNER
+ 0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // ICON_VERTICAL_BARS
+ 0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // ICON_VERTICAL_BARS_FILL
+ 0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // ICON_LIFE_BARS
+ 0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // ICON_INFO
+ 0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // ICON_CROSSLINE
+ 0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // ICON_HELP
+ 0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // ICON_FILETYPE_ALPHA
+ 0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // ICON_FILETYPE_HOME
+ 0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS_VISIBLE
+ 0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS
+ 0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_WINDOW
+ 0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // ICON_HIDPI
+ 0x3ff00000, 0x201c2010, 0x2a842e84, 0x2e842a84, 0x2ba42004, 0x2aa42aa4, 0x20042ba4, 0x00003ffc, // ICON_FILETYPE_BINARY
+ 0x00000000, 0x00000000, 0x00120012, 0x4a5e4bd2, 0x485233d2, 0x00004bd2, 0x00000000, 0x00000000, // ICON_HEX
+ 0x01800000, 0x381c0660, 0x23c42004, 0x23c42044, 0x13c82204, 0x08101008, 0x02400420, 0x00000180, // ICON_SHIELD
+ 0x007e0000, 0x20023fc2, 0x40227fe2, 0x400a403a, 0x400a400a, 0x400a400a, 0x4008400e, 0x00007ff8, // ICON_FILE_NEW
+ 0x00000000, 0x0042007e, 0x40027fc2, 0x44024002, 0x5f024402, 0x44024402, 0x7ffe4002, 0x00000000, // ICON_FOLDER_ADD
+ 0x44220000, 0x12482244, 0xf3cf0000, 0x14280420, 0x48122424, 0x08100810, 0x1ff81008, 0x03c00420, // ICON_ALARM
+ 0x0aa00000, 0x1ff80aa0, 0x1068700e, 0x1008706e, 0x1008700e, 0x1008700e, 0x0aa01ff8, 0x00000aa0, // ICON_CPU
+ 0x07e00000, 0x04201db8, 0x04a01c38, 0x04a01d38, 0x04a01d38, 0x04a01d38, 0x04201d38, 0x000007e0, // ICON_ROM
+ 0x00000000, 0x03c00000, 0x3c382ff0, 0x3c04380c, 0x01800000, 0x03c003c0, 0x00000180, 0x00000000, // ICON_STEP_OVER
+ 0x01800000, 0x01800180, 0x01800180, 0x03c007e0, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_INTO
+ 0x01800000, 0x07e003c0, 0x01800180, 0x01800180, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_OUT
+ 0x00000000, 0x0ff003c0, 0x181c1c34, 0x303c301c, 0x30003000, 0x1c301800, 0x03c00ff0, 0x00000000, // ICON_RESTART
+ 0x00000000, 0x00000000, 0x07e003c0, 0x0ff00ff0, 0x0ff00ff0, 0x03c007e0, 0x00000000, 0x00000000, // ICON_BREAKPOINT_ON
+ 0x00000000, 0x00000000, 0x042003c0, 0x08100810, 0x08100810, 0x03c00420, 0x00000000, 0x00000000, // ICON_BREAKPOINT_OFF
+ 0x00000000, 0x00000000, 0x1ff81ff8, 0x1ff80000, 0x00001ff8, 0x1ff81ff8, 0x00000000, 0x00000000, // ICON_BURGER_MENU
+ 0x00000000, 0x00000000, 0x00880070, 0x0c880088, 0x1e8810f8, 0x3e881288, 0x00000000, 0x00000000, // ICON_CASE_SENSITIVE
+ 0x00000000, 0x02000000, 0x07000a80, 0x07001fc0, 0x02000a80, 0x00300030, 0x00000000, 0x00000000, // ICON_REG_EXP
+ 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_FOLDER
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x00003ffc, // ICON_FILE
+ 0x1ff00000, 0x20082008, 0x17d02fe8, 0x05400ba0, 0x09200540, 0x23881010, 0x2fe827c8, 0x00001ff0, // ICON_SAND_TIMER
+ 0x01800000, 0x02400240, 0x05a00420, 0x09900990, 0x11881188, 0x21842004, 0x40024182, 0x00003ffc, // ICON_WARNING
+ 0x7ffe0000, 0x4ff24002, 0x4c324ff2, 0x4f824c02, 0x41824f82, 0x41824002, 0x40024182, 0x00007ffe, // ICON_HELP_BOX
+ 0x7ffe0000, 0x41824002, 0x40024182, 0x41824182, 0x41824182, 0x41824182, 0x40024182, 0x00007ffe, // ICON_INFO_BOX
+ 0x01800000, 0x04200240, 0x10080810, 0x7bde2004, 0x0a500a50, 0x08500bd0, 0x08100850, 0x00000ff0, // ICON_PRIORITY
+ 0x01800000, 0x18180660, 0x80016006, 0x98196006, 0x99996666, 0x19986666, 0x01800660, 0x00000000, // ICON_LAYERS_ISO
+ 0x07fe0000, 0x1c020402, 0x74021402, 0x54025402, 0x54025402, 0x500857fe, 0x40205ff8, 0x00007fe0, // ICON_LAYERS2
+ 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS
+ 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS
+ 0x04200000, 0x1cf00c60, 0x11f019f0, 0x0f3807b8, 0x1e3c0f3c, 0x1c1c1e1c, 0x1e3c1c1c, 0x00000f70, // ICON_HOT
+ 0x00000000, 0x20803f00, 0x2a202e40, 0x20082e10, 0x08021004, 0x02040402, 0x00900108, 0x00000060, // ICON_LABEL
+ 0x00000000, 0x042007e0, 0x47e27c3e, 0x4ffa4002, 0x47fa4002, 0x4ffa4002, 0x7ffe4002, 0x00000000, // ICON_NAME_ID
+ 0x7fe00000, 0x402e4020, 0x43ce5e0a, 0x40504078, 0x438e4078, 0x402e5e0a, 0x7fe04020, 0x00000000, // ICON_SLICING
+ 0x00000000, 0x40027ffe, 0x47c24002, 0x55425d42, 0x55725542, 0x50125552, 0x10105016, 0x00001ff0, // ICON_MANUAL_CONTROL
+ 0x7ffe0000, 0x43c24002, 0x48124422, 0x500a500a, 0x500a500a, 0x44224812, 0x400243c2, 0x00007ffe, // ICON_COLLISION
+ 0x03c00000, 0x10080c30, 0x21842184, 0x4ff24182, 0x41824ff2, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_ADD
+ 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x700e7e7e, 0x7e7e700e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_ADD_FILL
+ 0x03c00000, 0x10080c30, 0x21842184, 0x41824182, 0x40024182, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_WARNING
+ 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x7e7e7e7e, 0x7ffe7e7e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_WARNING_FILL
+ 0x00000000, 0x10041ffc, 0x10841004, 0x13e41084, 0x10841084, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MORE
+ 0x00000000, 0x1ffc1ffc, 0x1f7c1ffc, 0x1c1c1f7c, 0x1f7c1f7c, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MORE_FILL
+ 0x00000000, 0x1ffc1ffc, 0x1ffc1ffc, 0x1c1c1ffc, 0x1ffc1ffc, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS
+ 0x00000000, 0x10041ffc, 0x10041004, 0x13e41004, 0x10041004, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS_FILL
+ 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x55766eba, 0x55766eaa, 0x55606ffe, 0x55606aa0, 0x00007fe0, // ICON_UNION
+ 0x07fe0000, 0x04020402, 0x7fe20402, 0x456246a2, 0x456246a2, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_INTERSECTION
+ 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x4436442a, 0x4436442a, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_DIFFERENCE
+ 0x03c00000, 0x10080c30, 0x20042004, 0x60064002, 0x47e2581a, 0x20042004, 0x0c301008, 0x000003c0, // ICON_SPHERE
+ 0x03e00000, 0x08080410, 0x0c180808, 0x08080be8, 0x08080808, 0x08080808, 0x04100808, 0x000003e0, // ICON_CYLINDER
+ 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE
+ 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID
+ 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255
+};
+
+// NOTE: A pointer to current icons array should be defined
+static unsigned int *guiIconsPtr = guiIcons;
+
+#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS
+
+#ifndef RAYGUI_ICON_SIZE
+ #define RAYGUI_ICON_SIZE 0
+#endif
+
+// WARNING: Those values define the total size of the style data array,
+// if changed, previous saved styles could become incompatible
+#define RAYGUI_MAX_CONTROLS 16 // Maximum number of controls
+#define RAYGUI_MAX_PROPS_BASE 16 // Maximum number of base properties
+#define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties
+
+//----------------------------------------------------------------------------------
+// Module Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Gui control property style color element
+typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state
+
+static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib)
+static bool guiLocked = false; // Gui lock state (no inputs processed)
+static float guiAlpha = 1.0f; // Gui controls transparency
+
+static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled)
+
+static bool guiTooltip = false; // Tooltip enabled/disabled
+static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user)
+
+static bool guiControlExclusiveMode = false; // Gui control exclusive mode (no inputs processed except current control)
+static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds rectangle, used as an unique identifier
+
+static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*()
+//static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking
+static int autoCursorCounter = 0; // Frame counter for automatic repeated cursor movement on key-down (cooldown and delay)
+
+//----------------------------------------------------------------------------------
+// Style data array for all gui style properties (allocated on data segment by default)
+//
+// NOTE 1: First set of BASE properties are generic to all controls but could be individually
+// overwritten per control, first set of EXTENDED properties are generic to all controls and
+// can not be overwritten individually but custom EXTENDED properties can be used by control
+//
+// NOTE 2: A new style set could be loaded over this array using GuiLoadStyle(),
+// but default gui style could always be recovered with GuiLoadStyleDefault()
+//
+// guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB
+//----------------------------------------------------------------------------------
+static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)] = { 0 };
+
+static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization
+
+//----------------------------------------------------------------------------------
+// Standalone Mode Functions Declaration
+//
+// NOTE: raygui depend on some raylib input and drawing functions
+// To use raygui as standalone library, below functions must be defined by the user
+//----------------------------------------------------------------------------------
+#if defined(RAYGUI_STANDALONE)
+
+#define KEY_RIGHT 262
+#define KEY_LEFT 263
+#define KEY_DOWN 264
+#define KEY_UP 265
+#define KEY_BACKSPACE 259
+#define KEY_ENTER 257
+
+#define MOUSE_LEFT_BUTTON 0
+
+// Input required functions
+//-------------------------------------------------------------------------------
+static Vector2 GetMousePosition(void);
+static float GetMouseWheelMove(void);
+static bool IsMouseButtonDown(int button);
+static bool IsMouseButtonPressed(int button);
+static bool IsMouseButtonReleased(int button);
+
+static bool IsKeyDown(int key);
+static bool IsKeyPressed(int key);
+static int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox()
+//-------------------------------------------------------------------------------
+
+// Drawing required functions
+//-------------------------------------------------------------------------------
+static void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle()
+static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker()
+//-------------------------------------------------------------------------------
+
+// Text required functions
+//-------------------------------------------------------------------------------
+static Font GetFontDefault(void); // -- GuiLoadStyleDefault()
+static Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle(), load font
+
+static Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image
+static void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization)
+
+static char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data
+static void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data
+
+static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs
+
+static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list
+static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list
+
+static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle()
+//-------------------------------------------------------------------------------
+
+// raylib functions already implemented in raygui
+//-------------------------------------------------------------------------------
+static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
+static int ColorToInt(Color color); // Returns hexadecimal value for a Color
+static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle
+static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
+static const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings
+static int TextToInteger(const char *text); // Get integer value from text
+static float TextToFloat(const char *text); // Get float value from text
+
+static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text
+static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter)
+
+static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient
+//-------------------------------------------------------------------------------
+
+#endif // RAYGUI_STANDALONE
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only)
+
+static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds
+static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor
+
+static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font
+static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style
+
+static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings
+static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB
+static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV
+
+static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel()
+static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position
+
+static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor
+
+//----------------------------------------------------------------------------------
+// Gui Setup Functions Definition
+//----------------------------------------------------------------------------------
+// Enable gui global state
+// NOTE: We check for STATE_DISABLED to avoid messing custom global state setups
+void GuiEnable(void) { if (guiState == STATE_DISABLED) guiState = STATE_NORMAL; }
+
+// Disable gui global state
+// NOTE: We check for STATE_NORMAL to avoid messing custom global state setups
+void GuiDisable(void) { if (guiState == STATE_NORMAL) guiState = STATE_DISABLED; }
+
+// Lock gui global state
+void GuiLock(void) { guiLocked = true; }
+
+// Unlock gui global state
+void GuiUnlock(void) { guiLocked = false; }
+
+// Check if gui is locked (global state)
+bool GuiIsLocked(void) { return guiLocked; }
+
+// Set gui controls alpha global state
+void GuiSetAlpha(float alpha)
+{
+ if (alpha < 0.0f) alpha = 0.0f;
+ else if (alpha > 1.0f) alpha = 1.0f;
+
+ guiAlpha = alpha;
+}
+
+// Set gui state (global state)
+void GuiSetState(int state) { guiState = (GuiState)state; }
+
+// Get gui state (global state)
+int GuiGetState(void) { return guiState; }
+
+// Set custom gui font
+// NOTE: Font loading/unloading is external to raygui
+void GuiSetFont(Font font)
+{
+ if (font.texture.id > 0)
+ {
+ // NOTE: If we try to setup a font but default style has not been
+ // lazily loaded before, it will be overwritten, so we need to force
+ // default style loading first
+ if (!guiStyleLoaded) GuiLoadStyleDefault();
+
+ guiFont = font;
+ }
+}
+
+// Get custom gui font
+Font GuiGetFont(void)
+{
+ return guiFont;
+}
+
+// Set control style property value
+void GuiSetStyle(int control, int property, int value)
+{
+ if (!guiStyleLoaded) GuiLoadStyleDefault();
+ guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value;
+
+ // Default properties are propagated to all controls
+ if ((control == 0) && (property < RAYGUI_MAX_PROPS_BASE))
+ {
+ for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) guiStyle[i*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value;
+ }
+}
+
+// Get control style property value
+int GuiGetStyle(int control, int property)
+{
+ if (!guiStyleLoaded) GuiLoadStyleDefault();
+ return guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property];
+}
+
+//----------------------------------------------------------------------------------
+// Gui Controls Functions Definition
+//----------------------------------------------------------------------------------
+
+// Window Box control
+int GuiWindowBox(Rectangle bounds, const char *title)
+{
+ // Window title bar height (including borders)
+ // NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox()
+ #if !defined(RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT)
+ #define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24
+ #endif
+
+ #if !defined(RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT)
+ #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18
+ #endif
+
+ int result = 0;
+ //GuiState state = guiState;
+
+ int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT;
+
+ Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight };
+ if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f;
+
+ const float vPadding = statusBarHeight/2.0f - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT/2.0f;
+ Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 };
+ Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT - vPadding,
+ statusBar.y + vPadding, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT };
+
+ // Update control
+ //--------------------------------------------------------------------
+ // NOTE: Logic is directly managed by button
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiStatusBar(statusBar, title); // Draw window header as status bar
+ GuiPanel(windowPanel, NULL); // Draw window base
+
+ // Draw window close button
+ int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
+ int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+#if defined(RAYGUI_NO_ICONS)
+ result = GuiButton(closeButtonRec, "x");
+#else
+ result = GuiButton(closeButtonRec, GuiIconText(ICON_CROSS_SMALL, NULL));
+#endif
+ GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment);
+ //--------------------------------------------------------------------
+
+ return result; // Window close button clicked: result = 1
+}
+
+// Group Box control with text name
+int GuiGroupBox(Rectangle bounds, const char *text)
+{
+ #if !defined(RAYGUI_GROUPBOX_LINE_THICK)
+ #define RAYGUI_GROUPBOX_LINE_THICK 1
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)));
+
+ GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text);
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Line control
+int GuiLine(Rectangle bounds, const char *text)
+{
+ #if !defined(RAYGUI_LINE_MARGIN_TEXT)
+ #define RAYGUI_LINE_MARGIN_TEXT 12
+ #endif
+ #if !defined(RAYGUI_LINE_TEXT_PADDING)
+ #define RAYGUI_LINE_TEXT_PADDING 4
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR));
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (text == NULL) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, bounds.width, 1 }, 0, BLANK, color);
+ else
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
+ textBounds.height = bounds.height;
+ textBounds.x = bounds.x + RAYGUI_LINE_MARGIN_TEXT;
+ textBounds.y = bounds.y;
+
+ // Draw line with embedded text label: "--- text --------------"
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color);
+ GuiDrawText(text, textBounds, TEXT_ALIGN_LEFT, color);
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + 12 + textBounds.width + 4, bounds.y + bounds.height/2, bounds.width - textBounds.width - RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color);
+ }
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Panel control
+int GuiPanel(Rectangle bounds, const char *text)
+{
+ #if !defined(RAYGUI_PANEL_BORDER_WIDTH)
+ #define RAYGUI_PANEL_BORDER_WIDTH 1
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ // Text will be drawn as a header bar (if provided)
+ Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT };
+ if ((text != NULL) && (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f)) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f;
+
+ if (text != NULL)
+ {
+ // Move panel bounds after the header bar
+ bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1;
+ bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1;
+ }
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar
+
+ GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)),
+ GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR)));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Tab Bar control
+// NOTE: Using GuiToggle() for the TABS
+int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
+{
+ #define RAYGUI_TABBAR_ITEM_WIDTH 148
+
+ int result = -1;
+ //GuiState state = guiState;
+
+ Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height };
+
+ if (*active < 0) *active = 0;
+ else if (*active > count - 1) *active = count - 1;
+
+ int offsetX = 0; // Required in case tabs go out of screen
+ offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth();
+ if (offsetX < 0) offsetX = 0;
+
+ bool toggle = false; // Required for individual toggles
+
+ // Draw control
+ //--------------------------------------------------------------------
+ for (int i = 0; i < count; i++)
+ {
+ tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX;
+
+ if (tabBounds.x < GetScreenWidth())
+ {
+ // Draw tabs as toggle controls
+ int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT);
+ int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING);
+ GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+ GuiSetStyle(TOGGLE, TEXT_PADDING, 8);
+
+ if (i == (*active))
+ {
+ toggle = true;
+ GuiToggle(tabBounds, text[i], &toggle);
+ }
+ else
+ {
+ toggle = false;
+ GuiToggle(tabBounds, text[i], &toggle);
+ if (toggle) *active = i;
+ }
+
+ // Close tab with middle mouse button pressed
+ if (CheckCollisionPointRec(GetMousePosition(), tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i;
+
+ GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding);
+ GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment);
+
+ // Draw tab close button
+ // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds))
+ int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
+ int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+#if defined(RAYGUI_NO_ICONS)
+ if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i;
+#else
+ if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i;
+#endif
+ GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment);
+ }
+ }
+
+ // Draw tab-bar bottom line
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL)));
+ //--------------------------------------------------------------------
+
+ return result; // Return as result the current TAB closing requested
+}
+
+// Scroll Panel control
+int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view)
+{
+ #define RAYGUI_MIN_SCROLLBAR_WIDTH 40
+ #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40
+ #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20
+
+ int result = 0;
+ GuiState state = guiState;
+
+ Rectangle temp = { 0 };
+ if (view == NULL) view = &temp;
+
+ Vector2 scrollPos = { 0.0f, 0.0f };
+ if (scroll != NULL) scrollPos = *scroll;
+
+ // Text will be drawn as a header bar (if provided)
+ Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT };
+ if (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f;
+
+ if (text != NULL)
+ {
+ // Move panel bounds after the header bar
+ bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1;
+ bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + 1;
+ }
+
+ bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false;
+ bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false;
+
+ // Recheck to account for the other scrollbar being visible
+ if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false;
+ if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false;
+
+ int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0;
+ int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0;
+ Rectangle horizontalScrollBar = {
+ (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH),
+ (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH),
+ (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH),
+ (float)horizontalScrollBarWidth
+ };
+ Rectangle verticalScrollBar = {
+ (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)),
+ (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH),
+ (float)verticalScrollBarWidth,
+ (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH)
+ };
+
+ // Make sure scroll bars have a minimum width/height
+ if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH;
+ if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT;
+
+ // Calculate view area (area without the scrollbars)
+ *view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)?
+ RAYGUI_CLITERAL(Rectangle){ bounds.x + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth } :
+ RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth };
+
+ // Clip view area to the actual content size
+ if (view->width > content.width) view->width = content.width;
+ if (view->height > content.height) view->height = content.height;
+
+ float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH);
+ float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH);
+ float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f;
+ float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH);
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check button state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+
+#if defined(SUPPORT_SCROLLBAR_KEY_INPUT)
+ if (hasHorizontalScrollBar)
+ {
+ if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ }
+
+ if (hasVerticalScrollBar)
+ {
+ if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ }
+#endif
+ float wheelMove = GetMouseWheelMove();
+
+ // Set scrolling speed with mouse wheel based on ratio between bounds and content
+ Vector2 mouseWheelSpeed = { content.width/bounds.width, content.height/bounds.height };
+ if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
+ if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
+
+ // Horizontal and vertical scrolling with mouse wheel
+ if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x;
+ else scrollPos.y += wheelMove*mouseWheelSpeed.y; // Vertical scroll
+ }
+ }
+
+ // Normalize scroll values
+ if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin;
+ if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax;
+ if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin;
+ if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax;
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar
+
+ GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
+
+ // Save size of the scrollbar slider
+ const int slider = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE);
+
+ // Draw horizontal scrollbar if visible
+ if (hasHorizontalScrollBar)
+ {
+ // Change scrollbar slider size to show the diff in size between the content width and the widget width
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/(int)content.width)*((int)bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)));
+ scrollPos.x = (float)-GuiScrollBar(horizontalScrollBar, (int)-scrollPos.x, (int)horizontalMin, (int)horizontalMax);
+ }
+ else scrollPos.x = 0.0f;
+
+ // Draw vertical scrollbar if visible
+ if (hasVerticalScrollBar)
+ {
+ // Change scrollbar slider size to show the diff in size between the content height and the widget height
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/(int)content.height)*((int)bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)));
+ scrollPos.y = (float)-GuiScrollBar(verticalScrollBar, (int)-scrollPos.y, (int)verticalMin, (int)verticalMax);
+ }
+ else scrollPos.y = 0.0f;
+
+ // Draw detail corner rectangle if both scroll bars are visible
+ if (hasHorizontalScrollBar && hasVerticalScrollBar)
+ {
+ Rectangle corner = { (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) + 2) : (horizontalScrollBar.x + horizontalScrollBar.width + 2), verticalScrollBar.y + verticalScrollBar.height + 2, (float)horizontalScrollBarWidth - 4, (float)verticalScrollBarWidth - 4 };
+ GuiDrawRectangle(corner, 0, BLANK, GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3))));
+ }
+
+ // Draw scrollbar lines depending on current state
+ GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK);
+
+ // Set scrollbar slider size back to the way it was before
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider);
+ //--------------------------------------------------------------------
+
+ if (scroll != NULL) *scroll = scrollPos;
+
+ return result;
+}
+
+// Label control
+int GuiLabel(Rectangle bounds, const char *text)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ // Update control
+ //--------------------------------------------------------------------
+ //...
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Button control, returns true when clicked
+int GuiButton(Rectangle bounds, const char *text)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check button state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+
+ if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), GetColor(GuiGetStyle(BUTTON, BASE + (state*3))));
+ GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))));
+
+ if (state == STATE_FOCUSED) GuiTooltip(bounds);
+ //------------------------------------------------------------------
+
+ return result; // Button pressed: result = 1
+}
+
+// Label button control
+int GuiLabelButton(Rectangle bounds, const char *text)
+{
+ GuiState state = guiState;
+ bool pressed = false;
+
+ // NOTE: We force bounds.width to be all text
+ float textWidth = (float)GuiGetTextWidth(text);
+ if ((bounds.width - 2*GuiGetStyle(LABEL, BORDER_WIDTH) - 2*GuiGetStyle(LABEL, TEXT_PADDING)) < textWidth) bounds.width = textWidth + 2*GuiGetStyle(LABEL, BORDER_WIDTH) + 2*GuiGetStyle(LABEL, TEXT_PADDING) + 2;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check checkbox state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+
+ if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return pressed;
+}
+
+// Toggle Button control
+int GuiToggle(Rectangle bounds, const char *text, bool *active)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ bool temp = false;
+ if (active == NULL) active = &temp;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check toggle button state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_NORMAL;
+ *active = !(*active);
+ }
+ else state = STATE_FOCUSED;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state == STATE_NORMAL)
+ {
+ GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3)))), GetColor(GuiGetStyle(TOGGLE, ((*active)? BASE_COLOR_PRESSED : (BASE + state*3)))));
+ GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, ((*active)? TEXT_COLOR_PRESSED : (TEXT + state*3)))));
+ }
+ else
+ {
+ GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), GetColor(GuiGetStyle(TOGGLE, BASE + state*3)));
+ GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, TEXT + state*3)));
+ }
+
+ if (state == STATE_FOCUSED) GuiTooltip(bounds);
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Toggle Group control
+int GuiToggleGroup(Rectangle bounds, const char *text, int *active)
+{
+ #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS)
+ #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32
+ #endif
+
+ int result = 0;
+ float initBoundsX = bounds.x;
+
+ int temp = 0;
+ if (active == NULL) active = &temp;
+
+ bool toggle = false; // Required for individual toggles
+
+ // Get substrings items from text (items pointers)
+ int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 };
+ int itemCount = 0;
+ const char **items = GuiTextSplit(text, ';', &itemCount, rows);
+
+ int prevRow = rows[0];
+
+ for (int i = 0; i < itemCount; i++)
+ {
+ if (prevRow != rows[i])
+ {
+ bounds.x = initBoundsX;
+ bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING));
+ prevRow = rows[i];
+ }
+
+ if (i == (*active))
+ {
+ toggle = true;
+ GuiToggle(bounds, items[i], &toggle);
+ }
+ else
+ {
+ toggle = false;
+ GuiToggle(bounds, items[i], &toggle);
+ if (toggle) *active = i;
+ }
+
+ bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING));
+ }
+
+ return result;
+}
+
+// Toggle Slider control extended
+int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ int temp = 0;
+ if (active == NULL) active = &temp;
+
+ //bool toggle = false; // Required for individual toggles
+
+ // Get substrings items from text (items pointers)
+ int itemCount = 0;
+ const char **items = NULL;
+
+ if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
+
+ Rectangle slider = {
+ 0, // Calculated later depending on the active toggle
+ bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
+ (bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - (itemCount + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING))/itemCount,
+ bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ (*active)++;
+ result = 1;
+ }
+ else state = STATE_FOCUSED;
+ }
+
+ if ((*active) && (state != STATE_FOCUSED)) state = STATE_PRESSED;
+ }
+
+ if (*active >= itemCount) *active = 0;
+ slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width;
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + (state*3))),
+ GetColor(GuiGetStyle(TOGGLE, BASE_COLOR_NORMAL)));
+
+ // Draw internal slider
+ if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
+ else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_FOCUSED)));
+ else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
+
+ // Draw text in slider
+ if (text != NULL)
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GuiGetTextWidth(text);
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = slider.x + slider.width/2 - textBounds.width/2;
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+ GuiDrawText(items[*active], textBounds, GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + (state*3))), guiAlpha));
+ }
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Check Box control, returns 1 when state changed
+int GuiCheckBox(Rectangle bounds, const char *text, bool *checked)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ bool temp = false;
+ if (checked == NULL) checked = &temp;
+
+ Rectangle textBounds = { 0 };
+
+ if (text != NULL)
+ {
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+ if (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(CHECKBOX, TEXT_PADDING);
+ }
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ Rectangle totalBounds = {
+ (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT)? textBounds.x : bounds.x,
+ bounds.y,
+ bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING),
+ bounds.height,
+ };
+
+ // Check checkbox state
+ if (CheckCollisionPointRec(mousePoint, totalBounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+
+ if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
+ {
+ *checked = !(*checked);
+ result = 1;
+ }
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), BLANK);
+
+ if (*checked)
+ {
+ Rectangle check = { bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING),
+ bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING),
+ bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)),
+ bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)) };
+ GuiDrawRectangle(check, 0, BLANK, GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)));
+ }
+
+ GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Combo Box control
+int GuiComboBox(Rectangle bounds, const char *text, int *active)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ int temp = 0;
+ if (active == NULL) active = &temp;
+
+ bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING));
+
+ Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING),
+ (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height };
+
+ // Get substrings items from text (items pointers, lengths and count)
+ int itemCount = 0;
+ const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
+
+ if (*active < 0) *active = 0;
+ else if (*active > (itemCount - 1)) *active = itemCount - 1;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (CheckCollisionPointRec(mousePoint, bounds) ||
+ CheckCollisionPointRec(mousePoint, selector))
+ {
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ *active += 1;
+ if (*active >= itemCount) *active = 0; // Cyclic combobox
+ }
+
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ // Draw combo box main
+ GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3))));
+ GuiDrawText(items[*active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3))));
+
+ // Draw selector using a custom button
+ // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
+ int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
+ int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+ GuiButton(selector, TextFormat("%i/%i", *active + 1, itemCount));
+
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Dropdown Box control
+// NOTE: Returns mouse click
+int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ int temp = 0;
+ if (active == NULL) active = &temp;
+
+ int itemSelected = *active;
+ int itemFocused = -1;
+
+ int direction = 0; // Dropdown box open direction: down (default)
+ if (GuiGetStyle(DROPDOWNBOX, DROPDOWN_ROLL_UP) == 1) direction = 1; // Up
+
+ // Get substrings items from text (items pointers, lengths and count)
+ int itemCount = 0;
+ const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
+
+ Rectangle boundsOpen = bounds;
+ boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+ if (direction == 1) boundsOpen.y -= itemCount*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)) + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING);
+
+ Rectangle itemBounds = bounds;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (editMode)
+ {
+ state = STATE_PRESSED;
+
+ // Check if mouse has been pressed or released outside limits
+ if (!CheckCollisionPointRec(mousePoint, boundsOpen))
+ {
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
+ }
+
+ // Check if already selected item has been pressed again
+ if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
+
+ // Check focused and selected item
+ for (int i = 0; i < itemCount; i++)
+ {
+ // Update item rectangle y position for next item
+ if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+ else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+
+ if (CheckCollisionPointRec(mousePoint, itemBounds))
+ {
+ itemFocused = i;
+ if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
+ {
+ itemSelected = i;
+ result = 1; // Item selected
+ }
+ break;
+ }
+ }
+
+ itemBounds = bounds;
+ }
+ else
+ {
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ result = 1;
+ state = STATE_PRESSED;
+ }
+ else state = STATE_FOCUSED;
+ }
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (editMode) GuiPanel(boundsOpen, NULL);
+
+ GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3)));
+ GuiDrawText(items[itemSelected], GetTextBounds(DROPDOWNBOX, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3)));
+
+ if (editMode)
+ {
+ // Draw visible items
+ for (int i = 0; i < itemCount; i++)
+ {
+ // Update item rectangle y position for next item
+ if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+ else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+
+ if (i == itemSelected)
+ {
+ GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED)));
+ GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED)));
+ }
+ else if (i == itemFocused)
+ {
+ GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED)));
+ GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED)));
+ }
+ else GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL)));
+ }
+ }
+
+ if (!GuiGetStyle(DROPDOWNBOX, DROPDOWN_ARROW_HIDDEN))
+ {
+ // Draw arrows (using icon if available)
+#if defined(RAYGUI_NO_ICONS)
+ GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
+#else
+ GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL
+#endif
+ }
+ //--------------------------------------------------------------------
+
+ *active = itemSelected;
+
+ // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item...
+ return result; // Mouse click: result = 1
+}
+
+// Text Box control
+// NOTE: Returns true on ENTER pressed (useful for data validation)
+int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
+{
+ #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)
+ #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 20 // Frames to wait for autocursor movement
+ #endif
+ #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY)
+ #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ bool multiline = false; // TODO: Consider multiline text input
+ int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE);
+
+ Rectangle textBounds = GetTextBounds(TEXTBOX, bounds);
+ int textLength = (text != NULL)? (int)strlen(text) : 0; // Get current text length
+ int thisCursorIndex = textBoxCursorIndex;
+ if (thisCursorIndex > textLength) thisCursorIndex = textLength;
+ int textWidth = GuiGetTextWidth(text) - GuiGetTextWidth(text + thisCursorIndex);
+ int textIndexOffset = 0; // Text index offset to start drawing in the box
+
+ // Cursor rectangle
+ // NOTE: Position X value should be updated
+ Rectangle cursor = {
+ textBounds.x + textWidth + GuiGetStyle(DEFAULT, TEXT_SPACING),
+ textBounds.y + textBounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE),
+ 2,
+ (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2
+ };
+
+ if (cursor.height >= bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2;
+ if (cursor.y < (bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH))) cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH);
+
+ // Mouse cursor rectangle
+ // NOTE: Initialized outside of screen
+ Rectangle mouseCursor = cursor;
+ mouseCursor.x = -1;
+ mouseCursor.width = 1;
+
+ // Blink-cursor frame counter
+ //if (!autoCursorMode) blinkCursorFrameCounter++;
+ //else blinkCursorFrameCounter = 0;
+
+ // Update control
+ //--------------------------------------------------------------------
+ // WARNING: Text editing is only supported under certain conditions:
+ if ((state != STATE_DISABLED) && // Control not disabled
+ !GuiGetStyle(TEXTBOX, TEXT_READONLY) && // TextBox not on read-only mode
+ !guiLocked && // Gui not locked
+ !guiControlExclusiveMode && // No gui slider on dragging
+ (wrapMode == TEXT_WRAP_NONE)) // No wrap mode
+ {
+ Vector2 mousePosition = GetMousePosition();
+
+ if (editMode)
+ {
+ // GLOBAL: Auto-cursor movement logic
+ // NOTE: Keystrokes are handled repeatedly when button is held down for some time
+ if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCounter++;
+ else autoCursorCounter = 0;
+
+ bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0);
+
+ state = STATE_PRESSED;
+
+ if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
+
+ // If text does not fit in the textbox and current cursor position is out of bounds,
+ // we add an index offset to text for drawing only what requires depending on cursor
+ while (textWidth >= textBounds.width)
+ {
+ int nextCodepointSize = 0;
+ GetCodepointNext(text + textIndexOffset, &nextCodepointSize);
+
+ textIndexOffset += nextCodepointSize;
+
+ textWidth = GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex);
+ }
+
+ int codepoint = GetCharPressed(); // Get Unicode codepoint
+ if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n';
+
+ // Encode codepoint as UTF-8
+ int codepointSize = 0;
+ const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize);
+
+ // Handle text paste action
+ if (IsKeyPressed(KEY_V) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
+ {
+ const char *pasteText = GetClipboardText();
+ if (pasteText != NULL)
+ {
+ int pasteLength = 0;
+ int pasteCodepoint;
+ int pasteCodepointSize;
+
+ // Count how many codepoints to copy, stopping at the first unwanted control character
+ while (true)
+ {
+ pasteCodepoint = GetCodepointNext(pasteText + pasteLength, &pasteCodepointSize);
+ if (textLength + pasteLength + pasteCodepointSize >= textSize) break;
+ if (!(multiline && (pasteCodepoint == (int)'\n')) && !(pasteCodepoint >= 32)) break;
+ pasteLength += pasteCodepointSize;
+ }
+
+ if (pasteLength > 0)
+ {
+ // Move forward data from cursor position
+ for (int i = textLength + pasteLength; i > textBoxCursorIndex; i--) text[i] = text[i - pasteLength];
+
+ // Paste data in at cursor
+ for (int i = 0; i < pasteLength; i++) text[textBoxCursorIndex + i] = pasteText[i];
+
+ textBoxCursorIndex += pasteLength;
+ textLength += pasteLength;
+ text[textLength] = '\0';
+ }
+ }
+ }
+ else if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize))
+ {
+ // Adding codepoint to text, at current cursor position
+
+ // Move forward data from cursor position
+ for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize];
+
+ // Add new codepoint in current cursor position
+ for (int i = 0; i < codepointSize; i++) text[textBoxCursorIndex + i] = charEncoded[i];
+
+ textBoxCursorIndex += codepointSize;
+ textLength += codepointSize;
+
+ // Make sure text last character is EOL
+ text[textLength] = '\0';
+ }
+
+ // Move cursor to start
+ if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0;
+
+ // Move cursor to end
+ if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
+
+ // Delete related codepoints from text, after current cursor position
+ if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_DELETE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
+ {
+ int offset = textBoxCursorIndex;
+ int accCodepointSize = 0;
+ int nextCodepointSize;
+ int nextCodepoint;
+
+ // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ bool puctuation = ispunct(nextCodepoint & 0xff);
+ while (offset < textLength)
+ {
+ if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff))))
+ break;
+ offset += nextCodepointSize;
+ accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ }
+
+ // Check whitespace to delete (ASCII only)
+ while (offset < textLength)
+ {
+ if (!isspace(nextCodepoint & 0xff)) break;
+
+ offset += nextCodepointSize;
+ accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ }
+
+ // Move text after cursor forward (including final null terminator)
+ for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i];
+
+ textLength -= accCodepointSize;
+ }
+
+ else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && autoCursorShouldTrigger)))
+ {
+ // Delete single codepoint from text, after current cursor position
+
+ int nextCodepointSize = 0;
+ GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
+
+ // Move text after cursor forward (including final null terminator)
+ for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i];
+
+ textLength -= nextCodepointSize;
+ }
+
+ // Delete related codepoints from text, before current cursor position
+ if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
+ {
+ int offset = textBoxCursorIndex;
+ int accCodepointSize = 0;
+ int prevCodepointSize;
+ int prevCodepoint;
+
+ // Check whitespace to delete (ASCII only)
+ while (offset > 0)
+ {
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if (!isspace(prevCodepoint & 0xff)) break;
+
+ offset -= prevCodepointSize;
+ accCodepointSize += prevCodepointSize;
+ }
+
+ // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ bool puctuation = ispunct(prevCodepoint & 0xff);
+ while (offset > 0)
+ {
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break;
+
+ offset -= prevCodepointSize;
+ accCodepointSize += prevCodepointSize;
+ }
+
+ // Move text after cursor forward (including final null terminator)
+ for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - accCodepointSize] = text[i];
+
+ textLength -= accCodepointSize;
+ textBoxCursorIndex -= accCodepointSize;
+ }
+
+ else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && autoCursorShouldTrigger)))
+ {
+ // Delete single codepoint from text, before current cursor position
+
+ int prevCodepointSize = 0;
+
+ GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
+
+ // Move text after cursor forward (including final null terminator)
+ for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - prevCodepointSize] = text[i];
+
+ textLength -= prevCodepointSize;
+ textBoxCursorIndex -= prevCodepointSize;
+ }
+
+ // Move cursor position with keys
+ if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_LEFT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
+ {
+ int offset = textBoxCursorIndex;
+ //int accCodepointSize = 0;
+ int prevCodepointSize;
+ int prevCodepoint;
+
+ // Check whitespace to skip (ASCII only)
+ while (offset > 0)
+ {
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if (!isspace(prevCodepoint & 0xff)) break;
+
+ offset -= prevCodepointSize;
+ //accCodepointSize += prevCodepointSize;
+ }
+
+ // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ bool puctuation = ispunct(prevCodepoint & 0xff);
+ while (offset > 0)
+ {
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break;
+
+ offset -= prevCodepointSize;
+ //accCodepointSize += prevCodepointSize;
+ }
+
+ textBoxCursorIndex = offset;
+ }
+ else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && autoCursorShouldTrigger)))
+ {
+ int prevCodepointSize = 0;
+ GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
+
+ textBoxCursorIndex -= prevCodepointSize;
+ }
+ else if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_RIGHT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
+ {
+ int offset = textBoxCursorIndex;
+ //int accCodepointSize = 0;
+ int nextCodepointSize;
+ int nextCodepoint;
+
+ // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ bool puctuation = ispunct(nextCodepoint & 0xff);
+ while (offset < textLength)
+ {
+ if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break;
+
+ offset += nextCodepointSize;
+ //accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ }
+
+ // Check whitespace to skip (ASCII only)
+ while (offset < textLength)
+ {
+ if (!isspace(nextCodepoint & 0xff)) break;
+
+ offset += nextCodepointSize;
+ //accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ }
+
+ textBoxCursorIndex = offset;
+ }
+ else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && autoCursorShouldTrigger)))
+ {
+ int nextCodepointSize = 0;
+ GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
+
+ textBoxCursorIndex += nextCodepointSize;
+ }
+
+ // Move cursor position with mouse
+ if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text
+ {
+ float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize;
+ int codepointIndex = 0;
+ float glyphWidth = 0.0f;
+ float widthToMouseX = 0;
+ int mouseCursorIndex = 0;
+
+ for (int i = textIndexOffset; i < textLength; i += codepointSize)
+ {
+ codepoint = GetCodepointNext(&text[i], &codepointSize);
+ codepointIndex = GetGlyphIndex(guiFont, codepoint);
+
+ if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
+ else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
+
+ if (mousePosition.x <= (textBounds.x + (widthToMouseX + glyphWidth/2)))
+ {
+ mouseCursor.x = textBounds.x + widthToMouseX;
+ mouseCursorIndex = i;
+ break;
+ }
+
+ widthToMouseX += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ }
+
+ // Check if mouse cursor is at the last position
+ int textEndWidth = GuiGetTextWidth(text + textIndexOffset);
+ if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2))
+ {
+ mouseCursor.x = textBounds.x + textEndWidth;
+ mouseCursorIndex = textLength;
+ }
+
+ // Place cursor at required index on mouse click
+ if ((mouseCursor.x >= 0) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ cursor.x = mouseCursor.x;
+ textBoxCursorIndex = mouseCursorIndex;
+ }
+ }
+ else mouseCursor.x = -1;
+
+ // Recalculate cursor position.y depending on textBoxCursorIndex
+ cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING);
+ //if (multiline) cursor.y = GetTextLines()
+
+ // Finish text editing on ENTER or mouse click outside bounds
+ if ((!multiline && IsKeyPressed(KEY_ENTER)) ||
+ (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
+ {
+ textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index
+ autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes
+ result = 1;
+ }
+ }
+ else
+ {
+ if (CheckCollisionPointRec(mousePosition, bounds))
+ {
+ state = STATE_FOCUSED;
+
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text
+ autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes
+ result = 1;
+ }
+ }
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state == STATE_PRESSED)
+ {
+ GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)));
+ }
+ else if (state == STATE_DISABLED)
+ {
+ GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)));
+ }
+ else GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), BLANK);
+
+ // Draw text considering index offset if required
+ // NOTE: Text index offset depends on cursor position
+ GuiDrawText(text + textIndexOffset, textBounds, GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))));
+
+ // Draw cursor
+ if (editMode && !GuiGetStyle(TEXTBOX, TEXT_READONLY))
+ {
+ //if (autoCursorMode || ((blinkCursorFrameCounter/40)%2 == 0))
+ GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)));
+
+ // Draw mouse position cursor (if required)
+ if (mouseCursor.x >= 0) GuiDrawRectangle(mouseCursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)));
+ }
+ else if (state == STATE_FOCUSED) GuiTooltip(bounds);
+ //--------------------------------------------------------------------
+
+ return result; // Mouse button pressed: result = 1
+}
+
+/*
+// Text Box control with multiple lines and word-wrap
+// NOTE: This text-box is readonly, no editing supported by default
+bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
+{
+ bool pressed = false;
+
+ GuiSetStyle(TEXTBOX, TEXT_READONLY, 1);
+ GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // WARNING: If wrap mode enabled, text editing is not supported
+ GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP);
+
+ // TODO: Implement methods to calculate cursor position properly
+ pressed = GuiTextBox(bounds, text, textSize, editMode);
+
+ GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE);
+ GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE);
+ GuiSetStyle(TEXTBOX, TEXT_READONLY, 0);
+
+ return pressed;
+}
+*/
+
+// Spinner control, returns selected value
+int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
+{
+ int result = 1;
+ GuiState state = guiState;
+
+ int tempValue = *value;
+
+ Rectangle valueBoxBounds = {
+ bounds.x + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING),
+ bounds.y,
+ bounds.width - 2*(GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING)), bounds.height };
+ Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height };
+ Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.y,
+ (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height };
+
+ Rectangle textBounds = { 0 };
+ if (text != NULL)
+ {
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+ if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
+ }
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check spinner state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+ }
+ }
+
+#if defined(RAYGUI_NO_ICONS)
+ if (GuiButton(leftButtonBound, "<")) tempValue--;
+ if (GuiButton(rightButtonBound, ">")) tempValue++;
+#else
+ if (GuiButton(leftButtonBound, GuiIconText(ICON_ARROW_LEFT_FILL, NULL))) tempValue--;
+ if (GuiButton(rightButtonBound, GuiIconText(ICON_ARROW_RIGHT_FILL, NULL))) tempValue++;
+#endif
+
+ if (!editMode)
+ {
+ if (tempValue < minValue) tempValue = minValue;
+ if (tempValue > maxValue) tempValue = maxValue;
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ result = GuiValueBox(valueBoxBounds, NULL, &tempValue, minValue, maxValue, editMode);
+
+ // Draw value selector custom buttons
+ // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
+ int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
+ int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(VALUEBOX, BORDER_WIDTH));
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
+
+ // Draw text label if provided
+ GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ *value = tempValue;
+ return result;
+}
+
+// Value Box control, updates input text with numbers
+// NOTE: Requires static variables: frameCounter
+int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
+{
+ #if !defined(RAYGUI_VALUEBOX_MAX_CHARS)
+ #define RAYGUI_VALUEBOX_MAX_CHARS 32
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 };
+ snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value);
+
+ Rectangle textBounds = { 0 };
+ if (text != NULL)
+ {
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+ if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
+ }
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+ bool valueHasChanged = false;
+
+ if (editMode)
+ {
+ state = STATE_PRESSED;
+
+ int keyCount = (int)strlen(textValue);
+
+ // Add or remove minus symbol
+ if (IsKeyPressed(KEY_MINUS))
+ {
+ if (textValue[0] == '-')
+ {
+ for (int i = 0 ; i < keyCount; i++) textValue[i] = textValue[i + 1];
+
+ keyCount--;
+ valueHasChanged = true;
+ }
+ else if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
+ {
+ if (keyCount == 0)
+ {
+ textValue[0] = '0';
+ textValue[1] = '\0';
+ keyCount++;
+ }
+
+ for (int i = keyCount ; i > -1; i--) textValue[i + 1] = textValue[i];
+
+ textValue[0] = '-';
+ keyCount++;
+ valueHasChanged = true;
+ }
+ }
+
+ // Add new digit to text value
+ if ((keyCount >= 0) && (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) && (GuiGetTextWidth(textValue) < bounds.width))
+ {
+ int key = GetCharPressed();
+
+ // Only allow keys in range [48..57]
+ if ((key >= 48) && (key <= 57))
+ {
+ textValue[keyCount] = (char)key;
+ keyCount++;
+ valueHasChanged = true;
+ }
+ }
+
+ // Delete text
+ if ((keyCount > 0) && IsKeyPressed(KEY_BACKSPACE))
+ {
+ keyCount--;
+ textValue[keyCount] = '\0';
+ valueHasChanged = true;
+ }
+
+ if (valueHasChanged) *value = TextToInteger(textValue);
+
+ // NOTE: We are not clamp values until user input finishes
+ //if (*value > maxValue) *value = maxValue;
+ //else if (*value < minValue) *value = minValue;
+
+ if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
+ {
+ if (*value > maxValue) *value = maxValue;
+ else if (*value < minValue) *value = minValue;
+
+ result = 1;
+ }
+ }
+ else
+ {
+ if (*value > maxValue) *value = maxValue;
+ else if (*value < minValue) *value = minValue;
+
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ state = STATE_FOCUSED;
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
+ }
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ Color baseColor = BLANK;
+ if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED));
+ else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED));
+
+ GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor);
+ GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))));
+
+ // Draw cursor rectangle
+ if (editMode)
+ {
+ // NOTE: ValueBox internal text is always centered
+ Rectangle cursor = { bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1,
+ bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + 2,
+ 2, bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2 - 4 };
+ if (cursor.height > bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2;
+ GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)));
+ }
+
+ // Draw text label if provided
+ GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Floating point Value Box control, updates input val_str with numbers
+// NOTE: Requires static variables: frameCounter
+int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode)
+{
+ #if !defined(RAYGUI_VALUEBOX_MAX_CHARS)
+ #define RAYGUI_VALUEBOX_MAX_CHARS 32
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
+ //snprintf(textValue, sizeof(textValue), "%2.2f", *value);
+
+ Rectangle textBounds = { 0 };
+ if (text != NULL)
+ {
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+ if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
+ }
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ bool valueHasChanged = false;
+
+ if (editMode)
+ {
+ state = STATE_PRESSED;
+
+ int keyCount = (int)strlen(textValue);
+
+ // Add or remove minus symbol
+ if (IsKeyPressed(KEY_MINUS))
+ {
+ if (textValue[0] == '-')
+ {
+ for (int i = 0; i < keyCount; i++) textValue[i] = textValue[i + 1];
+
+ keyCount--;
+ valueHasChanged = true;
+ }
+ else if (keyCount < (RAYGUI_VALUEBOX_MAX_CHARS - 1))
+ {
+ if (keyCount == 0)
+ {
+ textValue[0] = '0';
+ textValue[1] = '\0';
+ keyCount++;
+ }
+
+ for (int i = keyCount; i > -1; i--) textValue[i + 1] = textValue[i];
+
+ textValue[0] = '-';
+ keyCount++;
+ valueHasChanged = true;
+ }
+ }
+
+ // Only allow keys in range [48..57]
+ if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
+ {
+ if (GuiGetTextWidth(textValue) < bounds.width)
+ {
+ int key = GetCharPressed();
+ if (((key >= 48) && (key <= 57)) ||
+ (key == '.') ||
+ ((keyCount == 0) && (key == '+')) || // NOTE: Sign can only be in first position
+ ((keyCount == 0) && (key == '-')))
+ {
+ textValue[keyCount] = (char)key;
+ keyCount++;
+
+ valueHasChanged = true;
+ }
+ }
+ }
+
+ // Pressed backspace
+ if (IsKeyPressed(KEY_BACKSPACE))
+ {
+ if (keyCount > 0)
+ {
+ keyCount--;
+ textValue[keyCount] = '\0';
+ valueHasChanged = true;
+ }
+ }
+
+ if (valueHasChanged) *value = TextToFloat(textValue);
+
+ if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1;
+ }
+ else
+ {
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ state = STATE_FOCUSED;
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
+ }
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ Color baseColor = BLANK;
+ if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED));
+ else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED));
+
+ GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor);
+ GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))));
+
+ // Draw cursor
+ if (editMode)
+ {
+ // NOTE: ValueBox internal text is always centered
+ Rectangle cursor = {bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1,
+ bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4,
+ bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH)};
+ GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)));
+ }
+
+ // Draw text label if provided
+ GuiDrawText(text, textBounds,
+ (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT,
+ GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Slider control with pro parameters
+// NOTE: Other GuiSlider*() controls use this one
+int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ float temp = (maxValue - minValue)/2.0f;
+ if (value == NULL) value = &temp;
+ float oldValue = *value;
+
+ int sliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH);
+
+ Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
+ 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ {
+ state = STATE_PRESSED;
+ // Get equivalent value and slider position from mousePosition.x
+ *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue;
+ }
+ }
+ else
+ {
+ guiControlExclusiveMode = false;
+ guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ }
+ }
+ else if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ guiControlExclusiveMode = true;
+ guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+
+ if (!CheckCollisionPointRec(mousePoint, slider))
+ {
+ // Get equivalent value and slider position from mousePosition.x
+ *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue;
+ }
+ }
+ else state = STATE_FOCUSED;
+ }
+
+ if (*value > maxValue) *value = maxValue;
+ else if (*value < minValue) *value = minValue;
+ }
+
+ // Control value change check
+ if (oldValue == *value) result = 0;
+ else result = 1;
+
+ // Slider bar limits check
+ float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH)));
+ if (sliderWidth > 0) // Slider
+ {
+ slider.x += sliderValue;
+ slider.width = (float)sliderWidth;
+ if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH);
+ else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH);
+ }
+ else if (sliderWidth == 0) // SliderBar
+ {
+ slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH);
+ slider.width = sliderValue;
+ if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)));
+
+ // Draw slider internal bar (depends on state)
+ if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
+ else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)));
+ else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED)));
+ else if (state == STATE_DISABLED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_DISABLED)));
+
+ // Draw left/right text if provided
+ if (textLeft != NULL)
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GuiGetTextWidth(textLeft);
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+ GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ }
+
+ if (textRight != NULL)
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GuiGetTextWidth(textRight);
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+ GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ }
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Slider Bar control extended, returns selected value
+int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
+{
+ int result = 0;
+ int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH);
+ GuiSetStyle(SLIDER, SLIDER_WIDTH, 0);
+ result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue);
+ GuiSetStyle(SLIDER, SLIDER_WIDTH, preSliderWidth);
+
+ return result;
+}
+
+// Progress Bar control extended, shows current progress value
+int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ float temp = (maxValue - minValue)/2.0f;
+ if (value == NULL) value = &temp;
+
+ // Progress bar
+ Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH),
+ bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0,
+ bounds.height - GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) -1 };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if (*value > maxValue) *value = maxValue;
+
+ // WARNING: Working with floats could lead to rounding issues
+ if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH));
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state == STATE_DISABLED)
+ {
+ GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), BLANK);
+ }
+ else
+ {
+ if (*value > minValue)
+ {
+ // Draw progress bar with colored border, more visual
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
+ }
+ else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+
+ if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1}, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
+ else
+ {
+ // Draw borders not yet reached by value
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y + bounds.height - 1, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ }
+
+ // Draw slider internal progress bar (depends on state)
+ GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED)));
+ }
+
+ // Draw left/right text if provided
+ if (textLeft != NULL)
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GuiGetTextWidth(textLeft);
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+ GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ }
+
+ if (textRight != NULL)
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GuiGetTextWidth(textRight);
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+ GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ }
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Status Bar control
+int GuiStatusBar(Rectangle bounds, const char *text)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3))));
+ GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), GetColor(GuiGetStyle(STATUSBAR, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Dummy rectangle control, intended for placeholding
+int GuiDummyRec(Rectangle bounds, const char *text)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check button state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)));
+ GuiDrawText(text, GetTextBounds(DEFAULT, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(BUTTON, (state != STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)));
+ //------------------------------------------------------------------
+
+ return result;
+}
+
+// List View control
+int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active)
+{
+ int result = 0;
+ int itemCount = 0;
+ const char **items = NULL;
+
+ if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
+
+ result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL);
+
+ return result;
+}
+
+// List View control with extended parameters
+int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ int itemFocused = (focus == NULL)? -1 : *focus;
+ int itemSelected = (active == NULL)? -1 : *active;
+
+ // Check if we need a scroll bar
+ bool useScrollBar = false;
+ if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING))*count > bounds.height) useScrollBar = true;
+
+ // Define base item rectangle [0]
+ Rectangle itemBounds = { 0 };
+ itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING);
+ itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
+ itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
+ itemBounds.height = (float)GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
+ if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH);
+
+ // Get items on the list
+ int visibleItems = (int)bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING));
+ if (visibleItems > count) visibleItems = count;
+
+ int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex;
+ if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0;
+ int endIndex = startIndex + visibleItems;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check mouse inside list view
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ state = STATE_FOCUSED;
+
+ // Check focused and selected item
+ for (int i = 0; i < visibleItems; i++)
+ {
+ if (CheckCollisionPointRec(mousePoint, itemBounds))
+ {
+ itemFocused = startIndex + i;
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ if (itemSelected == (startIndex + i)) itemSelected = -1;
+ else itemSelected = startIndex + i;
+ }
+ break;
+ }
+
+ // Update item rectangle y position for next item
+ itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING));
+ }
+
+ if (useScrollBar)
+ {
+ int wheelMove = (int)GetMouseWheelMove();
+ startIndex -= wheelMove;
+
+ if (startIndex < 0) startIndex = 0;
+ else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems;
+
+ endIndex = startIndex + visibleItems;
+ if (endIndex > count) endIndex = count;
+ }
+ }
+ else itemFocused = -1;
+
+ // Reset item rectangle y to [0]
+ itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
+
+ // Draw visible items
+ for (int i = 0; ((i < visibleItems) && (text != NULL)); i++)
+ {
+ if (GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL)) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK);
+
+ if (state == STATE_DISABLED)
+ {
+ if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)));
+
+ GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)));
+ }
+ else
+ {
+ if (((startIndex + i) == itemSelected) && (active != NULL))
+ {
+ // Draw item selected
+ GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)));
+ GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)));
+ }
+ else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: We want items focused, despite not returned!
+ {
+ // Draw item focused
+ GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)));
+ GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)));
+ }
+ else
+ {
+ // Draw item normal (no rectangle)
+ GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)));
+ }
+ }
+
+ // Update item rectangle y position for next item
+ itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING));
+ }
+
+ if (useScrollBar)
+ {
+ Rectangle scrollBarBounds = {
+ bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
+ bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
+ bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH)
+ };
+
+ // Calculate percentage of visible items and apply same percentage to scrollbar
+ float percentVisible = (float)(endIndex - startIndex)/count;
+ float sliderSize = bounds.height*percentVisible;
+
+ int prevSliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); // Save default slider size
+ int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)sliderSize); // Change slider size
+ GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed
+
+ startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems);
+
+ GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, prevSliderSize); // Reset slider size to default
+ }
+ //--------------------------------------------------------------------
+
+ if (active != NULL) *active = itemSelected;
+ if (focus != NULL) *focus = itemFocused;
+ if (scrollIndex != NULL) *scrollIndex = startIndex;
+
+ return result;
+}
+
+// Color Panel control - Color (RGBA) variant
+int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
+{
+ int result = 0;
+
+ Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f };
+ Vector3 hsv = ConvertRGBtoHSV(vcolor);
+ Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv
+
+ GuiColorPanelHSV(bounds, text, &hsv);
+
+ // Check if the hsv was changed, only then change the color
+ // This is required, because the Color->HSV->Color conversion has precision errors
+ // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value
+ // Otherwise GuiColorPanel would often modify it's color without user input
+ // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check
+ if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z)
+ {
+ Vector3 rgb = ConvertHSVtoRGB(hsv);
+
+ // NOTE: Vector3ToColor() only available on raylib 1.8.1
+ *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x),
+ (unsigned char)(255.0f*rgb.y),
+ (unsigned char)(255.0f*rgb.z),
+ color->a };
+ }
+ return result;
+}
+
+// Color Bar Alpha control
+// NOTE: Returns alpha value normalized [0..1]
+int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
+{
+ #if !defined(RAYGUI_COLORBARALPHA_CHECKED_SIZE)
+ #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+ Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2,
+ (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW),
+ (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT),
+ (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ {
+ state = STATE_PRESSED;
+
+ *alpha = (mousePoint.x - bounds.x)/bounds.width;
+ if (*alpha <= 0.0f) *alpha = 0.0f;
+ if (*alpha >= 1.0f) *alpha = 1.0f;
+ }
+ }
+ else
+ {
+ guiControlExclusiveMode = false;
+ guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ }
+ }
+ else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ guiControlExclusiveMode = true;
+ guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+
+ *alpha = (mousePoint.x - bounds.x)/bounds.width;
+ if (*alpha <= 0.0f) *alpha = 0.0f;
+ if (*alpha >= 1.0f) *alpha = 1.0f;
+ //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2;
+ }
+ else state = STATE_FOCUSED;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ // Draw alpha bar: checked background
+ if (state != STATE_DISABLED)
+ {
+ int checksX = (int)bounds.width/RAYGUI_COLORBARALPHA_CHECKED_SIZE;
+ int checksY = (int)bounds.height/RAYGUI_COLORBARALPHA_CHECKED_SIZE;
+
+ for (int x = 0; x < checksX; x++)
+ {
+ for (int y = 0; y < checksY; y++)
+ {
+ Rectangle check = { bounds.x + x*RAYGUI_COLORBARALPHA_CHECKED_SIZE, bounds.y + y*RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE };
+ GuiDrawRectangle(check, 0, BLANK, ((x + y)%2)? Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f) : Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f));
+ }
+ }
+
+ DrawRectangleGradientEx(bounds, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha));
+ }
+ else DrawRectangleGradientEx(bounds, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha));
+
+ GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK);
+
+ // Draw alpha bar: selector
+ GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Color Bar Hue control
+// Returns hue value normalized [0..1]
+// NOTE: Other similar bars (for reference):
+// Color GuiColorBarSat() [WHITE->color]
+// Color GuiColorBarValue() [BLACK->color], HSV/HSL
+// float GuiColorBarLuminance() [BLACK->WHITE]
+int GuiColorBarHue(Rectangle bounds, const char *text, float *hue)
+{
+ int result = 0;
+ GuiState state = guiState;
+ Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ {
+ state = STATE_PRESSED;
+
+ *hue = (mousePoint.y - bounds.y)*360/bounds.height;
+ if (*hue <= 0.0f) *hue = 0.0f;
+ if (*hue >= 359.0f) *hue = 359.0f;
+ }
+ }
+ else
+ {
+ guiControlExclusiveMode = false;
+ guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ }
+ }
+ else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ guiControlExclusiveMode = true;
+ guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+
+ *hue = (mousePoint.y - bounds.y)*360/bounds.height;
+ if (*hue <= 0.0f) *hue = 0.0f;
+ if (*hue >= 359.0f) *hue = 359.0f;
+
+ }
+ else state = STATE_FOCUSED;
+
+ /*if (IsKeyDown(KEY_UP))
+ {
+ hue -= 2.0f;
+ if (hue <= 0.0f) hue = 0.0f;
+ }
+ else if (IsKeyDown(KEY_DOWN))
+ {
+ hue += 2.0f;
+ if (hue >= 360.0f) hue = 360.0f;
+ }*/
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state != STATE_DISABLED)
+ {
+ // Draw hue bar:color bars
+ // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1);
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha));
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha));
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha));
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha));
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha));
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha));
+ }
+ else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha));
+
+ GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK);
+
+ // Draw hue bar: selector
+ GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Color Picker control
+// NOTE: It's divided in multiple controls:
+// Color GuiColorPanel(Rectangle bounds, Color color)
+// float GuiColorBarAlpha(Rectangle bounds, float alpha)
+// float GuiColorBarHue(Rectangle bounds, float value)
+// NOTE: bounds define GuiColorPanel() size
+// NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead
+int GuiColorPicker(Rectangle bounds, const char *text, Color *color)
+{
+ int result = 0;
+
+ Color temp = { 200, 0, 0, 255 };
+ if (color == NULL) color = &temp;
+
+ GuiColorPanel(bounds, NULL, color);
+
+ Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height };
+ //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) };
+
+ // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used
+ Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f });
+
+ GuiColorBarHue(boundsHue, NULL, &hsv.x);
+
+ //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f);
+ Vector3 rgb = ConvertHSVtoRGB(hsv);
+
+ *color = RAYGUI_CLITERAL(Color){ (unsigned char)roundf(rgb.x*255.0f), (unsigned char)roundf(rgb.y*255.0f), (unsigned char)roundf(rgb.z*255.0f), (*color).a };
+
+ return result;
+}
+
+// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering
+// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB
+// NOTE: It's divided in multiple controls:
+// int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
+// int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
+// float GuiColorBarHue(Rectangle bounds, float value)
+// NOTE: bounds define GuiColorPanelHSV() size
+int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
+{
+ int result = 0;
+
+ Vector3 tempHsv = { 0 };
+
+ if (colorHsv == NULL)
+ {
+ const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f };
+ tempHsv = ConvertRGBtoHSV(tempColor);
+ colorHsv = &tempHsv;
+ }
+
+ GuiColorPanelHSV(bounds, NULL, colorHsv);
+
+ const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height };
+
+ GuiColorBarHue(boundsHue, NULL, &colorHsv->x);
+
+ return result;
+}
+
+// Color Panel control - HSV variant
+int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
+{
+ int result = 0;
+ GuiState state = guiState;
+ Vector2 pickerSelector = { 0 };
+
+ const Color colWhite = { 255, 255, 255, 255 };
+ const Color colBlack = { 0, 0, 0, 255 };
+
+ pickerSelector.x = bounds.x + (float)colorHsv->y*bounds.width; // HSV: Saturation
+ pickerSelector.y = bounds.y + (1.0f - (float)colorHsv->z)*bounds.height; // HSV: Value
+
+ Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f };
+ Vector3 rgbHue = ConvertHSVtoRGB(maxHue);
+ Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x),
+ (unsigned char)(255.0f*rgbHue.y),
+ (unsigned char)(255.0f*rgbHue.z), 255 };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ {
+ pickerSelector = mousePoint;
+
+ if (pickerSelector.x < bounds.x) pickerSelector.x = bounds.x;
+ if (pickerSelector.x > bounds.x + bounds.width) pickerSelector.x = bounds.x + bounds.width;
+ if (pickerSelector.y < bounds.y) pickerSelector.y = bounds.y;
+ if (pickerSelector.y > bounds.y + bounds.height) pickerSelector.y = bounds.y + bounds.height;
+
+ // Calculate color from picker
+ Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y };
+
+ colorPick.x /= (float)bounds.width; // Get normalized value on x
+ colorPick.y /= (float)bounds.height; // Get normalized value on y
+
+ colorHsv->y = colorPick.x;
+ colorHsv->z = 1.0f - colorPick.y;
+
+ }
+ }
+ else
+ {
+ guiControlExclusiveMode = false;
+ guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ }
+ }
+ else if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ guiControlExclusiveMode = true;
+ guiControlExclusiveRec = bounds;
+ pickerSelector = mousePoint;
+
+ // Calculate color from picker
+ Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y };
+
+ colorPick.x /= (float)bounds.width; // Get normalized value on x
+ colorPick.y /= (float)bounds.height; // Get normalized value on y
+
+ colorHsv->y = colorPick.x;
+ colorHsv->z = 1.0f - colorPick.y;
+ }
+ else state = STATE_FOCUSED;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state != STATE_DISABLED)
+ {
+ DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha));
+ DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0));
+
+ // Draw color picker: selector
+ Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) };
+ GuiDrawRectangle(selector, 0, BLANK, colWhite);
+ }
+ else
+ {
+ DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha));
+ }
+
+ GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK);
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Message Box control
+int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons)
+{
+ #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT)
+ #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24
+ #endif
+ #if !defined(RAYGUI_MESSAGEBOX_BUTTON_PADDING)
+ #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12
+ #endif
+
+ int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button
+
+ int buttonCount = 0;
+ const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
+ Rectangle buttonBounds = { 0 };
+ buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
+ buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING;
+ buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount;
+ buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT;
+
+ //int textWidth = GuiGetTextWidth(message) + 2;
+
+ Rectangle textBounds = { 0 };
+ textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
+ textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
+ textBounds.width = bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*2;
+ textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT;
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (GuiWindowBox(bounds, title)) result = 0;
+
+ int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+ GuiLabel(textBounds, message);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment);
+
+ prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+ for (int i = 0; i < buttonCount; i++)
+ {
+ if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1;
+ buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
+ }
+
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment);
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Text Input Box control, ask for text
+int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive)
+{
+ #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT)
+ #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24
+ #endif
+ #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_PADDING)
+ #define RAYGUI_TEXTINPUTBOX_BUTTON_PADDING 12
+ #endif
+ #if !defined(RAYGUI_TEXTINPUTBOX_HEIGHT)
+ #define RAYGUI_TEXTINPUTBOX_HEIGHT 26
+ #endif
+
+ // Used to enable text edit mode
+ // WARNING: No more than one GuiTextInputBox() should be open at the same time
+ static bool textEditMode = false;
+
+ int result = -1;
+
+ int buttonCount = 0;
+ const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
+ Rectangle buttonBounds = { 0 };
+ buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
+ buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
+ buttonBounds.width = (bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount;
+ buttonBounds.height = RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT;
+
+ int messageInputHeight = (int)bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - 2*RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
+
+ Rectangle textBounds = { 0 };
+ if (message != NULL)
+ {
+ int textSize = GuiGetTextWidth(message) + 2;
+
+ textBounds.x = bounds.x + bounds.width/2 - textSize/2;
+ textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+ textBounds.width = (float)textSize;
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ }
+
+ Rectangle textBoxBounds = { 0 };
+ textBoxBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
+ textBoxBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - RAYGUI_TEXTINPUTBOX_HEIGHT/2;
+ if (message == NULL) textBoxBounds.y = bounds.y + 24 + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
+ else textBoxBounds.y += (messageInputHeight/2 + messageInputHeight/4);
+ textBoxBounds.width = bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*2;
+ textBoxBounds.height = RAYGUI_TEXTINPUTBOX_HEIGHT;
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (GuiWindowBox(bounds, title)) result = 0;
+
+ // Draw message if available
+ if (message != NULL)
+ {
+ int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+ GuiLabel(textBounds, message);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment);
+ }
+
+ if (secretViewActive != NULL)
+ {
+ static char stars[] = "****************";
+ if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height },
+ ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode;
+
+ GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive);
+ }
+ else
+ {
+ if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode;
+ }
+
+ int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+ for (int i = 0; i < buttonCount; i++)
+ {
+ if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1;
+ buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
+ }
+
+ if (result >= 0) textEditMode = false;
+
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment);
+ //--------------------------------------------------------------------
+
+ return result; // Result is the pressed button index
+}
+
+// Grid control
+// NOTE: Returns grid mouse-hover selected cell
+// About drawing lines at subpixel spacing, simple put, not easy solution:
+// https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster
+int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell)
+{
+ // Grid lines alpha amount
+ #if !defined(RAYGUI_GRID_ALPHA)
+ #define RAYGUI_GRID_ALPHA 0.15f
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ Vector2 mousePoint = GetMousePosition();
+ Vector2 currentMouseCell = { -1, -1 };
+
+ float spaceWidth = spacing/(float)subdivs;
+ int linesV = (int)(bounds.width/spaceWidth) + 1;
+ int linesH = (int)(bounds.height/spaceWidth) + 1;
+
+ int color = GuiGetStyle(DEFAULT, LINE_COLOR);
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ // NOTE: Cell values must be the upper left of the cell the mouse is in
+ currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing);
+ currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing);
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state == STATE_DISABLED) color = GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED);
+
+ if (subdivs > 0)
+ {
+ // Draw vertical grid lines
+ for (int i = 0; i < linesV; i++)
+ {
+ Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height + 1 };
+ GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA));
+ }
+
+ // Draw horizontal grid lines
+ for (int i = 0; i < linesH; i++)
+ {
+ Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width + 1, 1 };
+ GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA));
+ }
+ }
+
+ if (mouseCell != NULL) *mouseCell = currentMouseCell;
+ return result;
+}
+
+//----------------------------------------------------------------------------------
+// Tooltip management functions
+// NOTE: Tooltips requires some global variables: tooltipPtr
+//----------------------------------------------------------------------------------
+// Enable gui tooltips (global state)
+void GuiEnableTooltip(void) { guiTooltip = true; }
+
+// Disable gui tooltips (global state)
+void GuiDisableTooltip(void) { guiTooltip = false; }
+
+// Set tooltip string
+void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; }
+
+//----------------------------------------------------------------------------------
+// Styles loading functions
+//----------------------------------------------------------------------------------
+
+// Load raygui style file (.rgs)
+// NOTE: By default a binary file is expected, that file could contain a custom font,
+// in that case, custom font image atlas is GRAY+ALPHA and pixel data can be compressed (DEFLATE)
+void GuiLoadStyle(const char *fileName)
+{
+ #define MAX_LINE_BUFFER_SIZE 256
+
+ bool tryBinary = false;
+ if (!guiStyleLoaded) GuiLoadStyleDefault();
+
+ // Try reading the files as text file first
+ FILE *rgsFile = fopen(fileName, "rt");
+
+ if (rgsFile != NULL)
+ {
+ char buffer[MAX_LINE_BUFFER_SIZE] = { 0 };
+ fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile);
+
+ if (buffer[0] == '#')
+ {
+ int controlId = 0;
+ int propertyId = 0;
+ unsigned int propertyValue = 0;
+
+ while (!feof(rgsFile))
+ {
+ switch (buffer[0])
+ {
+ case 'p':
+ {
+ // Style property: p
+
+ sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
+ GuiSetStyle(controlId, propertyId, (int)propertyValue);
+
+ } break;
+ case 'f':
+ {
+ // Style font: f
+
+ int fontSize = 0;
+ char charmapFileName[256] = { 0 };
+ char fontFileName[256] = { 0 };
+ sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName);
+
+ Font font = { 0 };
+ int *codepoints = NULL;
+ int codepointCount = 0;
+
+ if (charmapFileName[0] != '0')
+ {
+ // Load text data from file
+ // NOTE: Expected an UTF-8 array of codepoints, no separation
+ char *textData = LoadFileText(TextFormat("%s/%s", GetDirectoryPath(fileName), charmapFileName));
+ codepoints = LoadCodepoints(textData, &codepointCount);
+ UnloadFileText(textData);
+ }
+
+ if (fontFileName[0] != '\0')
+ {
+ // In case a font is already loaded and it is not default internal font, unload it
+ if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
+
+ if (codepointCount > 0) font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, codepoints, codepointCount);
+ else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); // Default to 95 standard codepoints
+ }
+
+ // If font texture not properly loaded, revert to default font and size/spacing
+ if (font.texture.id == 0)
+ {
+ font = GetFontDefault();
+ GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
+ GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
+ }
+
+ UnloadCodepoints(codepoints);
+
+ if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font);
+
+ } break;
+ default: break;
+ }
+
+ fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile);
+ }
+ }
+ else tryBinary = true;
+
+ fclose(rgsFile);
+ }
+
+ if (tryBinary)
+ {
+ rgsFile = fopen(fileName, "rb");
+
+ if (rgsFile != NULL)
+ {
+ fseek(rgsFile, 0, SEEK_END);
+ int fileDataSize = ftell(rgsFile);
+ fseek(rgsFile, 0, SEEK_SET);
+
+ if (fileDataSize > 0)
+ {
+ unsigned char *fileData = (unsigned char *)RAYGUI_CALLOC(fileDataSize, sizeof(unsigned char));
+ fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile);
+
+ GuiLoadStyleFromMemory(fileData, fileDataSize);
+
+ RAYGUI_FREE(fileData);
+ }
+
+ fclose(rgsFile);
+ }
+ }
+}
+
+// Load style default over global style
+void GuiLoadStyleDefault(void)
+{
+ // We set this variable first to avoid cyclic function calls
+ // when calling GuiSetStyle() and GuiGetStyle()
+ guiStyleLoaded = true;
+
+ // Initialize default LIGHT style property values
+ // WARNING: Default value are applied to all controls on set but
+ // they can be overwritten later on for every custom control
+ GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff);
+ GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff);
+ GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff);
+ GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff);
+ GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff);
+ GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff);
+ GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff);
+ GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff);
+ GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff);
+ GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff);
+ GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff);
+ GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff);
+ GuiSetStyle(DEFAULT, BORDER_WIDTH, 1);
+ GuiSetStyle(DEFAULT, TEXT_PADDING, 0);
+ GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+ // Initialize default extended property values
+ // NOTE: By default, extended property values are initialized to 0
+ GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls
+ GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls
+ GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property
+ GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property
+ GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 15); // DEFAULT, 15 pixels between lines
+ GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds
+
+ // Initialize control-specific property values
+ // NOTE: Those properties are in default list but require specific values by control type
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, 2);
+ GuiSetStyle(SLIDER, TEXT_PADDING, 4);
+ GuiSetStyle(PROGRESSBAR, TEXT_PADDING, 4);
+ GuiSetStyle(CHECKBOX, TEXT_PADDING, 4);
+ GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT);
+ GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0);
+ GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+ GuiSetStyle(TEXTBOX, TEXT_PADDING, 4);
+ GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+ GuiSetStyle(VALUEBOX, TEXT_PADDING, 0);
+ GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+ GuiSetStyle(STATUSBAR, TEXT_PADDING, 8);
+ GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+
+ // Initialize extended property values
+ // NOTE: By default, extended property values are initialized to 0
+ GuiSetStyle(TOGGLE, GROUP_PADDING, 2);
+ GuiSetStyle(SLIDER, SLIDER_WIDTH, 16);
+ GuiSetStyle(SLIDER, SLIDER_PADDING, 1);
+ GuiSetStyle(PROGRESSBAR, PROGRESS_PADDING, 1);
+ GuiSetStyle(CHECKBOX, CHECK_PADDING, 1);
+ GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 32);
+ GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2);
+ GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16);
+ GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2);
+ GuiSetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH, 24);
+ GuiSetStyle(VALUEBOX, SPINNER_BUTTON_SPACING, 2);
+ GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0);
+ GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0);
+ GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6);
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING, 0);
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, 16);
+ GuiSetStyle(SCROLLBAR, SCROLL_PADDING, 0);
+ GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12);
+ GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28);
+ GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2);
+ GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH, 1);
+ GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12);
+ GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE);
+ GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8);
+ GuiSetStyle(COLORPICKER, HUEBAR_WIDTH, 16);
+ GuiSetStyle(COLORPICKER, HUEBAR_PADDING, 8);
+ GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT, 8);
+ GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW, 2);
+
+ if (guiFont.texture.id != GetFontDefault().texture.id)
+ {
+ // Unload previous font texture
+ UnloadTexture(guiFont.texture);
+ RAYGUI_FREE(guiFont.recs);
+ RAYGUI_FREE(guiFont.glyphs);
+ guiFont.recs = NULL;
+ guiFont.glyphs = NULL;
+
+ // Setup default raylib font
+ guiFont = GetFontDefault();
+
+ // NOTE: Default raylib font character 95 is a white square
+ Rectangle whiteChar = guiFont.recs[95];
+
+ // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
+ SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 });
+ }
+}
+
+// Get text with icon id prepended
+// NOTE: Useful to add icons by name id (enum) instead of
+// a number that can change between ricon versions
+const char *GuiIconText(int iconId, const char *text)
+{
+#if defined(RAYGUI_NO_ICONS)
+ return NULL;
+#else
+ static char buffer[1024] = { 0 };
+ static char iconBuffer[16] = { 0 };
+
+ if (text != NULL)
+ {
+ memset(buffer, 0, 1024);
+ snprintf(buffer, 1024, "#%03i#", iconId);
+
+ for (int i = 5; i < 1024; i++)
+ {
+ buffer[i] = text[i - 5];
+ if (text[i - 5] == '\0') break;
+ }
+
+ return buffer;
+ }
+ else
+ {
+ snprintf(iconBuffer, 16, "#%03i#", iconId);
+
+ return iconBuffer;
+ }
+#endif
+}
+
+#if !defined(RAYGUI_NO_ICONS)
+// Get full icons data pointer
+unsigned int *GuiGetIcons(void) { return guiIconsPtr; }
+
+// Load raygui icons file (.rgi)
+// NOTE: In case nameIds are required, they can be requested with loadIconsName,
+// they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH],
+// WARNING: guiIconsName[]][] memory should be manually freed!
+char **GuiLoadIcons(const char *fileName, bool loadIconsName)
+{
+ // Style File Structure (.rgi)
+ // ------------------------------------------------------
+ // Offset | Size | Type | Description
+ // ------------------------------------------------------
+ // 0 | 4 | char | Signature: "rGI "
+ // 4 | 2 | short | Version: 100
+ // 6 | 2 | short | reserved
+
+ // 8 | 2 | short | Num icons (N)
+ // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S)
+
+ // Icons name id (32 bytes per name id)
+ // foreach (icon)
+ // {
+ // 12+32*i | 32 | char | Icon NameId
+ // }
+
+ // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size)
+ // S*S pixels/32bit per unsigned int = K unsigned int per icon
+ // foreach (icon)
+ // {
+ // ... | K | unsigned int | Icon Data
+ // }
+
+ FILE *rgiFile = fopen(fileName, "rb");
+
+ char **guiIconsName = NULL;
+
+ if (rgiFile != NULL)
+ {
+ char signature[5] = { 0 };
+ short version = 0;
+ short reserved = 0;
+ short iconCount = 0;
+ short iconSize = 0;
+
+ fread(signature, 1, 4, rgiFile);
+ fread(&version, sizeof(short), 1, rgiFile);
+ fread(&reserved, sizeof(short), 1, rgiFile);
+ fread(&iconCount, sizeof(short), 1, rgiFile);
+ fread(&iconSize, sizeof(short), 1, rgiFile);
+
+ if ((signature[0] == 'r') &&
+ (signature[1] == 'G') &&
+ (signature[2] == 'I') &&
+ (signature[3] == ' '))
+ {
+ if (loadIconsName)
+ {
+ guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *));
+ for (int i = 0; i < iconCount; i++)
+ {
+ guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char));
+ fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile);
+ }
+ }
+ else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR);
+
+ // Read icons data directly over internal icons array
+ fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile);
+ }
+
+ fclose(rgiFile);
+ }
+
+ return guiIconsName;
+}
+
+// Load icons from memory
+// WARNING: Binary files only
+char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName)
+{
+ unsigned char *fileDataPtr = (unsigned char *)fileData;
+ char **guiIconsName = NULL;
+
+ char signature[5] = { 0 };
+ short version = 0;
+ short reserved = 0;
+ short iconCount = 0;
+ short iconSize = 0;
+
+ memcpy(signature, fileDataPtr, 4);
+ memcpy(&version, fileDataPtr + 4, sizeof(short));
+ memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short));
+ memcpy(&iconCount, fileDataPtr + 4 + 2 + 2, sizeof(short));
+ memcpy(&iconSize, fileDataPtr + 4 + 2 + 2 + 2, sizeof(short));
+ fileDataPtr += 12;
+
+ if ((signature[0] == 'r') &&
+ (signature[1] == 'G') &&
+ (signature[2] == 'I') &&
+ (signature[3] == ' '))
+ {
+ if (loadIconsName)
+ {
+ guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *));
+ for (int i = 0; i < iconCount; i++)
+ {
+ guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char));
+ memcpy(guiIconsName[i], fileDataPtr, RAYGUI_ICON_MAX_NAME_LENGTH);
+ fileDataPtr += RAYGUI_ICON_MAX_NAME_LENGTH;
+ }
+ }
+ else
+ {
+ // Skip icon name data if not required
+ fileDataPtr += iconCount*RAYGUI_ICON_MAX_NAME_LENGTH;
+ }
+
+ int iconDataSize = iconCount*((int)iconSize*(int)iconSize/32)*(int)sizeof(unsigned int);
+ guiIconsPtr = (unsigned int *)RAYGUI_CALLOC(iconDataSize, 1);
+
+ memcpy(guiIconsPtr, fileDataPtr, iconDataSize);
+ }
+
+ return guiIconsName;
+}
+
+// Draw selected icon using rectangles pixel-by-pixel
+void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color)
+{
+ #define BIT_CHECK(a,b) ((a) & (1u<<(b)))
+
+ for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++)
+ {
+ for (int k = 0; k < 32; k++)
+ {
+ if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k))
+ {
+ #if !defined(RAYGUI_STANDALONE)
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color);
+ #endif
+ }
+
+ if ((k == 15) || (k == 31)) y++;
+ }
+ }
+}
+
+// Set icon drawing size
+void GuiSetIconScale(int scale)
+{
+ if (scale >= 1) guiIconScale = scale;
+}
+
+// Get text width considering gui style and icon size (if required)
+int GuiGetTextWidth(const char *text)
+{
+ #if !defined(ICON_TEXT_PADDING)
+ #define ICON_TEXT_PADDING 4
+ #endif
+
+ Vector2 textSize = { 0 };
+ int textIconOffset = 0;
+
+ if ((text != NULL) && (text[0] != '\0'))
+ {
+ if (text[0] == '#')
+ {
+ for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
+ {
+ if (text[i] == '#')
+ {
+ textIconOffset = i;
+ break;
+ }
+ }
+ }
+
+ text += textIconOffset;
+
+ // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
+ float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+
+ // Custom MeasureText() implementation
+ if ((guiFont.texture.id > 0) && (text != NULL))
+ {
+ // Get size in bytes of text, considering end of line and line break
+ int size = 0;
+ for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++)
+ {
+ if ((text[i] != '\0') && (text[i] != '\n')) size++;
+ else break;
+ }
+
+ float scaleFactor = fontSize/(float)guiFont.baseSize;
+ textSize.y = (float)guiFont.baseSize*scaleFactor;
+ float glyphWidth = 0.0f;
+
+ for (int i = 0, codepointSize = 0; i < size; i += codepointSize)
+ {
+ int codepoint = GetCodepointNext(&text[i], &codepointSize);
+ int codepointIndex = GetGlyphIndex(guiFont, codepoint);
+
+ if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
+ else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
+
+ textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ }
+ }
+
+ if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING);
+ }
+
+ return (int)textSize.x;
+}
+
+#endif // !RAYGUI_NO_ICONS
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+// Load style from memory
+// WARNING: Binary files only
+static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
+{
+ unsigned char *fileDataPtr = (unsigned char *)fileData;
+
+ char signature[5] = { 0 };
+ short version = 0;
+ short reserved = 0;
+ int propertyCount = 0;
+
+ memcpy(signature, fileDataPtr, 4);
+ memcpy(&version, fileDataPtr + 4, sizeof(short));
+ memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short));
+ memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int));
+ fileDataPtr += 12;
+
+ if ((signature[0] == 'r') &&
+ (signature[1] == 'G') &&
+ (signature[2] == 'S') &&
+ (signature[3] == ' '))
+ {
+ short controlId = 0;
+ short propertyId = 0;
+ unsigned int propertyValue = 0;
+
+ for (int i = 0; i < propertyCount; i++)
+ {
+ memcpy(&controlId, fileDataPtr, sizeof(short));
+ memcpy(&propertyId, fileDataPtr + 2, sizeof(short));
+ memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int));
+ fileDataPtr += 8;
+
+ if (controlId == 0) // DEFAULT control
+ {
+ // If a DEFAULT property is loaded, it is propagated to all controls
+ // NOTE: All DEFAULT properties should be defined first in the file
+ GuiSetStyle(0, (int)propertyId, propertyValue);
+
+ if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue);
+ }
+ else GuiSetStyle((int)controlId, (int)propertyId, propertyValue);
+ }
+
+ // Font loading is highly dependant on raylib API to load font data and image
+
+#if !defined(RAYGUI_STANDALONE)
+ // Load custom font if available
+ int fontDataSize = 0;
+ memcpy(&fontDataSize, fileDataPtr, sizeof(int));
+ fileDataPtr += 4;
+
+ if (fontDataSize > 0)
+ {
+ Font font = { 0 };
+ int fontType = 0; // 0-Normal, 1-SDF
+
+ memcpy(&font.baseSize, fileDataPtr, sizeof(int));
+ memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int));
+ memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int));
+ fileDataPtr += 12;
+
+ // Load font white rectangle
+ Rectangle fontWhiteRec = { 0 };
+ memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle));
+ fileDataPtr += 16;
+
+ // Load font image parameters
+ int fontImageUncompSize = 0;
+ int fontImageCompSize = 0;
+ memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int));
+ memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int));
+ fileDataPtr += 8;
+
+ Image imFont = { 0 };
+ imFont.mipmaps = 1;
+ memcpy(&imFont.width, fileDataPtr, sizeof(int));
+ memcpy(&imFont.height, fileDataPtr + 4, sizeof(int));
+ memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int));
+ fileDataPtr += 12;
+
+ if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize))
+ {
+ // Compressed font atlas image data (DEFLATE), it requires DecompressData()
+ int dataUncompSize = 0;
+ unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char));
+ memcpy(compData, fileDataPtr, fontImageCompSize);
+ fileDataPtr += fontImageCompSize;
+
+ imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize);
+
+ // Security check, dataUncompSize must match the provided fontImageUncompSize
+ if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted");
+
+ RAYGUI_FREE(compData);
+ }
+ else
+ {
+ // Font atlas image data is not compressed
+ imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char));
+ memcpy(imFont.data, fileDataPtr, fontImageUncompSize);
+ fileDataPtr += fontImageUncompSize;
+ }
+
+ if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
+ font.texture = LoadTextureFromImage(imFont);
+
+ RAYGUI_FREE(imFont.data);
+
+ // Validate font atlas texture was loaded correctly
+ if (font.texture.id != 0)
+ {
+ // Load font recs data
+ int recsDataSize = font.glyphCount*sizeof(Rectangle);
+ int recsDataCompressedSize = 0;
+
+ // WARNING: Version 400 adds the compression size parameter
+ if (version >= 400)
+ {
+ // RGS files version 400 support compressed recs data
+ memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int));
+ fileDataPtr += sizeof(int);
+ }
+
+ if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize))
+ {
+ // Recs data is compressed, uncompress it
+ unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char));
+
+ memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize);
+ fileDataPtr += recsDataCompressedSize;
+
+ int recsDataUncompSize = 0;
+ font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize);
+
+ // Security check, data uncompressed size must match the expected original data size
+ if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted");
+
+ RAYGUI_FREE(recsDataCompressed);
+ }
+ else
+ {
+ // Recs data is uncompressed
+ font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
+ for (int i = 0; i < font.glyphCount; i++)
+ {
+ memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle));
+ fileDataPtr += sizeof(Rectangle);
+ }
+ }
+
+ // Load font glyphs info data
+ int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph
+ int glyphsDataCompressedSize = 0;
+
+ // WARNING: Version 400 adds the compression size parameter
+ if (version >= 400)
+ {
+ // RGS files version 400 support compressed glyphs data
+ memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int));
+ fileDataPtr += sizeof(int);
+ }
+
+ // Allocate required glyphs space to fill with data
+ font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
+
+ if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize))
+ {
+ // Glyphs data is compressed, uncompress it
+ unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char));
+
+ memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize);
+ fileDataPtr += glyphsDataCompressedSize;
+
+ int glyphsDataUncompSize = 0;
+ unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize);
+
+ // Security check, data uncompressed size must match the expected original data size
+ if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted");
+
+ unsigned char *glyphsDataUncompPtr = glyphsDataUncomp;
+
+ for (int i = 0; i < font.glyphCount; i++)
+ {
+ memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int));
+ memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int));
+ memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int));
+ memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int));
+ glyphsDataUncompPtr += 16;
+ }
+
+ RAYGUI_FREE(glypsDataCompressed);
+ RAYGUI_FREE(glyphsDataUncomp);
+ }
+ else
+ {
+ // Glyphs data is uncompressed
+ for (int i = 0; i < font.glyphCount; i++)
+ {
+ memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int));
+ memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int));
+ memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int));
+ memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int));
+ fileDataPtr += 16;
+ }
+ }
+ }
+ else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture
+
+ GuiSetFont(font);
+
+ // Set font texture source rectangle to be used as white texture to draw shapes
+ // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call
+ if ((fontWhiteRec.x > 0) &&
+ (fontWhiteRec.y > 0) &&
+ (fontWhiteRec.width > 0) &&
+ (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec);
+ }
+#endif
+ }
+}
+
+// Get text bounds considering control bounds
+static Rectangle GetTextBounds(int control, Rectangle bounds)
+{
+ Rectangle textBounds = bounds;
+
+ textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH);
+ textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, TEXT_PADDING);
+ textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING);
+ textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); // NOTE: Text is processed line per line!
+
+ // Depending on control, TEXT_PADDING and TEXT_ALIGNMENT properties could affect the text-bounds
+ switch (control)
+ {
+ case COMBOBOX:
+ case DROPDOWNBOX:
+ case LISTVIEW:
+ // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW
+ case SLIDER:
+ case CHECKBOX:
+ case VALUEBOX:
+ case CONTROL11:
+ // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER
+ default:
+ {
+ // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText()
+ if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING);
+ else textBounds.x += GuiGetStyle(control, TEXT_PADDING);
+ }
+ break;
+ }
+
+ return textBounds;
+}
+
+// Get text icon if provided and move text cursor
+// NOTE: We support up to 999 values for iconId
+static const char *GetTextIcon(const char *text, int *iconId)
+{
+#if !defined(RAYGUI_NO_ICONS)
+ *iconId = -1;
+ if (text[0] == '#') // Maybe we have an icon!
+ {
+ char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0'
+
+ int pos = 1;
+ while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9'))
+ {
+ iconValue[pos - 1] = text[pos];
+ pos++;
+ }
+
+ if (text[pos] == '#')
+ {
+ *iconId = TextToInteger(iconValue);
+
+ // Move text pointer after icon
+ // WARNING: If only icon provided, it could point to EOL character: '\0'
+ if (*iconId >= 0) text += (pos + 1);
+ }
+ }
+#endif
+
+ return text;
+}
+
+// Get text divided into lines (by line-breaks '\n')
+// WARNING: It returns pointers to new lines but it does not add NULL ('\0') terminator!
+static const char **GetTextLines(const char *text, int *count)
+{
+ #define RAYGUI_MAX_TEXT_LINES 128
+
+ static const char *lines[RAYGUI_MAX_TEXT_LINES] = { 0 };
+ for (int i = 0; i < RAYGUI_MAX_TEXT_LINES; i++) lines[i] = NULL; // Init NULL pointers to substrings
+
+ int textSize = (int)strlen(text);
+
+ lines[0] = text;
+ *count = 1;
+
+ for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
+ {
+ if (text[i] == '\n')
+ {
+ k++;
+ lines[k] = &text[i + 1]; // WARNING: next value is valid?
+ *count += 1;
+ }
+ }
+
+ return lines;
+}
+
+// Get text width to next space for provided string
+static float GetNextSpaceWidth(const char *text, int *nextSpaceIndex)
+{
+ float width = 0;
+ int codepointByteCount = 0;
+ int codepoint = 0;
+ int index = 0;
+ float glyphWidth = 0;
+ float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize;
+
+ for (int i = 0; text[i] != '\0'; i++)
+ {
+ if (text[i] != ' ')
+ {
+ codepoint = GetCodepoint(&text[i], &codepointByteCount);
+ index = GetGlyphIndex(guiFont, codepoint);
+ glyphWidth = (guiFont.glyphs[index].advanceX == 0)? guiFont.recs[index].width*scaleFactor : guiFont.glyphs[index].advanceX*scaleFactor;
+ width += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ }
+ else
+ {
+ *nextSpaceIndex = i;
+ break;
+ }
+ }
+
+ return width;
+}
+
+// Gui draw text using default font
+static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint)
+{
+ #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect
+
+ #if !defined(ICON_TEXT_PADDING)
+ #define ICON_TEXT_PADDING 4
+ #endif
+
+ if ((text == NULL) || (text[0] == '\0')) return; // Security check
+
+ // PROCEDURE:
+ // - Text is processed line per line
+ // - For every line, horizontal alignment is defined
+ // - For all text, vertical alignment is defined (multiline text only)
+ // - For every line, wordwrap mode is checked (useful for GuitextBox(), read-only)
+
+ // Get text lines (using '\n' as delimiter) to be processed individually
+ // WARNING: We can't use GuiTextSplit() function because it can be already used
+ // before the GuiDrawText() call and its buffer is static, it would be overriden :(
+ int lineCount = 0;
+ const char **lines = GetTextLines(text, &lineCount);
+
+ // Text style variables
+ //int alignment = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT);
+ int alignmentVertical = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL);
+ int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); // Wrap-mode only available in read-only mode, no for text editing
+
+ // TODO: WARNING: This totalHeight is not valid for vertical alignment in case of word-wrap
+ float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_SIZE)/2);
+ float posOffsetY = 0.0f;
+
+ for (int i = 0; i < lineCount; i++)
+ {
+ int iconId = 0;
+ lines[i] = GetTextIcon(lines[i], &iconId); // Check text for icon and move cursor
+
+ // Get text position depending on alignment and iconId
+ //---------------------------------------------------------------------------------
+ Vector2 textBoundsPosition = { textBounds.x, textBounds.y };
+ float textBoundsWidthOffset = 0.0f;
+
+ // NOTE: We get text size after icon has been processed
+ // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed?
+ int textSizeX = GuiGetTextWidth(lines[i]);
+
+ // If text requires an icon, add size to measure
+ if (iconId >= 0)
+ {
+ textSizeX += RAYGUI_ICON_SIZE*guiIconScale;
+
+ // WARNING: If only icon provided, text could be pointing to EOF character: '\0'
+#if !defined(RAYGUI_NO_ICONS)
+ if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING;
+#endif
+ }
+
+ // Check guiTextAlign global variables
+ switch (alignment)
+ {
+ case TEXT_ALIGN_LEFT: textBoundsPosition.x = textBounds.x; break;
+ case TEXT_ALIGN_CENTER: textBoundsPosition.x = textBounds.x + textBounds.width/2 - textSizeX/2; break;
+ case TEXT_ALIGN_RIGHT: textBoundsPosition.x = textBounds.x + textBounds.width - textSizeX; break;
+ default: break;
+ }
+
+ if (textSizeX > textBounds.width && (lines[i] != NULL) && (lines[i][0] != '\0')) textBoundsPosition.x = textBounds.x;
+
+ switch (alignmentVertical)
+ {
+ // Only valid in case of wordWrap = 0;
+ case TEXT_ALIGN_TOP: textBoundsPosition.y = textBounds.y + posOffsetY; break;
+ case TEXT_ALIGN_MIDDLE: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break;
+ case TEXT_ALIGN_BOTTOM: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height - totalHeight + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break;
+ default: break;
+ }
+
+ // NOTE: Make sure we get pixel-perfect coordinates,
+ // In case of decimals we got weird text positioning
+ textBoundsPosition.x = (float)((int)textBoundsPosition.x);
+ textBoundsPosition.y = (float)((int)textBoundsPosition.y);
+ //---------------------------------------------------------------------------------
+
+ // Draw text (with icon if available)
+ //---------------------------------------------------------------------------------
+#if !defined(RAYGUI_NO_ICONS)
+ if (iconId >= 0)
+ {
+ // NOTE: We consider icon height, probably different than text size
+ GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint);
+ textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
+ textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
+ }
+#endif
+ // Get size in bytes of text,
+ // considering end of line and line break
+ int lineSize = 0;
+ for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ }
+ float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize;
+
+ int lastSpaceIndex = 0;
+ bool tempWrapCharMode = false;
+
+ int textOffsetY = 0;
+ float textOffsetX = 0.0f;
+ float glyphWidth = 0;
+
+ int ellipsisWidth = GuiGetTextWidth("...");
+ bool textOverflow = false;
+ for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize)
+ {
+ int codepoint = GetCodepointNext(&lines[i][c], &codepointSize);
+ int index = GetGlyphIndex(guiFont, codepoint);
+
+ // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
+ // but we need to draw all of the bad bytes using the '?' symbol moving one byte
+ if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size
+
+ // Get glyph width to check if it goes out of bounds
+ if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor);
+ else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor;
+
+ // Wrap mode text measuring, to validate if
+ // it can be drawn or a new line is required
+ if (wrapMode == TEXT_WRAP_CHAR)
+ {
+ // Jump to next line if current character reach end of the box limits
+ if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset)
+ {
+ textOffsetX = 0.0f;
+ textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
+
+ if (tempWrapCharMode) // Wrap at char level when too long words
+ {
+ wrapMode = TEXT_WRAP_WORD;
+ tempWrapCharMode = false;
+ }
+ }
+ }
+ else if (wrapMode == TEXT_WRAP_WORD)
+ {
+ if (codepoint == 32) lastSpaceIndex = c;
+
+ // Get width to next space in line
+ int nextSpaceIndex = 0;
+ float nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex);
+
+ int nextSpaceIndex2 = 0;
+ float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2);
+
+ if (nextWordSize > textBounds.width - textBoundsWidthOffset)
+ {
+ // Considering the case the next word is longer than bounds
+ tempWrapCharMode = true;
+ wrapMode = TEXT_WRAP_CHAR;
+ }
+ else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset)
+ {
+ textOffsetX = 0.0f;
+ textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
+ }
+ }
+
+ if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint
+ else
+ {
+ // TODO: There are multiple types of spaces in Unicode,
+ // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html
+ if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph
+ {
+ if (wrapMode == TEXT_WRAP_NONE)
+ {
+ // Draw only required text glyphs fitting the textBounds.width
+ if (textSizeX > textBounds.width)
+ {
+ if (textOffsetX <= (textBounds.width - glyphWidth - textBoundsWidthOffset - ellipsisWidth))
+ {
+ DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
+ }
+ else if (!textOverflow)
+ {
+ textOverflow = true;
+
+ for (int j = 0; j < ellipsisWidth; j += ellipsisWidth/3)
+ {
+ DrawTextCodepoint(guiFont, '.', RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX + j, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
+ }
+ }
+ }
+ else
+ {
+ DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
+ }
+ }
+ else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD))
+ {
+ // Draw only glyphs inside the bounds
+ if ((textBoundsPosition.y + textOffsetY) <= (textBounds.y + textBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE)))
+ {
+ DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
+ }
+ }
+ }
+
+ if (guiFont.glyphs[index].advanceX == 0) textOffsetX += ((float)guiFont.recs[index].width*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ else textOffsetX += ((float)guiFont.glyphs[index].advanceX*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ }
+ }
+
+ if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
+ else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING));
+ //---------------------------------------------------------------------------------
+ }
+
+#if defined(RAYGUI_DEBUG_TEXT_BOUNDS)
+ GuiDrawRectangle(textBounds, 0, WHITE, Fade(BLUE, 0.4f));
+#endif
+}
+
+// Gui draw rectangle using default raygui plain style with borders
+static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color)
+{
+ if (color.a > 0)
+ {
+ // Draw rectangle filled with color
+ DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, GuiFade(color, guiAlpha));
+ }
+
+ if (borderWidth > 0)
+ {
+ // Draw rectangle border lines with color
+ DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha));
+ DrawRectangle((int)rec.x, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha));
+ DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha));
+ DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha));
+ }
+
+#if defined(RAYGUI_DEBUG_RECS_BOUNDS)
+ DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, Fade(RED, 0.4f));
+#endif
+}
+
+// Draw tooltip using control bounds
+static void GuiTooltip(Rectangle controlRec)
+{
+ if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode)
+ {
+ Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+
+ if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width);
+
+ GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, NULL);
+
+ int textPadding = GuiGetStyle(LABEL, TEXT_PADDING);
+ int textAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
+ GuiSetStyle(LABEL, TEXT_PADDING, 0);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+ GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, guiTooltipPtr);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment);
+ GuiSetStyle(LABEL, TEXT_PADDING, textPadding);
+ }
+}
+
+// Split controls text into multiple strings
+// Also check for multiple columns (required by GuiToggleGroup())
+static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow)
+{
+ // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
+ // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
+ // all used memory is static... it has some limitations:
+ // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS
+ // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE
+ // NOTE: Those definitions could be externally provided if required
+
+ // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user
+ // textRow is an externally provided array of integers that stores row number for every splitted string
+
+ #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS)
+ #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128
+ #endif
+ #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE)
+ #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024
+ #endif
+
+ static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data)
+ static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added)
+ memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE);
+
+ result[0] = buffer;
+ int counter = 1;
+
+ if (textRow != NULL) textRow[0] = 0;
+
+ // Count how many substrings we have on text and point to every one
+ for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++)
+ {
+ buffer[i] = text[i];
+ if (buffer[i] == '\0') break;
+ else if ((buffer[i] == delimiter) || (buffer[i] == '\n'))
+ {
+ result[counter] = buffer + i + 1;
+
+ if (textRow != NULL)
+ {
+ if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1;
+ else textRow[counter] = textRow[counter - 1];
+ }
+
+ buffer[i] = '\0'; // Set an end of string at this point
+
+ counter++;
+ if (counter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
+ }
+ }
+
+ *count = counter;
+
+ return result;
+}
+
+// Convert color data from RGB to HSV
+// NOTE: Color data should be passed normalized
+static Vector3 ConvertRGBtoHSV(Vector3 rgb)
+{
+ Vector3 hsv = { 0 };
+ float min = 0.0f;
+ float max = 0.0f;
+ float delta = 0.0f;
+
+ min = (rgb.x < rgb.y)? rgb.x : rgb.y;
+ min = (min < rgb.z)? min : rgb.z;
+
+ max = (rgb.x > rgb.y)? rgb.x : rgb.y;
+ max = (max > rgb.z)? max : rgb.z;
+
+ hsv.z = max; // Value
+ delta = max - min;
+
+ if (delta < 0.00001f)
+ {
+ hsv.y = 0.0f;
+ hsv.x = 0.0f; // Undefined, maybe NAN?
+ return hsv;
+ }
+
+ if (max > 0.0f)
+ {
+ // NOTE: If max is 0, this divide would cause a crash
+ hsv.y = (delta/max); // Saturation
+ }
+ else
+ {
+ // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
+ hsv.y = 0.0f;
+ hsv.x = 0.0f; // Undefined, maybe NAN?
+ return hsv;
+ }
+
+ // NOTE: Comparing float values could not work properly
+ if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
+ else
+ {
+ if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
+ else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
+ }
+
+ hsv.x *= 60.0f; // Convert to degrees
+
+ if (hsv.x < 0.0f) hsv.x += 360.0f;
+
+ return hsv;
+}
+
+// Convert color data from HSV to RGB
+// NOTE: Color data should be passed normalized
+static Vector3 ConvertHSVtoRGB(Vector3 hsv)
+{
+ Vector3 rgb = { 0 };
+ float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f;
+ long i = 0;
+
+ // NOTE: Comparing float values could not work properly
+ if (hsv.y <= 0.0f)
+ {
+ rgb.x = hsv.z;
+ rgb.y = hsv.z;
+ rgb.z = hsv.z;
+ return rgb;
+ }
+
+ hh = hsv.x;
+ if (hh >= 360.0f) hh = 0.0f;
+ hh /= 60.0f;
+
+ i = (long)hh;
+ ff = hh - i;
+ p = hsv.z*(1.0f - hsv.y);
+ q = hsv.z*(1.0f - (hsv.y*ff));
+ t = hsv.z*(1.0f - (hsv.y*(1.0f - ff)));
+
+ switch (i)
+ {
+ case 0:
+ {
+ rgb.x = hsv.z;
+ rgb.y = t;
+ rgb.z = p;
+ } break;
+ case 1:
+ {
+ rgb.x = q;
+ rgb.y = hsv.z;
+ rgb.z = p;
+ } break;
+ case 2:
+ {
+ rgb.x = p;
+ rgb.y = hsv.z;
+ rgb.z = t;
+ } break;
+ case 3:
+ {
+ rgb.x = p;
+ rgb.y = q;
+ rgb.z = hsv.z;
+ } break;
+ case 4:
+ {
+ rgb.x = t;
+ rgb.y = p;
+ rgb.z = hsv.z;
+ } break;
+ case 5:
+ default:
+ {
+ rgb.x = hsv.z;
+ rgb.y = p;
+ rgb.z = q;
+ } break;
+ }
+
+ return rgb;
+}
+
+// Scroll bar control (used by GuiScrollPanel())
+static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
+{
+ GuiState state = guiState;
+
+ // Is the scrollbar horizontal or vertical?
+ bool isVertical = (bounds.width > bounds.height)? false : true;
+
+ // The size (width or height depending on scrollbar type) of the spinner buttons
+ const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)?
+ (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) :
+ (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0;
+
+ // Arrow buttons [<] [>] [∧] [∨]
+ Rectangle arrowUpLeft = { 0 };
+ Rectangle arrowDownRight = { 0 };
+
+ // Actual area of the scrollbar excluding the arrow buttons
+ Rectangle scrollbar = { 0 };
+
+ // Slider bar that moves --[///]-----
+ Rectangle slider = { 0 };
+
+ // Normalize value
+ if (value > maxValue) value = maxValue;
+ if (value < minValue) value = minValue;
+
+ int valueRange = maxValue - minValue;
+ if (valueRange <= 0) valueRange = 1;
+
+ int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE);
+ if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size
+
+ // Calculate rectangles for all of the components
+ arrowUpLeft = RAYGUI_CLITERAL(Rectangle){
+ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH),
+ (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH),
+ (float)spinnerSize, (float)spinnerSize };
+
+ if (isVertical)
+ {
+ arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize };
+ scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) };
+
+ // Make sure the slider won't get outside of the scrollbar
+ sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize;
+ slider = RAYGUI_CLITERAL(Rectangle){
+ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING),
+ scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)),
+ bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)),
+ (float)sliderSize };
+ }
+ else // horizontal
+ {
+ arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize };
+ scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) };
+
+ // Make sure the slider won't get outside of the scrollbar
+ sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize;
+ slider = RAYGUI_CLITERAL(Rectangle){
+ scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)),
+ bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING),
+ (float)sliderSize,
+ bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) };
+ }
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) &&
+ !CheckCollisionPointRec(mousePoint, arrowUpLeft) &&
+ !CheckCollisionPointRec(mousePoint, arrowDownRight))
+ {
+ if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ {
+ state = STATE_PRESSED;
+
+ if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue);
+ else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue);
+ }
+ }
+ else
+ {
+ guiControlExclusiveMode = false;
+ guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ }
+ }
+ else if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ state = STATE_FOCUSED;
+
+ // Handle mouse wheel
+ int wheel = (int)GetMouseWheelMove();
+ if (wheel != 0) value += wheel;
+
+ // Handle mouse button down
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ guiControlExclusiveMode = true;
+ guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+
+ // Check arrows click
+ if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ else if (!CheckCollisionPointRec(mousePoint, slider))
+ {
+ // If click on scrollbar position but not on slider, place slider directly on that position
+ if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue);
+ else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue);
+ }
+
+ state = STATE_PRESSED;
+ }
+
+ // Keyboard control on mouse hover scrollbar
+ /*
+ if (isVertical)
+ {
+ if (IsKeyDown(KEY_DOWN)) value += 5;
+ else if (IsKeyDown(KEY_UP)) value -= 5;
+ }
+ else
+ {
+ if (IsKeyDown(KEY_RIGHT)) value += 5;
+ else if (IsKeyDown(KEY_LEFT)) value -= 5;
+ }
+ */
+ }
+
+ // Normalize value
+ if (value > maxValue) value = maxValue;
+ if (value < minValue) value = minValue;
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background
+
+ GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background
+ GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar
+
+ // Draw arrows (using icon if available)
+ if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE))
+ {
+#if defined(RAYGUI_NO_ICONS)
+ GuiDrawText(isVertical? "^" : "<",
+ RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
+ GuiDrawText(isVertical? "v" : ">",
+ RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
+#else
+ GuiDrawText(isVertical? "#121#" : "#118#",
+ RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL
+ GuiDrawText(isVertical? "#120#" : "#119#",
+ RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL
+#endif
+ }
+ //--------------------------------------------------------------------
+
+ return value;
+}
+
+// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
+// WARNING: It multiplies current alpha by alpha scale factor
+static Color GuiFade(Color color, float alpha)
+{
+ if (alpha < 0.0f) alpha = 0.0f;
+ else if (alpha > 1.0f) alpha = 1.0f;
+
+ Color result = { color.r, color.g, color.b, (unsigned char)(color.a*alpha) };
+
+ return result;
+}
+
+#if defined(RAYGUI_STANDALONE)
+// Returns a Color struct from hexadecimal value
+static Color GetColor(int hexValue)
+{
+ Color color;
+
+ color.r = (unsigned char)(hexValue >> 24) & 0xff;
+ color.g = (unsigned char)(hexValue >> 16) & 0xff;
+ color.b = (unsigned char)(hexValue >> 8) & 0xff;
+ color.a = (unsigned char)hexValue & 0xff;
+
+ return color;
+}
+
+// Returns hexadecimal value for a Color
+static int ColorToInt(Color color)
+{
+ return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
+}
+
+// Check if point is inside rectangle
+static bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
+{
+ bool collision = false;
+
+ if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) &&
+ (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true;
+
+ return collision;
+}
+
+// Formatting of text with variables to 'embed'
+static const char *TextFormat(const char *text, ...)
+{
+ #if !defined(RAYGUI_TEXTFORMAT_MAX_SIZE)
+ #define RAYGUI_TEXTFORMAT_MAX_SIZE 256
+ #endif
+
+ static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE];
+
+ va_list args;
+ va_start(args, text);
+ vsnprintf(buffer, RAYGUI_TEXTFORMAT_MAX_SIZE, text, args);
+ va_end(args);
+
+ return buffer;
+}
+
+// Draw rectangle with vertical gradient fill color
+// NOTE: This function is only used by GuiColorPicker()
+static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2)
+{
+ Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height };
+ DrawRectangleGradientEx(bounds, color1, color2, color2, color1);
+}
+
+// Split string into multiple strings
+const char **TextSplit(const char *text, char delimiter, int *count)
+{
+ // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
+ // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
+ // all used memory is static... it has some limitations:
+ // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS
+ // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE
+
+ #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS)
+ #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128
+ #endif
+ #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE)
+ #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024
+ #endif
+
+ static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL };
+ static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 };
+ memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE);
+
+ result[0] = buffer;
+ int counter = 0;
+
+ if (text != NULL)
+ {
+ counter = 1;
+
+ // Count how many substrings we have on text and point to every one
+ for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++)
+ {
+ buffer[i] = text[i];
+ if (buffer[i] == '\0') break;
+ else if (buffer[i] == delimiter)
+ {
+ buffer[i] = '\0'; // Set an end of string at this point
+ result[counter] = buffer + i + 1;
+ counter++;
+
+ if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
+ }
+ }
+ }
+
+ *count = counter;
+ return result;
+}
+
+// Get integer value from text
+// NOTE: This function replaces atoi() [stdlib.h]
+static int TextToInteger(const char *text)
+{
+ int value = 0;
+ int sign = 1;
+
+ if ((text[0] == '+') || (text[0] == '-'))
+ {
+ if (text[0] == '-') sign = -1;
+ text++;
+ }
+
+ for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
+
+ return value*sign;
+}
+
+// Get float value from text
+// NOTE: This function replaces atof() [stdlib.h]
+// WARNING: Only '.' character is understood as decimal point
+static float TextToFloat(const char *text)
+{
+ float value = 0.0f;
+ float sign = 1.0f;
+
+ if ((text[0] == '+') || (text[0] == '-'))
+ {
+ if (text[0] == '-') sign = -1.0f;
+ text++;
+ }
+
+ int i = 0;
+ for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0');
+
+ if (text[i++] != '.') value *= sign;
+ else
+ {
+ float divisor = 10.0f;
+ for (; ((text[i] >= '0') && (text[i] <= '9')); i++)
+ {
+ value += ((float)(text[i] - '0'))/divisor;
+ divisor = divisor*10.0f;
+ }
+ }
+
+ return value;
+}
+
+// Encode codepoint into UTF-8 text (char array size returned as parameter)
+static const char *CodepointToUTF8(int codepoint, int *byteSize)
+{
+ static char utf8[6] = { 0 };
+ int size = 0;
+
+ if (codepoint <= 0x7f)
+ {
+ utf8[0] = (char)codepoint;
+ size = 1;
+ }
+ else if (codepoint <= 0x7ff)
+ {
+ utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
+ utf8[1] = (char)((codepoint & 0x3f) | 0x80);
+ size = 2;
+ }
+ else if (codepoint <= 0xffff)
+ {
+ utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
+ utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
+ utf8[2] = (char)((codepoint & 0x3f) | 0x80);
+ size = 3;
+ }
+ else if (codepoint <= 0x10ffff)
+ {
+ utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
+ utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
+ utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
+ utf8[3] = (char)((codepoint & 0x3f) | 0x80);
+ size = 4;
+ }
+
+ *byteSize = size;
+
+ return utf8;
+}
+
+// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found
+// When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
+// Total number of bytes processed are returned as a parameter
+// NOTE: the standard says U+FFFD should be returned in case of errors
+// but that character is not supported by the default font in raylib
+static int GetCodepointNext(const char *text, int *codepointSize)
+{
+ const char *ptr = text;
+ int codepoint = 0x3f; // Codepoint (defaults to '?')
+ *codepointSize = 1;
+
+ // Get current codepoint and bytes processed
+ if (0xf0 == (0xf8 & ptr[0]))
+ {
+ // 4 byte UTF-8 codepoint
+ if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks
+ codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]);
+ *codepointSize = 4;
+ }
+ else if (0xe0 == (0xf0 & ptr[0]))
+ {
+ // 3 byte UTF-8 codepoint
+ if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks
+ codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]);
+ *codepointSize = 3;
+ }
+ else if (0xc0 == (0xe0 & ptr[0]))
+ {
+ // 2 byte UTF-8 codepoint
+ if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks
+ codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]);
+ *codepointSize = 2;
+ }
+ else if (0x00 == (0x80 & ptr[0]))
+ {
+ // 1 byte UTF-8 codepoint
+ codepoint = ptr[0];
+ *codepointSize = 1;
+ }
+
+ return codepoint;
+}
+#endif // RAYGUI_STANDALONE
+
+#endif // RAYGUI_IMPLEMENTATION
diff --git a/examples/shaders/resources/LICENSE.md b/examples/shaders/resources/LICENSE.md
index 7210e34b2..078036df7 100644
--- a/examples/shaders/resources/LICENSE.md
+++ b/examples/shaders/resources/LICENSE.md
@@ -10,4 +10,7 @@
| space.png | ❔ | ❔ | - |
| texel_checker.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | Made with [UV Checker Map Maker](http://uvchecker.byvalle.com/) |
| cubicmap.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |
-| spark_flame.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | Made with [EffectTextureMaker](https://mebiusbox.github.io/contents/EffectTextureMaker/) |
\ No newline at end of file
+| spark_flame.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | Made with [EffectTextureMaker](https://mebiusbox.github.io/contents/EffectTextureMaker/) |
+| parrots.png | [Kodak set](http://r0k.us/graphics/kodak/) | ❔ | Original name: `kodim23.png` |
+| cat.png | ❔ | ❔ | - |
+| mandrill.png | ❔ | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | Mandrill (a.k.a. Baboon) |
\ No newline at end of file
diff --git a/examples/shaders/resources/cat.png b/examples/shaders/resources/cat.png
new file mode 100644
index 000000000..db56b9ead
Binary files /dev/null and b/examples/shaders/resources/cat.png differ
diff --git a/examples/shaders/resources/mandrill.png b/examples/shaders/resources/mandrill.png
new file mode 100644
index 000000000..02d058eb0
Binary files /dev/null and b/examples/shaders/resources/mandrill.png differ
diff --git a/examples/shaders/resources/parrots.png b/examples/shaders/resources/parrots.png
new file mode 100644
index 000000000..9a0e7f806
Binary files /dev/null and b/examples/shaders/resources/parrots.png differ
diff --git a/examples/shaders/resources/shaders/glsl100/color_correction.fs b/examples/shaders/resources/shaders/glsl100/color_correction.fs
new file mode 100644
index 000000000..a678c6ed2
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl100/color_correction.fs
@@ -0,0 +1,34 @@
+#version 100
+
+precision mediump float;
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+uniform float contrast;
+uniform float saturation;
+uniform float brightness;
+
+void main()
+{
+ // Get texel color
+ vec4 texel = texture2D(texture0, fragTexCoord);
+
+ // Apply contrast
+ texel.rgb = (texel.rgb - 0.5)*(contrast/100.0 + 1.0) + 0.5;
+
+ // Apply brightness
+ texel.rgb = texel.rgb + brightness/100.0;
+
+ // Apply saturation
+ float intensity = dot(texel.rgb, vec3(0.299, 0.587, 0.114));
+ texel.rgb = (texel.rgb - intensity)*saturation/100.0 + texel.rgb;
+
+ // Output resulting color
+ gl_FragColor = texel;
+}
diff --git a/examples/shaders/resources/shaders/glsl100/hybrid_raster.fs b/examples/shaders/resources/shaders/glsl100/hybrid_raster.fs
index 35bc75d30..9658b3819 100644
--- a/examples/shaders/resources/shaders/glsl100/hybrid_raster.fs
+++ b/examples/shaders/resources/shaders/glsl100/hybrid_raster.fs
@@ -1,6 +1,7 @@
#version 100
-#extension GL_EXT_frag_depth : enable // Extension required for writing depth
+#extension GL_EXT_frag_depth : enable // Extension required for writing depth
+
precision mediump float; // Precision required for OpenGL ES2 (WebGL)
varying vec2 fragTexCoord;
diff --git a/examples/shaders/resources/shaders/glsl100/hybrid_raymarch.fs b/examples/shaders/resources/shaders/glsl100/hybrid_raymarch.fs
index 44233b3bb..8f9fa0907 100644
--- a/examples/shaders/resources/shaders/glsl100/hybrid_raymarch.fs
+++ b/examples/shaders/resources/shaders/glsl100/hybrid_raymarch.fs
@@ -2,6 +2,9 @@
#extension GL_EXT_frag_depth : enable //Extension required for writing depth
#extension GL_OES_standard_derivatives : enable //Extension used for fwidth()
+
+#define ZERO 0
+
precision mediump float; // Precision required for OpenGL ES2 (WebGL)
// Input vertex attributes (from vertex shader)
@@ -17,8 +20,6 @@ uniform vec3 camPos;
uniform vec3 camDir;
uniform vec2 screenCenter;
-#define ZERO 0
-
// SRC: https://learnopengl.com/Advanced-OpenGL/Depth-testing
float CalcDepth(in vec3 rd, in float Idist)
{
@@ -128,7 +129,7 @@ float calcSoftshadow(in vec3 ro, in vec3 rd, in float mint, in float tmax)
float res = 1.0;
float t = mint;
- for (int i=ZERO; i<24; i++)
+ for (int i = ZERO; i < 24; i++)
{
float h = map(ro + rd*t).x;
float s = clamp(8.0*h/t,0.0,1.0);
@@ -156,7 +157,7 @@ float calcAO(in vec3 pos, in vec3 nor)
{
float occ = 0.0;
float sca = 1.0;
- for (int i=ZERO; i<5; i++)
+ for (int i = ZERO; i < 5; i++)
{
float h = 0.01 + 0.12*float(i)/4.0;
float d = map(pos + h*nor).x;
@@ -257,7 +258,8 @@ vec4 render(in vec3 ro, in vec3 rd)
return vec4(vec3(clamp(col,0.0,1.0)),t);
}
-vec3 CalcRayDir(vec2 nCoord){
+vec3 CalcRayDir(vec2 nCoord)
+{
vec3 horizontal = normalize(cross(camDir,vec3(.0 , 1.0, .0)));
vec3 vertical = normalize(cross(horizontal,camDir));
return normalize(camDir + horizontal*nCoord.x + vertical*nCoord.y);
@@ -287,6 +289,7 @@ void main()
color = res.xyz;
depth = CalcDepth(rd,res.w);
}
+
gl_FragColor = vec4(color , 1.0);
gl_FragDepthEXT = depth;
}
\ No newline at end of file
diff --git a/examples/shaders/resources/shaders/glsl100/raymarching.fs b/examples/shaders/resources/shaders/glsl100/raymarching.fs
index ce9a2faca..58cd41059 100644
--- a/examples/shaders/resources/shaders/glsl100/raymarching.fs
+++ b/examples/shaders/resources/shaders/glsl100/raymarching.fs
@@ -1,9 +1,9 @@
#version 100
-precision mediump float;
-
#extension GL_OES_standard_derivatives : enable
+precision mediump float;
+
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord;
varying vec4 fragColor;
diff --git a/examples/shaders/resources/shaders/glsl120/color_correction.fs b/examples/shaders/resources/shaders/glsl120/color_correction.fs
new file mode 100644
index 000000000..520275ca4
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl120/color_correction.fs
@@ -0,0 +1,31 @@
+#version 120
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+uniform float contrast;
+uniform float saturation;
+uniform float brightness;
+
+void main()
+{
+ vec4 texel = texture2D(texture0, fragTexCoord); // Get texel color
+
+ // Apply contrast
+ texel.rgb = (texel.rgb - 0.5)*(contrast/100.0 + 1.0) + 0.5;
+
+ // Apply brightness
+ texel.rgb = texel.rgb + brightness/100.0;
+
+ // Apply saturation
+ float intensity = dot(texel.rgb, vec3(0.299, 0.587, 0.114));
+ texel.rgb = (texel.rgb - intensity)*saturation/100.0 + texel.rgb;
+
+ // Output resulting color
+ gl_FragColor = texel;
+}
\ No newline at end of file
diff --git a/examples/shaders/resources/shaders/glsl330/color_correction.fs b/examples/shaders/resources/shaders/glsl330/color_correction.fs
new file mode 100644
index 000000000..c489d6df1
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl330/color_correction.fs
@@ -0,0 +1,34 @@
+#version 330
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+uniform float contrast;
+uniform float saturation;
+uniform float brightness;
+
+// Output fragment color
+out vec4 finalColor;
+
+void main()
+{
+ vec4 texel = texture(texture0, fragTexCoord); // Get texel color
+
+ // Apply contrast
+ texel.rgb = (texel.rgb - 0.5f)*(contrast/100.0f + 1.0f) + 0.5f;
+
+ // Apply brightness
+ texel.rgb = texel.rgb + brightness/100.0f;
+
+ // Apply saturation
+ float intensity = dot(texel.rgb, vec3(0.299f, 0.587f, 0.114f));
+ texel.rgb = (texel.rgb - intensity)*saturation/100.0f + texel.rgb;
+
+ // Output resulting color
+ finalColor = texel;
+}
\ No newline at end of file
diff --git a/examples/shaders/resources/shaders/glsl330/hybrid_raster.fs b/examples/shaders/resources/shaders/glsl330/hybrid_raster.fs
index 12409d137..0b94dbdef 100644
--- a/examples/shaders/resources/shaders/glsl330/hybrid_raster.fs
+++ b/examples/shaders/resources/shaders/glsl330/hybrid_raster.fs
@@ -9,7 +9,7 @@ uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Output fragment color
-//out vec4 finalColor;
+out vec4 finalColor;
// NOTE: Add your custom variables here
@@ -17,6 +17,6 @@ void main()
{
vec4 texelColor = texture(texture0, fragTexCoord);
- gl_FragColor = texelColor*colDiffuse*fragColor;
- gl_FragDepth = gl_FragCoord.z;
+ finalColor = texelColor*colDiffuse*fragColor;
+ gl_FragDepth = finalColor.z;
}
\ No newline at end of file
diff --git a/examples/shaders/resources/shaders/glsl330/hybrid_raymarch.fs b/examples/shaders/resources/shaders/glsl330/hybrid_raymarch.fs
index 2edb625ad..f1fafc640 100644
--- a/examples/shaders/resources/shaders/glsl330/hybrid_raymarch.fs
+++ b/examples/shaders/resources/shaders/glsl330/hybrid_raymarch.fs
@@ -1,5 +1,7 @@
# version 330
+#define ZERO 0
+
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
@@ -13,10 +15,12 @@ uniform vec3 camPos;
uniform vec3 camDir;
uniform vec2 screenCenter;
-#define ZERO 0
+// Output fragment color
+out vec4 finalColor;
// https://learnopengl.com/Advanced-OpenGL/Depth-testing
-float CalcDepth(in vec3 rd, in float Idist){
+float CalcDepth(in vec3 rd, in float Idist)
+{
float local_z = dot(normalize(camDir),rd)*Idist;
return (1.0/(local_z) - 1.0/0.01)/(1.0/1000.0 -1.0/0.01);
}
@@ -26,15 +30,13 @@ float sdHorseshoe(in vec3 p, in vec2 c, in float r, in float le, vec2 w)
{
p.x = abs(p.x);
float l = length(p.xy);
- p.xy = mat2(-c.x, c.y,
- c.y, c.x)*p.xy;
- p.xy = vec2((p.y>0.0 || p.x>0.0)?p.x:l*sign(-c.x),
- (p.x>0.0)?p.y:l);
- p.xy = vec2(p.x,abs(p.y-r))-vec2(le,0.0);
+ p.xy = mat2(-c.x, c.y, c.y, c.x)*p.xy;
+ p.xy = vec2(((p.y > 0.0) || (p.x > 0.0))? p.x : l*sign(-c.x), (p.x>0.0)? p.y : l);
+ p.xy = vec2(p.x, abs(p.y - r)) - vec2(le, 0.0);
- vec2 q = vec2(length(max(p.xy,0.0)) + min(0.0,max(p.x,p.y)),p.z);
+ vec2 q = vec2(length(max(p.xy, 0.0)) + min(0.0, max(p.x, p.y)), p.z);
vec2 d = abs(q) - w;
- return min(max(d.x,d.y),0.0) + length(max(d,0.0));
+ return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}
// r = sphere's radius
@@ -44,17 +46,16 @@ float sdSixWayCutHollowSphere(vec3 p, float r, float h, float t)
{
// Six way symetry Transformation
vec3 ap = abs(p);
- if (ap.x < max(ap.y, ap.z)){
+ if (ap.x < max(ap.y, ap.z))
+ {
if (ap.y < ap.z) ap.xz = ap.zx;
else ap.xy = ap.yx;
}
vec2 q = vec2(length(ap.yz), ap.x);
-
float w = sqrt(r*r-h*h);
- return ((h*q.x0.0)
+ if (tp1 > 0.0)
{
tmax = min(tmax, tp1);
res = vec2(tp1, 1.0);
}
float t = tmin;
- for (int i=0; i<70 ; i++)
+ for (int i = 0; i < 70 ; i++)
{
- if (t>tmax) break;
- vec2 h = map(ro+rd*t);
- if (abs(h.x)<(0.0001*t))
+ if (t > tmax) break;
+ vec2 h = map(ro + rd*t);
+ if (abs(h.x )< (0.0001*t))
{
- res = vec2(t,h.y);
+ res = vec2(t, h.y);
break;
}
t += h.x;
@@ -111,28 +115,28 @@ vec2 raycast(in vec3 ro, in vec3 rd){
return res;
}
-
// https://iquilezles.org/articles/rmshadows
float calcSoftshadow(in vec3 ro, in vec3 rd, in float mint, in float tmax)
{
// bounding volume
- float tp = (0.8-ro.y)/rd.y; if (tp>0.0) tmax = min(tmax, tp);
+ float tp = (0.8 - ro.y)/rd.y; if (tp > 0.0) tmax = min(tmax, tp);
float res = 1.0;
float t = mint;
- for (int i=ZERO; i<24; i++)
+ for (int i = ZERO; i < 24; i++)
{
float h = map(ro + rd*t).x;
- float s = clamp(8.0*h/t,0.0,1.0);
+ float s = clamp(8.0*h/t, 0.0, 1.0);
res = min(res, s);
t += clamp(h, 0.01, 0.2);
- if (res<0.004 || t>tmax) break;
+ if ((res < 0.004) || (t > tmax)) break;
}
+
res = clamp(res, 0.0, 1.0);
+
return res*res*(3.0-2.0*res);
}
-
// https://iquilezles.org/articles/normalsSDF
vec3 calcNormal(in vec3 pos)
{
@@ -148,7 +152,7 @@ float calcAO(in vec3 pos, in vec3 nor)
{
float occ = 0.0;
float sca = 1.0;
- for (int i=ZERO; i<5; i++)
+ for (int i = ZERO; i < 5; i++)
{
float h = 0.01 + 0.12*float(i)/4.0;
float d = map(pos + h*nor).x;
@@ -156,6 +160,7 @@ float calcAO(in vec3 pos, in vec3 nor)
sca *= 0.95;
if (occ>0.35) break;
}
+
return clamp(1.0 - 3.0*occ, 0.0, 1.0)*(0.5+0.5*nor.y);
}
@@ -165,9 +170,9 @@ float checkersGradBox(in vec2 p)
// filter kernel
vec2 w = fwidth(p) + 0.001;
// analytical integral (box filter)
- vec2 i = 2.0*(abs(fract((p-0.5*w)*0.5)-0.5)-abs(fract((p+0.5*w)*0.5)-0.5))/w;
+ vec2 i = 2.0*(abs(fract((p - 0.5*w)*0.5)-0.5) - abs(fract((p + 0.5*w)*0.5) - 0.5))/w;
// xor pattern
- return 0.5 - 0.5*i.x*i.y;
+ return (0.5 - 0.5*i.x*i.y);
}
// https://www.shadertoy.com/view/tdS3DG
@@ -180,7 +185,7 @@ vec4 render(in vec3 ro, in vec3 rd)
vec2 res = raycast(ro,rd);
float t = res.x;
float m = res.y;
- if (m>-0.5)
+ if (m > -0.5)
{
vec3 pos = ro + t*rd;
vec3 nor = (m<1.5) ? vec3(0.0,1.0,0.0) : calcNormal(pos);
@@ -190,7 +195,7 @@ vec4 render(in vec3 ro, in vec3 rd)
col = 0.2 + 0.2*sin(m*2.0 + vec3(0.0,1.0,2.0));
float ks = 1.0;
- if (m<1.5)
+ if (m < 1.5)
{
float f = checkersGradBox(3.0*pos.xz);
col = 0.15 + f*vec3(0.05);
@@ -207,14 +212,14 @@ vec4 render(in vec3 ro, in vec3 rd)
vec3 lig = normalize(vec3(-0.5, 0.4, -0.6));
vec3 hal = normalize(lig-rd);
float dif = clamp(dot(nor, lig), 0.0, 1.0);
- //if (dif>0.0001)
+ //if (dif>0.0001)
dif *= calcSoftshadow(pos, lig, 0.02, 2.5);
float spe = pow(clamp(dot(nor, hal), 0.0, 1.0),16.0);
spe *= dif;
spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0);
//spe *= 0.04+0.96*pow(clamp(1.0-sqrt(0.5*(1.0-dot(rd,lig))),0.0,1.0),5.0);
lin += col*2.20*dif*vec3(1.30,1.00,0.70);
- lin += 5.00*spe*vec3(1.30,1.00,0.70)*ks;
+ lin += 5.00*spe*vec3(1.30,1.00,0.70)*ks;
}
// sky
{
@@ -249,7 +254,8 @@ vec4 render(in vec3 ro, in vec3 rd)
return vec4(vec3(clamp(col,0.0,1.0)),t);
}
-vec3 CalcRayDir(vec2 nCoord){
+vec3 CalcRayDir(vec2 nCoord)
+{
vec3 horizontal = normalize(cross(camDir,vec3(.0 , 1.0, .0)));
vec3 vertical = normalize(cross(horizontal,camDir));
return normalize(camDir + horizontal*nCoord.x + vertical*nCoord.y);
@@ -279,6 +285,7 @@ void main()
color = res.xyz;
depth = CalcDepth(rd,res.w);
}
- gl_FragColor = vec4(color , 1.0);
+
+ finalColor = vec4(color , 1.0);
gl_FragDepth = depth;
}
\ No newline at end of file
diff --git a/examples/shaders/shaders_ascii_rendering.c b/examples/shaders/shaders_ascii_rendering.c
index 523b381b2..d3302bf53 100644
--- a/examples/shaders/shaders_ascii_rendering.c
+++ b/examples/shaders/shaders_ascii_rendering.c
@@ -87,15 +87,15 @@ int main(void)
DrawTexture(fudesumi, 500, -30, WHITE);
DrawTextureV(raysan, circlePos, WHITE);
EndTextureMode();
-
+
BeginDrawing();
ClearBackground(RAYWHITE);
BeginShaderMode(shader);
// Draw the scene texture (that we rendered earlier) to the screen
// The shader will process every pixel of this texture
- DrawTextureRec(target.texture,
- (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height },
+ DrawTextureRec(target.texture,
+ (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height },
(Vector2){ 0, 0 }, WHITE);
EndShaderMode();
diff --git a/examples/shaders/shaders_basic_pbr.c b/examples/shaders/shaders_basic_pbr.c
index 6fb15a607..dd5f871da 100644
--- a/examples/shaders/shaders_basic_pbr.c
+++ b/examples/shaders/shaders_basic_pbr.c
@@ -77,7 +77,7 @@ static void UpdateLight(Shader shader, Light light);
//----------------------------------------------------------------------------------
// Program main entry point
//----------------------------------------------------------------------------------
-int main()
+int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
@@ -242,7 +242,7 @@ int main()
SetShaderValue(shader, emissiveColorLoc, &carEmissiveColor, SHADER_UNIFORM_VEC4);
float emissiveIntensity = 0.01f;
SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, SHADER_UNIFORM_FLOAT);
-
+
// Set old car metallic and roughness values
SetShaderValue(shader, metallicValueLoc, &car.materials[0].maps[MATERIAL_MAP_METALNESS].value, SHADER_UNIFORM_FLOAT);
SetShaderValue(shader, roughnessValueLoc, &car.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value, SHADER_UNIFORM_FLOAT);
@@ -252,11 +252,11 @@ int main()
// Draw spheres to show the lights positions
for (int i = 0; i < MAX_LIGHTS; i++)
{
- Color lightColor = (Color){
+ Color lightColor = (Color){
(unsigned char)(lights[i].color[0]*255),
- (unsigned char)(lights[i].color[1] * 255),
- (unsigned char)(lights[i].color[2] * 255),
- (unsigned char)(lights[i].color[3] * 255) };
+ (unsigned char)(lights[i].color[1]*255),
+ (unsigned char)(lights[i].color[2]*255),
+ (unsigned char)(lights[i].color[3]*255) };
if (lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, lightColor);
else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(lightColor, 0.3f));
diff --git a/examples/shaders/shaders_color_correction.c b/examples/shaders/shaders_color_correction.c
new file mode 100644
index 000000000..826baecc7
--- /dev/null
+++ b/examples/shaders/shaders_color_correction.c
@@ -0,0 +1,148 @@
+/*******************************************************************************************
+*
+* raylib [shaders] example - color correction
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
+* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
+*
+* Example originally created with raylib 5.6, last time updated with raylib 5.6
+*
+* Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 Jordi Santonja (@JordSant)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h" // Required for GUI controls
+
+#if defined(PLATFORM_DESKTOP)
+ #define GLSL_VERSION 330
+#else // PLATFORM_ANDROID, PLATFORM_WEB
+ #define GLSL_VERSION 100
+#endif
+
+#define MAX_TEXTURES 4
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [shaders] example - color correction");
+
+ Texture2D texture[MAX_TEXTURES] = {
+ LoadTexture("resources/parrots.png"),
+ LoadTexture("resources/cat.png"),
+ LoadTexture("resources/mandrill.png"),
+ LoadTexture("resources/fudesumi.png")
+ };
+
+ Shader shdrColorCorrection = LoadShader(0, TextFormat("resources/shaders/glsl%i/color_correction.fs", GLSL_VERSION));
+
+ int imageIndex = 0;
+ int resetButtonClicked = 0;
+
+ float contrast = 0.0f;
+ float saturation = 0.0f;
+ float brightness = 0.0f;
+
+ // Get shader locations
+ int contrastLoc = GetShaderLocation(shdrColorCorrection, "contrast");
+ int saturationLoc = GetShaderLocation(shdrColorCorrection, "saturation");
+ int brightnessLoc = GetShaderLocation(shdrColorCorrection, "brightness");
+
+ // Set shader values (they can be changed later)
+ SetShaderValue(shdrColorCorrection, contrastLoc, &contrast, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shdrColorCorrection, saturationLoc, &saturation, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shdrColorCorrection, brightnessLoc, &brightness, SHADER_UNIFORM_FLOAT);
+
+ 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
+ //----------------------------------------------------------------------------------
+ // Select texture to draw
+ if (IsKeyPressed(KEY_ONE)) imageIndex = 0;
+ else if (IsKeyPressed(KEY_TWO)) imageIndex = 1;
+ else if (IsKeyPressed(KEY_THREE)) imageIndex = 2;
+ else if (IsKeyPressed(KEY_FOUR)) imageIndex = 3;
+
+ // Reset values to 0
+ if (IsKeyPressed(KEY_R) || resetButtonClicked)
+ {
+ contrast = 0.0f;
+ saturation = 0.0f;
+ brightness = 0.0f;
+ }
+
+ // Send the values to the shader
+ SetShaderValue(shdrColorCorrection, contrastLoc, &contrast, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shdrColorCorrection, saturationLoc, &saturation, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shdrColorCorrection, brightnessLoc, &brightness, SHADER_UNIFORM_FLOAT);
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ BeginShaderMode(shdrColorCorrection);
+
+ DrawTexture(texture[imageIndex], 580/2 - texture[imageIndex].width/2, GetScreenHeight()/2 - texture[imageIndex].height/2, WHITE);
+
+ EndShaderMode();
+
+ DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 });
+ DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 232, 232, 232, 255 });
+
+ // Draw UI info text
+ DrawText("Color Correction", 585, 40, 20, GRAY);
+
+ DrawText("Picture", 602, 75, 10, GRAY);
+ DrawText("Press [1] - [4] to Change Picture", 600, 230, 8, GRAY);
+ DrawText("Press [R] to Reset Values", 600, 250, 8, GRAY);
+
+ // Draw GUI controls
+ //------------------------------------------------------------------------------
+ GuiToggleGroup((Rectangle){ 645, 70, 20, 20 }, "1;2;3;4", &imageIndex);
+
+ GuiSliderBar((Rectangle){ 645, 100, 120, 20 }, "Contrast", TextFormat("%.0f", contrast), &contrast, -100.0f, 100.0f);
+ GuiSliderBar((Rectangle){ 645, 130, 120, 20 }, "Saturation", TextFormat("%.0f", saturation), &saturation, -100.0f, 100.0f);
+ GuiSliderBar((Rectangle){ 645, 160, 120, 20 }, "Brightness", TextFormat("%.0f", brightness), &brightness, -100.0f, 100.0f);
+
+ resetButtonClicked = GuiButton((Rectangle){ 645, 190, 40, 20 }, "Reset");
+ //------------------------------------------------------------------------------
+
+ DrawFPS(710, 10);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ for (int i = 0; i < MAX_TEXTURES; i++) UnloadTexture(texture[i]);
+ UnloadShader(shdrColorCorrection);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
diff --git a/examples/shaders/shaders_color_correction.png b/examples/shaders/shaders_color_correction.png
new file mode 100644
index 000000000..5bf5dcba6
Binary files /dev/null and b/examples/shaders/shaders_color_correction.png differ
diff --git a/examples/shaders/shaders_hybrid_rendering.c b/examples/shaders/shaders_hybrid_rendering.c
index ec6b8b0a6..439965fd6 100644
--- a/examples/shaders/shaders_hybrid_rendering.c
+++ b/examples/shaders/shaders_hybrid_rendering.c
@@ -118,7 +118,7 @@ int main(void)
// Raymarch Scene
rlEnableDepthTest(); // Manually enable Depth Test to handle multiple rendering methods
BeginShaderMode(shdrRaymarch);
- DrawRectangleRec((Rectangle){0,0, (float)screenWidth, (float)screenHeight},WHITE);
+ DrawRectangleRec((Rectangle){ 0,0, (float)screenWidth, (float)screenHeight },WHITE);
EndShaderMode();
// Rasterize Scene
@@ -138,6 +138,7 @@ int main(void)
ClearBackground(RAYWHITE);
DrawTextureRec(target.texture, (Rectangle) { 0, 0, (float)screenWidth, (float)-screenHeight }, (Vector2) { 0, 0 }, WHITE);
+
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
diff --git a/examples/shaders/shaders_lightmap_rendering.c b/examples/shaders/shaders_lightmap_rendering.c
index e269aada2..05d9c0e09 100644
--- a/examples/shaders/shaders_lightmap_rendering.c
+++ b/examples/shaders/shaders_lightmap_rendering.c
@@ -33,7 +33,7 @@
#define GLSL_VERSION 100
#endif
-#define MAP_SIZE 10
+#define MAP_SIZE 16
//------------------------------------------------------------------------------------
// Program main entry point
@@ -88,8 +88,6 @@ int main(void)
RenderTexture lightmap = LoadRenderTexture(MAP_SIZE, MAP_SIZE);
- SetTextureFilter(lightmap.texture, TEXTURE_FILTER_TRILINEAR);
-
Material material = LoadMaterialDefault();
material.shader = shader;
material.maps[MATERIAL_MAP_ALBEDO].texture = texture;
@@ -103,30 +101,34 @@ int main(void)
DrawTexturePro(
light,
(Rectangle){ 0, 0, (float)light.width, (float)light.height },
- (Rectangle){ 0, 0, 20, 20 },
- (Vector2){ 10.0, 10.0 },
+ (Rectangle){ 0, 0, 2.0f*MAP_SIZE, 2.0f*MAP_SIZE },
+ (Vector2){ (float)MAP_SIZE, (float)MAP_SIZE },
0.0,
RED
);
DrawTexturePro(
light,
(Rectangle){ 0, 0, (float)light.width, (float)light.height },
- (Rectangle){ 8, 4, 20, 20 },
- (Vector2){ 10.0, 10.0 },
+ (Rectangle){ (float)MAP_SIZE*0.8f, (float)MAP_SIZE/2.0f, 2.0f*MAP_SIZE, 2.0f*MAP_SIZE },
+ (Vector2){ (float)MAP_SIZE, (float)MAP_SIZE },
0.0,
BLUE
);
DrawTexturePro(
light,
(Rectangle){ 0, 0, (float)light.width, (float)light.height },
- (Rectangle){ 8, 8, 10, 10 },
- (Vector2){ 5.0, 5.0 },
+ (Rectangle){ (float)MAP_SIZE*0.8f, (float)MAP_SIZE*0.8f, (float)MAP_SIZE, (float)MAP_SIZE },
+ (Vector2){ (float)MAP_SIZE/2.0f, (float)MAP_SIZE/2.0f },
0.0,
GREEN
);
BeginBlendMode(BLEND_ALPHA);
EndTextureMode();
+ // NOTE: To enable trilinear filtering we need mipmaps available for texture
+ GenTextureMipmaps(&lightmap.texture);
+ SetTextureFilter(lightmap.texture, TEXTURE_FILTER_TRILINEAR);
+
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
@@ -141,24 +143,20 @@ int main(void)
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
+
ClearBackground(RAYWHITE);
BeginMode3D(camera);
DrawMesh(mesh, material, MatrixIdentity());
EndMode3D();
- DrawFPS(10, 10);
-
- DrawTexturePro(
- lightmap.texture,
- (Rectangle){ 0, 0, -MAP_SIZE, -MAP_SIZE },
+ DrawTexturePro(lightmap.texture, (Rectangle){ 0, 0, -MAP_SIZE, -MAP_SIZE },
(Rectangle){ (float)GetRenderWidth() - MAP_SIZE*8 - 10, 10, (float)MAP_SIZE*8, (float)MAP_SIZE*8 },
- (Vector2){ 0.0, 0.0 },
- 0.0,
- WHITE);
+ (Vector2){ 0.0, 0.0 }, 0.0, WHITE);
- DrawText("lightmap", GetRenderWidth() - 66, 16 + MAP_SIZE*8, 10, GRAY);
- DrawText("10x10 pixels", GetRenderWidth() - 76, 30 + MAP_SIZE*8, 10, GRAY);
+ DrawText(TextFormat("LIGHTMAP: %ix%i pixels", MAP_SIZE, MAP_SIZE), GetRenderWidth() - 130, 20 + MAP_SIZE*8, 10, GREEN);
+
+ DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
diff --git a/examples/shaders/shaders_mandelbrot_set.c b/examples/shaders/shaders_mandelbrot_set.c
index a373c518a..dc592b6e4 100644
--- a/examples/shaders/shaders_mandelbrot_set.c
+++ b/examples/shaders/shaders_mandelbrot_set.c
@@ -69,7 +69,7 @@ int main(void)
float offset[2] = { startingOffset[0], startingOffset[1] };
float zoom = startingZoom;
// Depending on the zoom the mximum number of iterations must be adapted to get more detail as we zzoom in
- // The solution is not perfect, so a control has been added to increase/decrease the number of iterations with UP/DOWN keys
+ // The solution is not perfect, so a control has been added to increase/decrease the number of iterations with UP/DOWN keys
#if defined(PLATFORM_DESKTOP)
int maxIterations = 333;
float maxIterationsMultiplier = 166.5f;
@@ -134,8 +134,8 @@ int main(void)
if (IsKeyPressed(KEY_F1)) showControls = !showControls; // Toggle whether or not to show controls
- // Change number of max iterations with UP and DOWN keys
- // WARNING: Increasing the number of max iterations greatly impacts performance
+ // Change number of max iterations with UP and DOWN keys
+ // WARNING: Increasing the number of max iterations greatly impacts performance
if (IsKeyPressed(KEY_UP))
{
maxIterationsMultiplier *= 1.4f;
@@ -167,10 +167,10 @@ int main(void)
updateShader = true;
}
- // In case a parameter has been changed, update the shader values
+ // In case a parameter has been changed, update the shader values
if (updateShader)
- {
- // As we zoom in, increase the number of max iterations to get more detail
+ {
+ // As we zoom in, increase the number of max iterations to get more detail
// Aproximate formula, but it works-ish
maxIterations = (int)(sqrtf(2.0f*sqrtf(fabsf(1.0f - sqrtf(37.5f*zoom))))*maxIterationsMultiplier);
diff --git a/examples/shaders/shaders_normalmap_rendering.c b/examples/shaders/shaders_normalmap_rendering.c
index 4859ec813..07399a78e 100644
--- a/examples/shaders/shaders_normalmap_rendering.c
+++ b/examples/shaders/shaders_normalmap_rendering.c
@@ -49,7 +49,7 @@ int main(void)
camera.projection = CAMERA_PERSPECTIVE;
// Load basic normal map lighting shader
- Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/normalmap.vs", GLSL_VERSION),
+ Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/normalmap.vs", GLSL_VERSION),
TextFormat("resources/shaders/glsl%i/normalmap.fs", GLSL_VERSION));
// Get some required shader locations
diff --git a/examples/shaders/shaders_shadowmap_rendering.c b/examples/shaders/shaders_shadowmap_rendering.c
index 7b75b80e0..a739cdd93 100644
--- a/examples/shaders/shaders_shadowmap_rendering.c
+++ b/examples/shaders/shaders_shadowmap_rendering.c
@@ -45,7 +45,7 @@ int main(void)
// Shadows are a HUGE topic, and this example shows an extremely simple implementation of the shadowmapping algorithm,
// which is the industry standard for shadows. This algorithm can be extended in a ridiculous number of ways to improve
// realism and also adapt it for different scenes. This is pretty much the simplest possible implementation
-
+
SetConfigFlags(FLAG_MSAA_4X_HINT);
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - shadowmap rendering");
@@ -59,7 +59,7 @@ int main(void)
Shader shadowShader = LoadShader(TextFormat("resources/shaders/glsl%i/shadowmap.vs", GLSL_VERSION),
TextFormat("resources/shaders/glsl%i/shadowmap.fs", GLSL_VERSION));
shadowShader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shadowShader, "viewPos");
-
+
Vector3 lightDir = Vector3Normalize((Vector3){ 0.35f, -1.0f, -0.35f });
Color lightColor = WHITE;
Vector4 lightColorNormalized = ColorNormalize(lightColor);
@@ -83,7 +83,7 @@ int main(void)
ModelAnimation *robotAnimations = LoadModelAnimations("resources/models/robot.glb", &animCount);
RenderTexture2D shadowMap = LoadShadowmapRenderTexture(SHADOWMAP_RESOLUTION, SHADOWMAP_RESOLUTION);
-
+
// For the shadowmapping algorithm, we will be rendering everything from the light's point of view
Camera3D lightCamera = { 0 };
lightCamera.position = Vector3Scale(lightDir, -15.0f);
@@ -91,9 +91,9 @@ int main(void)
lightCamera.projection = CAMERA_ORTHOGRAPHIC; // Use an orthographic projection for directional lights
lightCamera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
lightCamera.fovy = 20.0f;
-
+
int frameCounter = 0;
-
+
// Store the light matrices
Matrix lightView = { 0 };
Matrix lightProj = { 0 };
@@ -136,7 +136,7 @@ int main(void)
{
if (lightDir.z > -0.6f) lightDir.z -= cameraSpeed*60.0f*deltaTime;
}
-
+
lightDir = Vector3Normalize(lightDir);
lightCamera.position = Vector3Scale(lightDir, -15.0f);
SetShaderValue(shadowShader, lightDirLoc, &lightDir, SHADER_UNIFORM_VEC3);
@@ -151,13 +151,13 @@ int main(void)
// to determine whether a given point is "visible" to the light
BeginTextureMode(shadowMap);
ClearBackground(WHITE);
-
+
BeginMode3D(lightCamera);
lightView = rlGetMatrixModelview();
lightProj = rlGetMatrixProjection();
DrawScene(cube, robot);
EndMode3D();
-
+
EndTextureMode();
lightViewProj = MatrixMultiply(lightView, lightProj);
@@ -167,7 +167,7 @@ int main(void)
SetShaderValueMatrix(shadowShader, lightVPLoc, lightViewProj);
rlEnableShader(shadowShader.id);
-
+
rlActiveTextureSlot(textureActiveSlot);
rlEnableTexture(shadowMap.depth.id);
rlSetUniform(shadowMapLoc, &textureActiveSlot, SHADER_UNIFORM_INT, 1);
@@ -178,7 +178,7 @@ int main(void)
DrawText("Use the arrow keys to rotate the light!", 10, 10, 30, RED);
DrawText("Shadows in raylib using the shadowmapping algorithm!", screenWidth - 280, screenHeight - 20, 10, GRAY);
-
+
EndDrawing();
if (IsKeyPressed(KEY_F)) TakeScreenshot("shaders_shadowmap.png");
@@ -200,7 +200,7 @@ int main(void)
}
// Load render texture for shadowmap projection
-// NOTE: Load framebuffer with only a texture depth attachment,
+// NOTE: Load framebuffer with only a texture depth attachment,
// no color attachment required for shadowmap
static RenderTexture2D LoadShadowmapRenderTexture(int width, int height)
{
diff --git a/examples/shaders/shaders_spotlight_rendering.c b/examples/shaders/shaders_spotlight_rendering.c
index c9ee950c1..3678f9796 100644
--- a/examples/shaders/shaders_spotlight_rendering.c
+++ b/examples/shaders/shaders_spotlight_rendering.c
@@ -239,7 +239,7 @@ int main(void)
static void ResetStar(Star *star)
{
star->position = (Vector2){ GetScreenWidth()/2.0f, GetScreenHeight()/2.0f };
-
+
star->speed.x = (float)GetRandomValue(-1000, 1000)/100.0f;
star->speed.y = (float)GetRandomValue(-1000, 1000)/100.0f;
@@ -247,7 +247,7 @@ static void ResetStar(Star *star)
{
star->speed.x = (float)GetRandomValue(-1000, 1000)/100.0f;
star->speed.y = (float)GetRandomValue(-1000, 1000)/100.0f;
- }
+ }
star->position = Vector2Add(star->position, Vector2Multiply(star->speed, (Vector2){ 8.0f, 8.0f }));
}
diff --git a/examples/shapes/raygui.h b/examples/shapes/raygui.h
index a3fc51f0f..88fe5cc5b 100644
--- a/examples/shapes/raygui.h
+++ b/examples/shapes/raygui.h
@@ -4,7 +4,7 @@
*
* DESCRIPTION:
* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also
-* available as a standalone library, as long as input and drawing functions are provided.
+* available as a standalone library, as long as input and drawing functions are provided
*
* FEATURES:
* - Immediate-mode gui, minimal retained data
@@ -27,7 +27,7 @@
* - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for
* font atlas recs and glyphs, freeing that memory is (usually) up to the user,
* no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads
-* by default any previously loaded font (texture, recs, glyphs).
+* by default any previously loaded font (texture, recs, glyphs)
* - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions
*
* CONTROLS PROVIDED:
@@ -65,7 +65,7 @@
* - MessageBox --> Window, Label, Button
* - TextInputBox --> Window, Label, TextBox, Button
*
-* It also provides a set of functions for styling the controls based on its properties (size, color).
+* It also provides a set of functions for styling the controls based on its properties (size, color)
*
*
* RAYGUI STYLE (guiStyle):
@@ -77,11 +77,11 @@
*
* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)];
*
-* guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB
+* guiStyle size is by default: 16*(16 + 8) = 384 int = 384*4 bytes = 1536 bytes = 1.5 KB
*
* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style
* used for all controls, when any of those base values is set, it is automatically populated to all
-* controls, so, specific control values overwriting generic style should be set after base values.
+* controls, so, specific control values overwriting generic style should be set after base values
*
* After the first BASE set we have the EXTENDED properties (by default guiStyle[16..23]), those
* properties are actually common to all controls and can not be overwritten individually (like BASE ones)
@@ -100,7 +100,7 @@
* Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon
* requires 8 integers (16*16/32) to be stored in memory.
*
-* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set.
+* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set
*
* The global icons array size is fixed and depends on the number of icons and size:
*
@@ -112,20 +112,20 @@
*
* RAYGUI LAYOUT:
* raygui currently does not provide an auto-layout mechanism like other libraries,
-* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it.
+* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it
*
* TOOL: rGuiLayout is a visual tool to create raygui layouts: github.com/raysan5/rguilayout
*
* CONFIGURATION:
* #define RAYGUI_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 RAYGUI_STANDALONE
* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined
* internally in the library and input management and drawing functions must be provided by
-* the user (check library implementation for further details).
+* the user (check library implementation for further details)
*
* #define RAYGUI_NO_ICONS
* Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB)
@@ -141,12 +141,17 @@
* Draw text bounds rectangles for debug
*
* VERSIONS HISTORY:
-* 4.5-dev (Sep-2024) Current dev version...
+* 5.0 (xx-Nov-2025) ADDED: Support up to 32 controls (v500)
* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
* ADDED: GuiValueBoxFloat()
* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
* ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH
+* ADDED: GuiLoadIconsFromMemory()
* ADDED: Multiple new icons
+* REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties
+* REMOVED: GuiSliderPro(), functionality was redundant
+* REVIEWED: Controls using text labels to use LABEL properties
+* REVIEWED: Replaced sprintf() by snprintf() for more safety
* REVIEWED: GuiTabBar(), close tab with mouse middle button
* REVIEWED: GuiScrollPanel(), scroll speed proportional to content
* REVIEWED: GuiDropdownBox(), support roll up and hidden arrow
@@ -156,6 +161,8 @@
* REVIEWED: GuiIconText(), increase buffer size and reviewed padding
* REVIEWED: GuiDrawText(), improved wrap mode drawing
* REVIEWED: GuiScrollBar(), minor tweaks
+* REVIEWED: GuiProgressBar(), improved borders computing
+* REVIEWED: GuiTextBox(), multiple improvements: autocursor and more
* REVIEWED: Functions descriptions, removed wrong return value reference
* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion
*
@@ -259,16 +266,16 @@
* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones)
* 1.3 (12-Jun-2017) Complete redesign of style system
* 1.1 (01-Jun-2017) Complete review of the library
-* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria.
-* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria.
-* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria.
+* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria
+* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria
+* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria
*
* DEPENDENCIES:
-* raylib 5.0 - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing
+* raylib 5.6-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing
*
* STANDALONE MODE:
* By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled
-* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs.
+* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs
*
* The following functions should be redefined for a custom backend:
*
@@ -309,7 +316,7 @@
*
* LICENSE: zlib/libpng
*
-* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5)
+* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
@@ -334,7 +341,7 @@
#define RAYGUI_VERSION_MAJOR 4
#define RAYGUI_VERSION_MINOR 5
#define RAYGUI_VERSION_PATCH 0
-#define RAYGUI_VERSION "4.5-dev"
+#define RAYGUI_VERSION "5.0-dev"
#if !defined(RAYGUI_STANDALONE)
#include "raylib.h"
@@ -358,17 +365,6 @@
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
-// Allow custom memory allocators
-#ifndef RAYGUI_MALLOC
- #define RAYGUI_MALLOC(sz) malloc(sz)
-#endif
-#ifndef RAYGUI_CALLOC
- #define RAYGUI_CALLOC(n,sz) calloc(n,sz)
-#endif
-#ifndef RAYGUI_FREE
- #define RAYGUI_FREE(p) free(p)
-#endif
-
// Simple log system to avoid printf() calls if required
// NOTE: Avoiding those calls, also avoids const strings memory usage
#define RAYGUI_SUPPORT_LOG_INFO
@@ -421,13 +417,16 @@
// TODO: Texture2D type is very coupled to raylib, required by Font type
// It should be redesigned to be provided by user
- typedef struct Texture2D {
+ typedef struct Texture {
unsigned int id; // OpenGL texture id
int width; // Texture base width
int height; // Texture base height
int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (PixelFormat type)
- } Texture2D;
+ } Texture;
+
+ // Texture2D, same as Texture
+ typedef Texture Texture2D;
// Image, pixel data stored in CPU memory (RAM)
typedef struct Image {
@@ -527,7 +526,7 @@ typedef enum {
DROPDOWNBOX,
TEXTBOX, // Used also for: TEXTBOXMULTI
VALUEBOX,
- SPINNER, // Uses: BUTTON, VALUEBOX
+ CONTROL11,
LISTVIEW,
COLORPICKER,
SCROLLBAR,
@@ -549,12 +548,12 @@ typedef enum {
BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED
BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED
TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED
- BORDER_WIDTH, // Control border size, 0 for no border
+ BORDER_WIDTH = 12, // Control border size, 0 for no border
//TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls
//TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls
- //TEXT_LINE_SPACING // Control text spacing between lines -> GLOBAL for all controls
- TEXT_PADDING, // Control text padding, not considering border
- TEXT_ALIGNMENT, // Control text horizontal alignment inside control text bound (after border and padding)
+ //TEXT_LINE_SPACING, // Control text spacing between lines -> GLOBAL for all controls
+ TEXT_PADDING = 13, // Control text padding, not considering border
+ TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding)
//TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls
} GuiControlProperty;
@@ -641,11 +640,14 @@ typedef enum {
TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable
} GuiTextBoxProperty;
-// Spinner
+// ValueBox/Spinner
typedef enum {
- SPIN_BUTTON_WIDTH = 16, // Spinner left/right buttons width
- SPIN_BUTTON_SPACING, // Spinner buttons separation
-} GuiSpinnerProperty;
+ SPINNER_BUTTON_WIDTH = 16, // Spinner left/right buttons width
+ SPINNER_BUTTON_SPACING, // Spinner buttons separation
+} GuiValueBoxProperty;
+
+// Control11
+//typedef enum { } GuiControl11Property;
// ListView
typedef enum {
@@ -653,6 +655,7 @@ typedef enum {
LIST_ITEMS_SPACING, // ListView items separation
SCROLLBAR_WIDTH, // ListView scrollbar size (usually width)
SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE)
+ LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state
LIST_ITEMS_BORDER_WIDTH // ListView items border width
} GuiListViewProperty;
@@ -717,6 +720,9 @@ RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load
RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position
#endif
+// Utility functions
+RAYGUIAPI int GuiGetTextWidth(const char *text); // Get text width considering gui style and icon size (if required)
+
// Controls
//----------------------------------------------------------------------------------------------------------
// Container/separator controls, useful for controls organization
@@ -999,33 +1005,33 @@ typedef enum {
ICON_MLAYERS = 226,
ICON_MAPS = 227,
ICON_HOT = 228,
- ICON_229 = 229,
- ICON_230 = 230,
- ICON_231 = 231,
- ICON_232 = 232,
- ICON_233 = 233,
- ICON_234 = 234,
- ICON_235 = 235,
- ICON_236 = 236,
- ICON_237 = 237,
- ICON_238 = 238,
- ICON_239 = 239,
- ICON_240 = 240,
- ICON_241 = 241,
- ICON_242 = 242,
- ICON_243 = 243,
- ICON_244 = 244,
- ICON_245 = 245,
- ICON_246 = 246,
- ICON_247 = 247,
- ICON_248 = 248,
- ICON_249 = 249,
+ ICON_LABEL = 229,
+ ICON_NAME_ID = 230,
+ ICON_SLICING = 231,
+ ICON_MANUAL_CONTROL = 232,
+ ICON_COLLISION = 233,
+ ICON_CIRCLE_ADD = 234,
+ ICON_CIRCLE_ADD_FILL = 235,
+ ICON_CIRCLE_WARNING = 236,
+ ICON_CIRCLE_WARNING_FILL = 237,
+ ICON_BOX_MORE = 238,
+ ICON_BOX_MORE_FILL = 239,
+ ICON_BOX_MINUS = 240,
+ ICON_BOX_MINUS_FILL = 241,
+ ICON_UNION = 242,
+ ICON_INTERSECTION = 243,
+ ICON_DIFFERENCE = 244,
+ ICON_SPHERE = 245,
+ ICON_CYLINDER = 246,
+ ICON_CONE = 247,
+ ICON_ELLIPSOID = 248,
+ ICON_CAPSULE = 249,
ICON_250 = 250,
ICON_251 = 251,
ICON_252 = 252,
ICON_253 = 253,
ICON_254 = 254,
- ICON_255 = 255,
+ ICON_255 = 255
} GuiIconName;
#endif
@@ -1046,12 +1052,24 @@ typedef enum {
#if defined(RAYGUI_IMPLEMENTATION)
#include // required for: isspace() [GuiTextBox()]
-#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
-#include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()]
+#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
#include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
#include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
#include // Required for: roundf() [GuiColorPicker()]
+// Allow custom memory allocators
+#if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE)
+ #if !defined(RAYGUI_MALLOC) || !defined(RAYGUI_CALLOC) || !defined(RAYGUI_FREE)
+ #error "RAYGUI: if RAYGUI_MALLOC, RAYGUI_CALLOC, or RAYGUI_FREE is customized, all three must be customized"
+ #endif
+#else
+ #include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()]
+
+ #define RAYGUI_MALLOC(sz) malloc(sz)
+ #define RAYGUI_CALLOC(n,sz) calloc(n,sz)
+ #define RAYGUI_FREE(p) free(p)
+#endif
+
#ifdef __cplusplus
#define RAYGUI_CLITERAL(name) name
#else
@@ -1060,7 +1078,7 @@ typedef enum {
// Check if two rectangles are equal, used to validate a slider bounds as an id
#ifndef CHECK_BOUNDS_ID
- #define CHECK_BOUNDS_ID(src, dst) ((src.x == dst.x) && (src.y == dst.y) && (src.width == dst.width) && (src.height == dst.height))
+ #define CHECK_BOUNDS_ID(src, dst) (((int)src.x == (int)dst.x) && ((int)src.y == (int)dst.y) && ((int)src.width == (int)dst.width) && ((int)src.height == (int)dst.height))
#endif
#if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS)
@@ -1318,27 +1336,27 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] =
0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS
0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS
0x04200000, 0x1cf00c60, 0x11f019f0, 0x0f3807b8, 0x1e3c0f3c, 0x1c1c1e1c, 0x1e3c1c1c, 0x00000f70, // ICON_HOT
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_229
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_230
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_231
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_232
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_233
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_234
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_235
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_236
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_237
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_238
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_239
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_240
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_241
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_242
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_243
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_244
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_245
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_246
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_247
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_248
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_249
+ 0x00000000, 0x20803f00, 0x2a202e40, 0x20082e10, 0x08021004, 0x02040402, 0x00900108, 0x00000060, // ICON_LABEL
+ 0x00000000, 0x042007e0, 0x47e27c3e, 0x4ffa4002, 0x47fa4002, 0x4ffa4002, 0x7ffe4002, 0x00000000, // ICON_NAME_ID
+ 0x7fe00000, 0x402e4020, 0x43ce5e0a, 0x40504078, 0x438e4078, 0x402e5e0a, 0x7fe04020, 0x00000000, // ICON_SLICING
+ 0x00000000, 0x40027ffe, 0x47c24002, 0x55425d42, 0x55725542, 0x50125552, 0x10105016, 0x00001ff0, // ICON_MANUAL_CONTROL
+ 0x7ffe0000, 0x43c24002, 0x48124422, 0x500a500a, 0x500a500a, 0x44224812, 0x400243c2, 0x00007ffe, // ICON_COLLISION
+ 0x03c00000, 0x10080c30, 0x21842184, 0x4ff24182, 0x41824ff2, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_ADD
+ 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x700e7e7e, 0x7e7e700e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_ADD_FILL
+ 0x03c00000, 0x10080c30, 0x21842184, 0x41824182, 0x40024182, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_WARNING
+ 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x7e7e7e7e, 0x7ffe7e7e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_WARNING_FILL
+ 0x00000000, 0x10041ffc, 0x10841004, 0x13e41084, 0x10841084, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MORE
+ 0x00000000, 0x1ffc1ffc, 0x1f7c1ffc, 0x1c1c1f7c, 0x1f7c1f7c, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MORE_FILL
+ 0x00000000, 0x1ffc1ffc, 0x1ffc1ffc, 0x1c1c1ffc, 0x1ffc1ffc, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS
+ 0x00000000, 0x10041ffc, 0x10041004, 0x13e41004, 0x10041004, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS_FILL
+ 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x55766eba, 0x55766eaa, 0x55606ffe, 0x55606aa0, 0x00007fe0, // ICON_UNION
+ 0x07fe0000, 0x04020402, 0x7fe20402, 0x456246a2, 0x456246a2, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_INTERSECTION
+ 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x4436442a, 0x4436442a, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_DIFFERENCE
+ 0x03c00000, 0x10080c30, 0x20042004, 0x60064002, 0x47e2581a, 0x20042004, 0x0c301008, 0x000003c0, // ICON_SPHERE
+ 0x03e00000, 0x08080410, 0x0c180808, 0x08080be8, 0x08080808, 0x08080808, 0x04100808, 0x000003e0, // ICON_CYLINDER
+ 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE
+ 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID
+ 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252
@@ -1363,7 +1381,7 @@ static unsigned int *guiIconsPtr = guiIcons;
#define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties
//----------------------------------------------------------------------------------
-// Types and Structures Definition
+// Module Types and Structures Definition
//----------------------------------------------------------------------------------
// Gui control property style color element
typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement;
@@ -1387,8 +1405,7 @@ static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds
static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*()
//static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking
-static int autoCursorCooldownCounter = 0; // Cooldown frame counter for automatic cursor movement on key-down
-static int autoCursorDelayCounter = 0; // Delay frame counter for automatic cursor movement
+static int autoCursorCounter = 0; // Frame counter for automatic repeated cursor movement on key-down (cooldown and delay)
//----------------------------------------------------------------------------------
// Style data array for all gui style properties (allocated on data segment by default)
@@ -1484,7 +1501,6 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co
//----------------------------------------------------------------------------------
static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only)
-static int GetTextWidth(const char *text); // Gui get text width using gui font and style
static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds
static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor
@@ -1589,6 +1605,10 @@ int GuiWindowBox(Rectangle bounds, const char *title)
#define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24
#endif
+ #if !defined(RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT)
+ #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18
+ #endif
+
int result = 0;
//GuiState state = guiState;
@@ -1597,9 +1617,10 @@ int GuiWindowBox(Rectangle bounds, const char *title)
Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight };
if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f;
+ const float vPadding = statusBarHeight/2.0f - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT/2.0f;
Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 };
- Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 20,
- statusBar.y + statusBarHeight/2.0f - 18.0f/2.0f, 18, 18 };
+ Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT - vPadding,
+ statusBar.y + vPadding, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT };
// Update control
//--------------------------------------------------------------------
@@ -1653,7 +1674,7 @@ int GuiGroupBox(Rectangle bounds, const char *text)
// Line control
int GuiLine(Rectangle bounds, const char *text)
{
- #if !defined(RAYGUI_LINE_ORIGIN_SIZE)
+ #if !defined(RAYGUI_LINE_MARGIN_TEXT)
#define RAYGUI_LINE_MARGIN_TEXT 12
#endif
#if !defined(RAYGUI_LINE_TEXT_PADDING)
@@ -1671,7 +1692,7 @@ int GuiLine(Rectangle bounds, const char *text)
else
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
textBounds.height = bounds.height;
textBounds.x = bounds.x + RAYGUI_LINE_MARGIN_TEXT;
textBounds.y = bounds.y;
@@ -1711,8 +1732,8 @@ int GuiPanel(Rectangle bounds, const char *text)
//--------------------------------------------------------------------
if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar
- GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED: (int)LINE_COLOR)),
- GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR)));
+ GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)),
+ GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR)));
//--------------------------------------------------------------------
return result;
@@ -1722,7 +1743,7 @@ int GuiPanel(Rectangle bounds, const char *text)
// NOTE: Using GuiToggle() for the TABS
int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
{
- #define RAYGUI_TABBAR_ITEM_WIDTH 160
+ #define RAYGUI_TABBAR_ITEM_WIDTH 148
int result = -1;
//GuiState state = guiState;
@@ -1755,12 +1776,12 @@ int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
if (i == (*active))
{
toggle = true;
- GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle);
+ GuiToggle(tabBounds, text[i], &toggle);
}
else
{
toggle = false;
- GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle);
+ GuiToggle(tabBounds, text[i], &toggle);
if (toggle) *active = i;
}
@@ -2011,7 +2032,7 @@ int GuiLabelButton(Rectangle bounds, const char *text)
bool pressed = false;
// NOTE: We force bounds.width to be all text
- float textWidth = (float)GetTextWidth(text);
+ float textWidth = (float)GuiGetTextWidth(text);
if ((bounds.width - 2*GuiGetStyle(LABEL, BORDER_WIDTH) - 2*GuiGetStyle(LABEL, TEXT_PADDING)) < textWidth) bounds.width = textWidth + 2*GuiGetStyle(LABEL, BORDER_WIDTH) + 2*GuiGetStyle(LABEL, TEXT_PADDING) + 2;
// Update control
@@ -2149,7 +2170,9 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
// Get substrings items from text (items pointers)
int itemCount = 0;
- const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
+ const char **items = NULL;
+
+ if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
Rectangle slider = {
0, // Calculated later depending on the active toggle
@@ -2196,7 +2219,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
if (text != NULL)
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(text);
+ textBounds.width = (float)GuiGetTextWidth(text);
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = slider.x + slider.width/2 - textBounds.width/2;
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
@@ -2221,7 +2244,7 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked)
if (text != NULL)
{
- textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
@@ -2474,7 +2497,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod
int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
{
#if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)
- #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 40 // Frames to wait for autocursor movement
+ #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 20 // Frames to wait for autocursor movement
#endif
#if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY)
#define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement
@@ -2487,10 +2510,10 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE);
Rectangle textBounds = GetTextBounds(TEXTBOX, bounds);
- int textLength = (int)strlen(text); // Get current text length
+ int textLength = (text != NULL)? (int)strlen(text) : 0; // Get current text length
int thisCursorIndex = textBoxCursorIndex;
if (thisCursorIndex > textLength) thisCursorIndex = textLength;
- int textWidth = GetTextWidth(text) - GetTextWidth(text + thisCursorIndex);
+ int textWidth = GuiGetTextWidth(text) - GuiGetTextWidth(text + thisCursorIndex);
int textIndexOffset = 0; // Text index offset to start drawing in the box
// Cursor rectangle
@@ -2511,15 +2534,6 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
mouseCursor.x = -1;
mouseCursor.width = 1;
- // Auto-cursor movement logic
- // NOTE: Cursor moves automatically when key down after some time
- if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCooldownCounter++;
- else
- {
- autoCursorCooldownCounter = 0; // GLOBAL: Cursor cooldown counter
- autoCursorDelayCounter = 0; // GLOBAL: Cursor delay counter
- }
-
// Blink-cursor frame counter
//if (!autoCursorMode) blinkCursorFrameCounter++;
//else blinkCursorFrameCounter = 0;
@@ -2537,6 +2551,13 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if (editMode)
{
+ // GLOBAL: Auto-cursor movement logic
+ // NOTE: Keystrokes are handled repeatedly when button is held down for some time
+ if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCounter++;
+ else autoCursorCounter = 0;
+
+ bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0);
+
state = STATE_PRESSED;
if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
@@ -2550,7 +2571,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
textIndexOffset += nextCodepointSize;
- textWidth = GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex);
+ textWidth = GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex);
}
int codepoint = GetCharPressed(); // Get Unicode codepoint
@@ -2560,10 +2581,43 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
int codepointSize = 0;
const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize);
- // Add codepoint to text, at current cursor position
- // NOTE: Make sure we do not overflow buffer size
- if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize))
+ // Handle text paste action
+ if (IsKeyPressed(KEY_V) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
{
+ const char *pasteText = GetClipboardText();
+ if (pasteText != NULL)
+ {
+ int pasteLength = 0;
+ int pasteCodepoint;
+ int pasteCodepointSize;
+
+ // Count how many codepoints to copy, stopping at the first unwanted control character
+ while (true)
+ {
+ pasteCodepoint = GetCodepointNext(pasteText + pasteLength, &pasteCodepointSize);
+ if (textLength + pasteLength + pasteCodepointSize >= textSize) break;
+ if (!(multiline && (pasteCodepoint == (int)'\n')) && !(pasteCodepoint >= 32)) break;
+ pasteLength += pasteCodepointSize;
+ }
+
+ if (pasteLength > 0)
+ {
+ // Move forward data from cursor position
+ for (int i = textLength + pasteLength; i > textBoxCursorIndex; i--) text[i] = text[i - pasteLength];
+
+ // Paste data in at cursor
+ for (int i = 0; i < pasteLength; i++) text[textBoxCursorIndex + i] = pasteText[i];
+
+ textBoxCursorIndex += pasteLength;
+ textLength += pasteLength;
+ text[textLength] = '\0';
+ }
+ }
+ }
+ else if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize))
+ {
+ // Adding codepoint to text, at current cursor position
+
// Move forward data from cursor position
for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize];
@@ -2583,113 +2637,185 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
// Move cursor to end
if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
- // Delete codepoint from text, after current cursor position
- if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
+ // Delete related codepoints from text, after current cursor position
+ if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_DELETE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
{
- autoCursorDelayCounter++;
+ int offset = textBoxCursorIndex;
+ int accCodepointSize = 0;
+ int nextCodepointSize;
+ int nextCodepoint;
- if (IsKeyPressed(KEY_DELETE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
+ // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ bool puctuation = ispunct(nextCodepoint & 0xff);
+ while (offset < textLength)
{
- int nextCodepointSize = 0;
- GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
-
- // Move backward text from cursor position
- for (int i = textBoxCursorIndex; i < textLength; i++) text[i] = text[i + nextCodepointSize];
-
- textLength -= codepointSize;
- if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
-
- // Make sure text last character is EOL
- text[textLength] = '\0';
+ if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff))))
+ break;
+ offset += nextCodepointSize;
+ accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
}
+
+ // Check whitespace to delete (ASCII only)
+ while (offset < textLength)
+ {
+ if (!isspace(nextCodepoint & 0xff)) break;
+
+ offset += nextCodepointSize;
+ accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ }
+
+ // Move text after cursor forward (including final null terminator)
+ for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i];
+
+ textLength -= accCodepointSize;
+ }
+
+ else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && autoCursorShouldTrigger)))
+ {
+ // Delete single codepoint from text, after current cursor position
+
+ int nextCodepointSize = 0;
+ GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
+
+ // Move text after cursor forward (including final null terminator)
+ for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i];
+
+ textLength -= nextCodepointSize;
}
// Delete related codepoints from text, before current cursor position
- if ((textLength > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
+ if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
{
- int i = textBoxCursorIndex - 1;
+ int offset = textBoxCursorIndex;
int accCodepointSize = 0;
+ int prevCodepointSize;
+ int prevCodepoint;
- // Move cursor to the end of word if on space already
- while ((i > 0) && isspace(text[i]))
+ // Check whitespace to delete (ASCII only)
+ while (offset > 0)
{
- int prevCodepointSize = 0;
- GetCodepointPrevious(text + i, &prevCodepointSize);
- i -= prevCodepointSize;
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if (!isspace(prevCodepoint & 0xff)) break;
+
+ offset -= prevCodepointSize;
accCodepointSize += prevCodepointSize;
}
- // Move cursor to the start of the word
- while ((i > 0) && !isspace(text[i]))
+ // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ bool puctuation = ispunct(prevCodepoint & 0xff);
+ while (offset > 0)
{
- int prevCodepointSize = 0;
- GetCodepointPrevious(text + i, &prevCodepointSize);
- i -= prevCodepointSize;
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break;
+
+ offset -= prevCodepointSize;
accCodepointSize += prevCodepointSize;
}
- // Move forward text from cursor position
- for (int j = (textBoxCursorIndex - accCodepointSize); j < textLength; j++) text[j] = text[j + accCodepointSize];
+ // Move text after cursor forward (including final null terminator)
+ for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - accCodepointSize] = text[i];
- // Prevent cursor index from decrementing past 0
- if (textBoxCursorIndex > 0)
- {
- textBoxCursorIndex -= accCodepointSize;
- textLength -= accCodepointSize;
- }
+ textLength -= accCodepointSize;
+ textBoxCursorIndex -= accCodepointSize;
+ }
- // Make sure text last character is EOL
- text[textLength] = '\0';
- }
- else if ((textLength > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
+ else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && autoCursorShouldTrigger)))
{
- autoCursorDelayCounter++;
+ // Delete single codepoint from text, before current cursor position
- if (IsKeyPressed(KEY_BACKSPACE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
- {
- int prevCodepointSize = 0;
+ int prevCodepointSize = 0;
- // Prevent cursor index from decrementing past 0
- if (textBoxCursorIndex > 0)
- {
- GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
+ GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
- // Move backward text from cursor position
- for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize];
+ // Move text after cursor forward (including final null terminator)
+ for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - prevCodepointSize] = text[i];
- textBoxCursorIndex -= codepointSize;
- textLength -= codepointSize;
- }
-
- // Make sure text last character is EOL
- text[textLength] = '\0';
- }
+ textLength -= prevCodepointSize;
+ textBoxCursorIndex -= prevCodepointSize;
}
// Move cursor position with keys
- if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
+ if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_LEFT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
{
- autoCursorDelayCounter++;
+ int offset = textBoxCursorIndex;
+ //int accCodepointSize = 0;
+ int prevCodepointSize;
+ int prevCodepoint;
- if (IsKeyPressed(KEY_LEFT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
+ // Check whitespace to skip (ASCII only)
+ while (offset > 0)
{
- int prevCodepointSize = 0;
- if (textBoxCursorIndex > 0) GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if (!isspace(prevCodepoint & 0xff)) break;
- if (textBoxCursorIndex >= prevCodepointSize) textBoxCursorIndex -= prevCodepointSize;
+ offset -= prevCodepointSize;
+ //accCodepointSize += prevCodepointSize;
}
+
+ // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ bool puctuation = ispunct(prevCodepoint & 0xff);
+ while (offset > 0)
+ {
+ prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize);
+ if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break;
+
+ offset -= prevCodepointSize;
+ //accCodepointSize += prevCodepointSize;
+ }
+
+ textBoxCursorIndex = offset;
}
- else if (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
+ else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && autoCursorShouldTrigger)))
{
- autoCursorDelayCounter++;
+ int prevCodepointSize = 0;
+ GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
- if (IsKeyPressed(KEY_RIGHT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
+ textBoxCursorIndex -= prevCodepointSize;
+ }
+ else if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_RIGHT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
+ {
+ int offset = textBoxCursorIndex;
+ //int accCodepointSize = 0;
+ int nextCodepointSize;
+ int nextCodepoint;
+
+ // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace)
+ // Not using isalnum() since it only works on ASCII characters
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ bool puctuation = ispunct(nextCodepoint & 0xff);
+ while (offset < textLength)
{
- int nextCodepointSize = 0;
- GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
+ if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break;
- if ((textBoxCursorIndex + nextCodepointSize) <= textLength) textBoxCursorIndex += nextCodepointSize;
+ offset += nextCodepointSize;
+ //accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
}
+
+ // Check whitespace to skip (ASCII only)
+ while (offset < textLength)
+ {
+ if (!isspace(nextCodepoint & 0xff)) break;
+
+ offset += nextCodepointSize;
+ //accCodepointSize += nextCodepointSize;
+ nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize);
+ }
+
+ textBoxCursorIndex = offset;
+ }
+ else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && autoCursorShouldTrigger)))
+ {
+ int nextCodepointSize = 0;
+ GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
+
+ textBoxCursorIndex += nextCodepointSize;
}
// Move cursor position with mouse
@@ -2701,7 +2827,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
float widthToMouseX = 0;
int mouseCursorIndex = 0;
- for (int i = textIndexOffset; i < textLength; i++)
+ for (int i = textIndexOffset; i < textLength; i += codepointSize)
{
codepoint = GetCodepointNext(&text[i], &codepointSize);
codepointIndex = GetGlyphIndex(guiFont, codepoint);
@@ -2720,7 +2846,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
}
// Check if mouse cursor is at the last position
- int textEndWidth = GetTextWidth(text + textIndexOffset);
+ int textEndWidth = GuiGetTextWidth(text + textIndexOffset);
if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2))
{
mouseCursor.x = textBounds.x + textEndWidth;
@@ -2737,7 +2863,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
else mouseCursor.x = -1;
// Recalculate cursor position.y depending on textBoxCursorIndex
- cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING);
+ cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING);
//if (multiline) cursor.y = GetTextLines()
// Finish text editing on ENTER or mouse click outside bounds
@@ -2745,6 +2871,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
(!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
{
textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index
+ autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes
result = 1;
}
}
@@ -2757,6 +2884,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
{
textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text
+ autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes
result = 1;
}
}
@@ -2825,19 +2953,22 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int
int tempValue = *value;
- Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING), bounds.y,
- bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING)), bounds.height };
- Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
- Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
+ Rectangle valueBoxBounds = {
+ bounds.x + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING),
+ bounds.y,
+ bounds.width - 2*(GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING)), bounds.height };
+ Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height };
+ Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.y,
+ (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height };
Rectangle textBounds = { 0 };
if (text != NULL)
{
- textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
- textBounds.x = bounds.x + bounds.width + GuiGetStyle(SPINNER, TEXT_PADDING);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
- if (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SPINNER, TEXT_PADDING);
+ if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
}
// Update control
@@ -2871,20 +3002,20 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int
// Draw control
//--------------------------------------------------------------------
- result = GuiValueBox(spinner, NULL, &tempValue, minValue, maxValue, editMode);
+ result = GuiValueBox(valueBoxBounds, NULL, &tempValue, minValue, maxValue, editMode);
// Draw value selector custom buttons
// NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
- GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH));
+ GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(VALUEBOX, BORDER_WIDTH));
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
// Draw text label if provided
- GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
//--------------------------------------------------------------------
*value = tempValue;
@@ -2902,13 +3033,13 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
int result = 0;
GuiState state = guiState;
- char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
- sprintf(textValue, "%i", *value);
+ char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 };
+ snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value);
Rectangle textBounds = { 0 };
if (text != NULL)
{
- textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
@@ -2920,7 +3051,6 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
{
Vector2 mousePoint = GetMousePosition();
-
bool valueHasChanged = false;
if (editMode)
@@ -2929,30 +3059,53 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
int keyCount = (int)strlen(textValue);
- // Only allow keys in range [48..57]
- if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
+ // Add or remove minus symbol
+ if (IsKeyPressed(KEY_MINUS))
{
- if (GetTextWidth(textValue) < bounds.width)
+ if (textValue[0] == '-')
{
- int key = GetCharPressed();
- if ((key >= 48) && (key <= 57))
+ for (int i = 0 ; i < keyCount; i++) textValue[i] = textValue[i + 1];
+
+ keyCount--;
+ valueHasChanged = true;
+ }
+ else if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
+ {
+ if (keyCount == 0)
{
- textValue[keyCount] = (char)key;
+ textValue[0] = '0';
+ textValue[1] = '\0';
keyCount++;
- valueHasChanged = true;
}
+
+ for (int i = keyCount ; i > -1; i--) textValue[i + 1] = textValue[i];
+
+ textValue[0] = '-';
+ keyCount++;
+ valueHasChanged = true;
+ }
+ }
+
+ // Add new digit to text value
+ if ((keyCount >= 0) && (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) && (GuiGetTextWidth(textValue) < bounds.width))
+ {
+ int key = GetCharPressed();
+
+ // Only allow keys in range [48..57]
+ if ((key >= 48) && (key <= 57))
+ {
+ textValue[keyCount] = (char)key;
+ keyCount++;
+ valueHasChanged = true;
}
}
// Delete text
- if (keyCount > 0)
+ if ((keyCount > 0) && IsKeyPressed(KEY_BACKSPACE))
{
- if (IsKeyPressed(KEY_BACKSPACE))
- {
- keyCount--;
- textValue[keyCount] = '\0';
- valueHasChanged = true;
- }
+ keyCount--;
+ textValue[keyCount] = '\0';
+ valueHasChanged = true;
}
if (valueHasChanged) *value = TextToInteger(textValue);
@@ -2992,11 +3145,14 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor);
GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))));
- // Draw cursor
+ // Draw cursor rectangle
if (editMode)
{
// NOTE: ValueBox internal text is always centered
- Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) };
+ Rectangle cursor = { bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1,
+ bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + 2,
+ 2, bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2 - 4 };
+ if (cursor.height > bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2;
GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)));
}
@@ -3019,12 +3175,12 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float
GuiState state = guiState;
//char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
- //sprintf(textValue, "%2.2f", *value);
+ //snprintf(textValue, sizeof(textValue), "%2.2f", *value);
- Rectangle textBounds = {0};
+ Rectangle textBounds = { 0 };
if (text != NULL)
{
- textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.width = (float)GuiGetTextWidth(text) + 2;
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
@@ -3045,10 +3201,37 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float
int keyCount = (int)strlen(textValue);
+ // Add or remove minus symbol
+ if (IsKeyPressed(KEY_MINUS))
+ {
+ if (textValue[0] == '-')
+ {
+ for (int i = 0; i < keyCount; i++) textValue[i] = textValue[i + 1];
+
+ keyCount--;
+ valueHasChanged = true;
+ }
+ else if (keyCount < (RAYGUI_VALUEBOX_MAX_CHARS - 1))
+ {
+ if (keyCount == 0)
+ {
+ textValue[0] = '0';
+ textValue[1] = '\0';
+ keyCount++;
+ }
+
+ for (int i = keyCount; i > -1; i--) textValue[i + 1] = textValue[i];
+
+ textValue[0] = '-';
+ keyCount++;
+ valueHasChanged = true;
+ }
+ }
+
// Only allow keys in range [48..57]
if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
{
- if (GetTextWidth(textValue) < bounds.width)
+ if (GuiGetTextWidth(textValue) < bounds.width)
{
int key = GetCharPressed();
if (((key >= 48) && (key <= 57)) ||
@@ -3103,7 +3286,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float
if (editMode)
{
// NOTE: ValueBox internal text is always centered
- Rectangle cursor = {bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1,
+ Rectangle cursor = {bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1,
bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4,
bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH)};
GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)));
@@ -3120,7 +3303,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float
// Slider control with pro parameters
// NOTE: Other GuiSlider*() controls use this one
-int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth)
+int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
{
int result = 0;
GuiState state = guiState;
@@ -3129,6 +3312,8 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
if (value == NULL) value = &temp;
float oldValue = *value;
+ int sliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH);
+
Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) };
@@ -3146,7 +3331,7 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
{
state = STATE_PRESSED;
// Get equivalent value and slider position from mousePosition.x
- *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue;
+ *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue;
}
}
else
@@ -3166,7 +3351,7 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
if (!CheckCollisionPointRec(mousePoint, slider))
{
// Get equivalent value and slider position from mousePosition.x
- *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue;
+ *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue;
}
}
else state = STATE_FOCUSED;
@@ -3205,44 +3390,45 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)));
else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED)));
+ else if (state == STATE_DISABLED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_DISABLED)));
// Draw left/right text if provided
if (textLeft != NULL)
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(textLeft);
+ textBounds.width = (float)GuiGetTextWidth(textLeft);
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
- GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))));
+ GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
}
if (textRight != NULL)
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(textRight);
+ textBounds.width = (float)GuiGetTextWidth(textRight);
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
- GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))));
+ GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
}
//--------------------------------------------------------------------
return result;
}
-// Slider control extended, returns selected value and has text
-int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
-{
- return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH));
-}
-
// Slider Bar control extended, returns selected value
int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
{
- return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, 0);
+ int result = 0;
+ int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH);
+ GuiSetStyle(SLIDER, SLIDER_WIDTH, 0);
+ result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue);
+ GuiSetStyle(SLIDER, SLIDER_WIDTH, preSliderWidth);
+
+ return result;
}
// Progress Bar control extended, shows current progress value
@@ -3257,14 +3443,14 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight
// Progress bar
Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH),
bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0,
- bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) };
+ bounds.height - GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) -1 };
// Update control
//--------------------------------------------------------------------
if (*value > maxValue) *value = maxValue;
// WARNING: Working with floats could lead to rounding issues
- if ((state != STATE_DISABLED)) progress.width = (float)(*value/(maxValue - minValue))*bounds.width - ((*value >= maxValue)? (float)(2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)) : 0.0f);
+ if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH));
//--------------------------------------------------------------------
// Draw control
@@ -3282,15 +3468,15 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight
GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
}
- else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
- if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + 1, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
+ if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1}, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
else
{
// Draw borders not yet reached by value
- GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
- GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y + bounds.height - 1, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
- GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y + bounds.height - 1, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
}
// Draw slider internal progress bar (depends on state)
@@ -3301,23 +3487,23 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight
if (textLeft != NULL)
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(textLeft);
+ textBounds.width = (float)GuiGetTextWidth(textLeft);
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
- GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))));
+ GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
}
if (textRight != NULL)
{
Rectangle textBounds = { 0 };
- textBounds.width = (float)GetTextWidth(textRight);
+ textBounds.width = (float)GuiGetTextWidth(textRight);
textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING);
textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
- GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))));
+ GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
}
//--------------------------------------------------------------------
@@ -3467,11 +3653,11 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd
// Draw visible items
for (int i = 0; ((i < visibleItems) && (text != NULL)); i++)
{
- GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK);
+ if (GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL)) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK);
if (state == STATE_DISABLED)
{
- if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)));
+ if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)));
GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)));
}
@@ -3480,18 +3666,18 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd
if (((startIndex + i) == itemSelected) && (active != NULL))
{
// Draw item selected
- GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)));
+ GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)));
GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)));
}
else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: We want items focused, despite not returned!
{
// Draw item focused
- GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)));
+ GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)));
GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)));
}
else
{
- // Draw item normal
+ // Draw item normal (no rectangle)
GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)));
}
}
@@ -3531,22 +3717,22 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd
return result;
}
-// Color Panel control - Color (RGBA) variant.
+// Color Panel control - Color (RGBA) variant
int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
{
int result = 0;
Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f };
Vector3 hsv = ConvertRGBtoHSV(vcolor);
- Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv.
+ Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv
GuiColorPanelHSV(bounds, text, &hsv);
- // Check if the hsv was changed, only then change the color.
- // This is required, because the Color->HSV->Color conversion has precision errors.
- // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value.
- // Otherwise GuiColorPanel would often modify it's color without user input.
- // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check.
+ // Check if the hsv was changed, only then change the color
+ // This is required, because the Color->HSV->Color conversion has precision errors
+ // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value
+ // Otherwise GuiColorPanel would often modify it's color without user input
+ // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check
if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z)
{
Vector3 rgb = ConvertHSVtoRGB(hsv);
@@ -3570,7 +3756,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
int result = 0;
GuiState state = guiState;
- Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 };
+ Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2,
+ (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW),
+ (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT),
+ (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 };
// Update control
//--------------------------------------------------------------------
@@ -3617,7 +3806,6 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
// Draw control
//--------------------------------------------------------------------
-
// Draw alpha bar: checked background
if (state != STATE_DISABLED)
{
@@ -3755,7 +3943,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color)
Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height };
//Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) };
- // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used.
+ // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used
Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f });
GuiColorBarHue(boundsHue, NULL, &hsv.x);
@@ -3768,8 +3956,8 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color)
return result;
}
-// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering.
-// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB.
+// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering
+// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB
// NOTE: It's divided in multiple controls:
// int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
// int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
@@ -3917,7 +4105,7 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons
buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount;
buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT;
- //int textWidth = GetTextWidth(message) + 2;
+ //int textWidth = GuiGetTextWidth(message) + 2;
Rectangle textBounds = { 0 };
textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
@@ -3981,7 +4169,7 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co
Rectangle textBounds = { 0 };
if (message != NULL)
{
- int textSize = GetTextWidth(message) + 2;
+ int textSize = GuiGetTextWidth(message) + 2;
textBounds.x = bounds.x + bounds.width/2 - textSize/2;
textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
@@ -4221,7 +4409,7 @@ void GuiLoadStyle(const char *fileName)
if (fileDataSize > 0)
{
- unsigned char *fileData = (unsigned char *)RAYGUI_MALLOC(fileDataSize*sizeof(unsigned char));
+ unsigned char *fileData = (unsigned char *)RAYGUI_CALLOC(fileDataSize, sizeof(unsigned char));
fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile);
GuiLoadStyleFromMemory(fileData, fileDataSize);
@@ -4283,8 +4471,6 @@ void GuiLoadStyleDefault(void)
GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
GuiSetStyle(VALUEBOX, TEXT_PADDING, 0);
GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
- GuiSetStyle(SPINNER, TEXT_PADDING, 0);
- GuiSetStyle(SPINNER, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
GuiSetStyle(STATUSBAR, TEXT_PADDING, 8);
GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
@@ -4299,8 +4485,8 @@ void GuiLoadStyleDefault(void)
GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2);
GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16);
GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2);
- GuiSetStyle(SPINNER, SPIN_BUTTON_WIDTH, 24);
- GuiSetStyle(SPINNER, SPIN_BUTTON_SPACING, 2);
+ GuiSetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH, 24);
+ GuiSetStyle(VALUEBOX, SPINNER_BUTTON_SPACING, 2);
GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0);
GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0);
GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6);
@@ -4310,6 +4496,7 @@ void GuiLoadStyleDefault(void)
GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12);
GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28);
GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2);
+ GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH, 1);
GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12);
GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE);
GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8);
@@ -4322,8 +4509,8 @@ void GuiLoadStyleDefault(void)
{
// Unload previous font texture
UnloadTexture(guiFont.texture);
- RL_FREE(guiFont.recs);
- RL_FREE(guiFont.glyphs);
+ RAYGUI_FREE(guiFont.recs);
+ RAYGUI_FREE(guiFont.glyphs);
guiFont.recs = NULL;
guiFont.glyphs = NULL;
@@ -4352,7 +4539,7 @@ const char *GuiIconText(int iconId, const char *text)
if (text != NULL)
{
memset(buffer, 0, 1024);
- sprintf(buffer, "#%03i#", iconId);
+ snprintf(buffer, 1024, "#%03i#", iconId);
for (int i = 5; i < 1024; i++)
{
@@ -4364,7 +4551,7 @@ const char *GuiIconText(int iconId, const char *text)
}
else
{
- sprintf(iconBuffer, "#%03i#", iconId);
+ snprintf(iconBuffer, 16, "#%03i#", iconId);
return iconBuffer;
}
@@ -4430,17 +4617,17 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName)
{
if (loadIconsName)
{
- guiIconsName = (char **)RAYGUI_MALLOC(iconCount*sizeof(char **));
+ guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *));
for (int i = 0; i < iconCount; i++)
{
- guiIconsName[i] = (char *)RAYGUI_MALLOC(RAYGUI_ICON_MAX_NAME_LENGTH);
+ guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char));
fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile);
}
}
else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR);
// Read icons data directly over internal icons array
- fread(guiIconsPtr, sizeof(unsigned int), iconCount*(iconSize*iconSize/32), rgiFile);
+ fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile);
}
fclose(rgiFile);
@@ -4449,6 +4636,56 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName)
return guiIconsName;
}
+// Load icons from memory
+// WARNING: Binary files only
+char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName)
+{
+ unsigned char *fileDataPtr = (unsigned char *)fileData;
+ char **guiIconsName = NULL;
+
+ char signature[5] = { 0 };
+ short version = 0;
+ short reserved = 0;
+ short iconCount = 0;
+ short iconSize = 0;
+
+ memcpy(signature, fileDataPtr, 4);
+ memcpy(&version, fileDataPtr + 4, sizeof(short));
+ memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short));
+ memcpy(&iconCount, fileDataPtr + 4 + 2 + 2, sizeof(short));
+ memcpy(&iconSize, fileDataPtr + 4 + 2 + 2 + 2, sizeof(short));
+ fileDataPtr += 12;
+
+ if ((signature[0] == 'r') &&
+ (signature[1] == 'G') &&
+ (signature[2] == 'I') &&
+ (signature[3] == ' '))
+ {
+ if (loadIconsName)
+ {
+ guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *));
+ for (int i = 0; i < iconCount; i++)
+ {
+ guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char));
+ memcpy(guiIconsName[i], fileDataPtr, RAYGUI_ICON_MAX_NAME_LENGTH);
+ fileDataPtr += RAYGUI_ICON_MAX_NAME_LENGTH;
+ }
+ }
+ else
+ {
+ // Skip icon name data if not required
+ fileDataPtr += iconCount*RAYGUI_ICON_MAX_NAME_LENGTH;
+ }
+
+ int iconDataSize = iconCount*((int)iconSize*(int)iconSize/32)*(int)sizeof(unsigned int);
+ guiIconsPtr = (unsigned int *)RAYGUI_CALLOC(iconDataSize, 1);
+
+ memcpy(guiIconsPtr, fileDataPtr, iconDataSize);
+ }
+
+ return guiIconsName;
+}
+
// Draw selected icon using rectangles pixel-by-pixel
void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color)
{
@@ -4476,12 +4713,73 @@ void GuiSetIconScale(int scale)
if (scale >= 1) guiIconScale = scale;
}
+// Get text width considering gui style and icon size (if required)
+int GuiGetTextWidth(const char *text)
+{
+ #if !defined(ICON_TEXT_PADDING)
+ #define ICON_TEXT_PADDING 4
+ #endif
+
+ Vector2 textSize = { 0 };
+ int textIconOffset = 0;
+
+ if ((text != NULL) && (text[0] != '\0'))
+ {
+ if (text[0] == '#')
+ {
+ for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
+ {
+ if (text[i] == '#')
+ {
+ textIconOffset = i;
+ break;
+ }
+ }
+ }
+
+ text += textIconOffset;
+
+ // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
+ float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+
+ // Custom MeasureText() implementation
+ if ((guiFont.texture.id > 0) && (text != NULL))
+ {
+ // Get size in bytes of text, considering end of line and line break
+ int size = 0;
+ for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++)
+ {
+ if ((text[i] != '\0') && (text[i] != '\n')) size++;
+ else break;
+ }
+
+ float scaleFactor = fontSize/(float)guiFont.baseSize;
+ textSize.y = (float)guiFont.baseSize*scaleFactor;
+ float glyphWidth = 0.0f;
+
+ for (int i = 0, codepointSize = 0; i < size; i += codepointSize)
+ {
+ int codepoint = GetCodepointNext(&text[i], &codepointSize);
+ int codepointIndex = GetGlyphIndex(guiFont, codepoint);
+
+ if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
+ else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
+
+ textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ }
+ }
+
+ if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING);
+ }
+
+ return (int)textSize.x;
+}
+
#endif // !RAYGUI_NO_ICONS
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
-
// Load style from memory
// WARNING: Binary files only
static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
@@ -4567,7 +4865,7 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
{
// Compressed font atlas image data (DEFLATE), it requires DecompressData()
int dataUncompSize = 0;
- unsigned char *compData = (unsigned char *)RAYGUI_MALLOC(fontImageCompSize);
+ unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char));
memcpy(compData, fileDataPtr, fontImageCompSize);
fileDataPtr += fontImageCompSize;
@@ -4581,7 +4879,7 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
else
{
// Font atlas image data is not compressed
- imFont.data = (unsigned char *)RAYGUI_MALLOC(fontImageUncompSize);
+ imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char));
memcpy(imFont.data, fileDataPtr, fontImageUncompSize);
fileDataPtr += fontImageUncompSize;
}
@@ -4609,7 +4907,7 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize))
{
// Recs data is compressed, uncompress it
- unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_MALLOC(recsDataCompressedSize);
+ unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char));
memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize);
fileDataPtr += recsDataCompressedSize;
@@ -4651,7 +4949,7 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize))
{
// Glyphs data is compressed, uncompress it
- unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_MALLOC(glyphsDataCompressedSize);
+ unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char));
memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize);
fileDataPtr += glyphsDataCompressedSize;
@@ -4704,68 +5002,6 @@ static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
}
}
-// Gui get text width considering icon
-static int GetTextWidth(const char *text)
-{
- #if !defined(ICON_TEXT_PADDING)
- #define ICON_TEXT_PADDING 4
- #endif
-
- Vector2 textSize = { 0 };
- int textIconOffset = 0;
-
- if ((text != NULL) && (text[0] != '\0'))
- {
- if (text[0] == '#')
- {
- for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
- {
- if (text[i] == '#')
- {
- textIconOffset = i;
- break;
- }
- }
- }
-
- text += textIconOffset;
-
- // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
- float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
-
- // Custom MeasureText() implementation
- if ((guiFont.texture.id > 0) && (text != NULL))
- {
- // Get size in bytes of text, considering end of line and line break
- int size = 0;
- for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++)
- {
- if ((text[i] != '\0') && (text[i] != '\n')) size++;
- else break;
- }
-
- float scaleFactor = fontSize/(float)guiFont.baseSize;
- textSize.y = (float)guiFont.baseSize*scaleFactor;
- float glyphWidth = 0.0f;
-
- for (int i = 0, codepointSize = 0; i < size; i += codepointSize)
- {
- int codepoint = GetCodepointNext(&text[i], &codepointSize);
- int codepointIndex = GetGlyphIndex(guiFont, codepoint);
-
- if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
- else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
-
- textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
- }
- }
-
- if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING);
- }
-
- return (int)textSize.x;
-}
-
// Get text bounds considering control bounds
static Rectangle GetTextBounds(int control, Rectangle bounds)
{
@@ -4786,7 +5022,7 @@ static Rectangle GetTextBounds(int control, Rectangle bounds)
case SLIDER:
case CHECKBOX:
case VALUEBOX:
- case SPINNER:
+ case CONTROL11:
// TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER
default:
{
@@ -4832,7 +5068,8 @@ static const char *GetTextIcon(const char *text, int *iconId)
}
// Get text divided into lines (by line-breaks '\n')
-const char **GetTextLines(const char *text, int *count)
+// WARNING: It returns pointers to new lines but it does not add NULL ('\0') terminator!
+static const char **GetTextLines(const char *text, int *count)
{
#define RAYGUI_MAX_TEXT_LINES 128
@@ -4842,25 +5079,18 @@ const char **GetTextLines(const char *text, int *count)
int textSize = (int)strlen(text);
lines[0] = text;
- int len = 0;
*count = 1;
- //int lineSize = 0; // Stores current line size, not returned
for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
{
if (text[i] == '\n')
{
- //lineSize = len;
k++;
- lines[k] = &text[i + 1]; // WARNING: next value is valid?
- len = 0;
+ lines[k] = &text[i + 1]; // WARNING: next value is valid?
*count += 1;
}
- else len++;
}
- //lines[*count - 1].size = len;
-
return lines;
}
@@ -4936,8 +5166,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
float textBoundsWidthOffset = 0.0f;
// NOTE: We get text size after icon has been processed
- // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed?
- int textSizeX = GetTextWidth(lines[i]);
+ // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed?
+ int textSizeX = GuiGetTextWidth(lines[i]);
// If text requires an icon, add size to measure
if (iconId >= 0)
@@ -5000,7 +5230,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
float textOffsetX = 0.0f;
float glyphWidth = 0;
- int ellipsisWidth = GetTextWidth("...");
+ int ellipsisWidth = GuiGetTextWidth("...");
bool textOverflow = false;
for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize)
{
@@ -5144,13 +5374,13 @@ static void GuiTooltip(Rectangle controlRec)
if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width);
- GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, NULL);
+ GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, NULL);
int textPadding = GuiGetStyle(LABEL, TEXT_PADDING);
int textAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
GuiSetStyle(LABEL, TEXT_PADDING, 0);
GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
- GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, guiTooltipPtr);
+ GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, guiTooltipPtr);
GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment);
GuiSetStyle(LABEL, TEXT_PADDING, textPadding);
}
@@ -5204,7 +5434,7 @@ static const char **GuiTextSplit(const char *text, char delimiter, int *count, i
buffer[i] = '\0'; // Set an end of string at this point
counter++;
- if (counter > RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
+ if (counter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
}
}
@@ -5526,10 +5756,10 @@ static Color GetColor(int hexValue)
{
Color color;
- color.r = (unsigned char)(hexValue >> 24) & 0xFF;
- color.g = (unsigned char)(hexValue >> 16) & 0xFF;
- color.b = (unsigned char)(hexValue >> 8) & 0xFF;
- color.a = (unsigned char)hexValue & 0xFF;
+ color.r = (unsigned char)(hexValue >> 24) & 0xff;
+ color.g = (unsigned char)(hexValue >> 16) & 0xff;
+ color.b = (unsigned char)(hexValue >> 8) & 0xff;
+ color.a = (unsigned char)hexValue & 0xff;
return color;
}
@@ -5562,7 +5792,7 @@ static const char *TextFormat(const char *text, ...)
va_list args;
va_start(args, text);
- vsprintf(buffer, text, args);
+ vsnprintf(buffer, RAYGUI_TEXTFORMAT_MAX_SIZE, text, args);
va_end(args);
return buffer;
@@ -5731,7 +5961,7 @@ static int GetCodepointNext(const char *text, int *codepointSize)
}
else if (0xe0 == (0xf0 & ptr[0]))
{
- // 3 byte UTF-8 codepoint */
+ // 3 byte UTF-8 codepoint
if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks
codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]);
*codepointSize = 3;
diff --git a/examples/shapes/shapes_bouncing_ball.c b/examples/shapes/shapes_bouncing_ball.c
index 5ae699944..d55c47f56 100644
--- a/examples/shapes/shapes_bouncing_ball.c
+++ b/examples/shapes/shapes_bouncing_ball.c
@@ -7,7 +7,7 @@
* Example originally created with raylib 2.5, last time updated with raylib 2.5
*
* Example contributed by Ramon Santamaria (@raysan5), reviewed by Jopestpe (@jopestpe)
-*
+*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
@@ -49,14 +49,14 @@ int main(void)
//-----------------------------------------------------
if (IsKeyPressed(KEY_G)) useGravity = !useGravity;
if (IsKeyPressed(KEY_SPACE)) pause = !pause;
-
+
if (!pause)
{
ballPosition.x += ballSpeed.x;
ballPosition.y += ballSpeed.y;
if (useGravity) ballSpeed.y += gravity;
-
+
// Check walls collision for bouncing
if ((ballPosition.x >= (GetScreenWidth() - ballRadius)) || (ballPosition.x <= ballRadius)) ballSpeed.x *= -1.0f;
if ((ballPosition.y >= (GetScreenHeight() - ballRadius)) || (ballPosition.y <= ballRadius)) ballSpeed.y *= -0.95f;
@@ -72,7 +72,7 @@ int main(void)
DrawCircleV(ballPosition, (float)ballRadius, MAROON);
DrawText("PRESS SPACE to PAUSE BALL MOVEMENT", 10, GetScreenHeight() - 25, 20, LIGHTGRAY);
-
+
if (useGravity) DrawText("GRAVITY: ON (Press G to disable)", 10, GetScreenHeight() - 50, 20, DARKGREEN);
else DrawText("GRAVITY: OFF (Press G to enable)", 10, GetScreenHeight() - 50, 20, RED);
@@ -80,7 +80,7 @@ int main(void)
if (pause && ((framesCounter/30)%2)) DrawText("PAUSED", 350, 200, 30, GRAY);
DrawFPS(10, 10);
-
+
EndDrawing();
//-----------------------------------------------------
}
diff --git a/examples/shapes/shapes_bullet_hell.c b/examples/shapes/shapes_bullet_hell.c
index 235df4d16..2ff3be14b 100644
--- a/examples/shapes/shapes_bullet_hell.c
+++ b/examples/shapes/shapes_bullet_hell.c
@@ -107,7 +107,7 @@ int main(void)
float bulletDirection = baseDirection + (degreesPerRow*row);
- // Bullet speed * bullet direction, this will determine how much pixels will be incremented/decremented
+ // Bullet speed*bullet direction, this will determine how much pixels will be incremented/decremented
// from the bullet position every frame. Since the bullets doesn't change its direction and speed,
// only need to calculate it at the spawning time
// 0 degrees = right, 90 degrees = down, 180 degrees = left and 270 degrees = up, basically clockwise
@@ -197,7 +197,7 @@ int main(void)
bullets[i].color);
}
}
- }
+ }
else
{
// Draw bullets using DrawCircle(), less performant
diff --git a/examples/shapes/shapes_clock_of_clocks.c b/examples/shapes/shapes_clock_of_clocks.c
index 493e53b5e..d87ec6411 100644
--- a/examples/shapes/shapes_clock_of_clocks.c
+++ b/examples/shapes/shapes_clock_of_clocks.c
@@ -32,14 +32,14 @@ int main(void)
SetConfigFlags(FLAG_MSAA_4X_HINT);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - clock of clocks");
-
+
const Color bgColor = ColorLerp(DARKBLUE, BLACK, 0.75f);
const Color handsColor = ColorLerp(YELLOW, RAYWHITE, .25f);
-
+
const float clockFaceSize = 24;
const float clockFaceSpacing = 8.0f;
const float sectionSpacing = 16.0f;
-
+
const Vector2 TL = (Vector2){ 0.0f, 90.0f }; // Top-left corner
const Vector2 TR = (Vector2){ 90.0f, 180.0f }; // Top-right corner
const Vector2 BR = (Vector2){ 180.0f, 270.0f }; // Bottom-right corner
@@ -47,7 +47,7 @@ int main(void)
const Vector2 HH = (Vector2){ 0.0f, 180.0f }; // Horizontal line
const Vector2 VV = (Vector2){ 90.0f, 270.0f }; // Vertical line
const Vector2 ZZ = (Vector2){ 135.0f, 135.0f }; // Not relevant
-
+
const Vector2 digitAngles[10][24] = {
/* 0 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,VV,VV,VV,/* */ VV,VV,VV,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR },
/* 1 */ { TL,HH,TR,ZZ, /* */ BL,TR,VV,ZZ,/* */ ZZ,VV,VV,ZZ,/* */ ZZ,VV,VV,ZZ,/* */ TL,BR,BL,TR,/* */ BL,HH,HH,BR },
@@ -60,24 +60,16 @@ int main(void)
/* 8 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,HH,BR },
/* 9 */ { TL,HH,HH,TR, /* */ VV,TL,TR,VV,/* */ VV,BL,BR,VV,/* */ BL,HH,TR,VV,/* */ TL,HH,BR,VV,/* */ BL,HH,HH,BR },
};
+
// Time for the hands to move to the new position (in seconds); this must be <1s
- const float handsMoveDuration = .5f;
-
- // We store the previous seconds value so we can see if the time has changed
+ const float handsMoveDuration = 0.5f;
+
int prevSeconds = -1;
-
- // This represents the real position where the hands are right now
Vector2 currentAngles[6][24] = { 0 };
-
- // This is the position where the hands were moving from
Vector2 srcAngles[6][24] = { 0 };
- // This is the position where the hands are moving to
Vector2 dstAngles[6][24] = { 0 };
-
- // Current animation timer
+
float handsMoveTimer = 0.0f;
-
- // 12 or 24 hour mode
int hourMode = 24;
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
@@ -88,77 +80,64 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
-
// Get the current time
time_t rawtime;
struct tm *timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
-
- if (timeinfo->tm_sec != prevSeconds) {
+
+ if (timeinfo->tm_sec != prevSeconds)
+ {
// The time has changed, so we need to move the hands to the new positions
prevSeconds = timeinfo->tm_sec;
-
+
// Format the current time so we can access the individual digits
- const char *clockDigits = TextFormat("%02d%02d%02d", timeinfo->tm_hour % hourMode, timeinfo->tm_min, timeinfo->tm_sec);
-
+ const char *clockDigits = TextFormat("%02d%02d%02d", timeinfo->tm_hour%hourMode, timeinfo->tm_min, timeinfo->tm_sec);
+
// Fetch where we want all the hands to be
- for (int digit = 0; digit < 6; digit++) {
- for (int cell = 0; cell < 24; cell++) {
+ for (int digit = 0; digit < 6; digit++)
+ {
+ for (int cell = 0; cell < 24; cell++)
+ {
srcAngles[digit][cell] = currentAngles[digit][cell];
- dstAngles[digit][cell] = digitAngles[ clockDigits[digit] - '0' ][cell];
-
+ dstAngles[digit][cell] = digitAngles[clockDigits[digit] - '0'][cell];
+
// Quick exception for 12h mode
- if (digit == 0 && hourMode == 12 && clockDigits[0] == '0') {
- dstAngles[digit][cell] = ZZ;
- }
-
- if (srcAngles[digit][cell].x > dstAngles[digit][cell].x) {
- srcAngles[digit][cell].x -= 360.0f;
- }
- if (srcAngles[digit][cell].y > dstAngles[digit][cell].y) {
- srcAngles[digit][cell].y -= 360.0f;
- }
+ if ((digit == 0) && (hourMode == 12) && (clockDigits[0] == '0')) dstAngles[digit][cell] = ZZ;
+ if (srcAngles[digit][cell].x > dstAngles[digit][cell].x) srcAngles[digit][cell].x -= 360.0f;
+ if (srcAngles[digit][cell].y > dstAngles[digit][cell].y) srcAngles[digit][cell].y -= 360.0f;
}
}
-
+
// Reset the timer
handsMoveTimer = -GetFrameTime();
}
-
+
// Now let's animate all the hands if we need to
- if (handsMoveTimer < handsMoveDuration) {
+ if (handsMoveTimer < handsMoveDuration)
+ {
// Increase the timer but don't go above the maximum
handsMoveTimer = Clamp(handsMoveTimer + GetFrameTime(), 0, handsMoveDuration);
-
- // Calculate the % completion of the animation
- float t = handsMoveTimer / handsMoveDuration;
-
+
+ // Calculate the%completion of the animation
+ float t = handsMoveTimer/handsMoveDuration;
+
// A little cheeky smoothstep
- t = t * t * (3.0f - 2.0f * t);
-
- for (int digit = 0; digit < 6; digit++) {
- for (int cell = 0; cell < 24; cell++) {
+ t = t*t*(3.0f - 2.0f*t);
+
+ for (int digit = 0; digit < 6; digit++)
+ {
+ for (int cell = 0; cell < 24; cell++)
+ {
currentAngles[digit][cell].x = Lerp(srcAngles[digit][cell].x, dstAngles[digit][cell].x, t);
currentAngles[digit][cell].y = Lerp(srcAngles[digit][cell].y, dstAngles[digit][cell].y, t);
}
}
-
- if (handsMoveTimer == handsMoveDuration) {
- // The animation has now finished
- }
}
-
+
// Handle input
-
- // Toggle between 12 and 24 hour mode with space
- if (IsKeyPressed(KEY_SPACE)) {
- hourMode = 36 - hourMode;
- }
-
-
-
+ if (IsKeyPressed(KEY_SPACE)) hourMode = 36 - hourMode; // Toggle between 12 and 24 hour mode with space
//----------------------------------------------------------------------------------
// Draw
@@ -166,52 +145,52 @@ int main(void)
BeginDrawing();
ClearBackground(bgColor);
-
+
DrawText(TextFormat("%d-h mode, space to change", hourMode), 10, 30, 20, RAYWHITE);
-
+
float xOffset = 4.0f;
-
- for (int digit = 0; digit < 6; digit++) {
-
- for (int row = 0; row < 6; row++) {
- for (int col = 0; col < 4; col++) {
+
+ for (int digit = 0; digit < 6; digit++)
+ {
+ for (int row = 0; row < 6; row++)
+ {
+ for (int col = 0; col < 4; col++)
+ {
Vector2 centre = (Vector2){
- xOffset + col*(clockFaceSize+clockFaceSpacing) + clockFaceSize * .5f,
- 100 + row*(clockFaceSize+clockFaceSpacing) + clockFaceSize * .5f
+ xOffset + col*(clockFaceSize+clockFaceSpacing) + clockFaceSize*0.5f,
+ 100 + row*(clockFaceSize+clockFaceSpacing) + clockFaceSize*0.5f
};
- DrawRing(centre, clockFaceSize * 0.5f - 2.0f, clockFaceSize * 0.5f, 0, 360, 24, DARKGRAY);
-
+
+ DrawRing(centre, clockFaceSize*0.5f - 2.0f, clockFaceSize*0.5f, 0, 360, 24, DARKGRAY);
+
// Big hand
DrawRectanglePro(
- (Rectangle){centre.x, centre.y, clockFaceSize*.5f+4.0f, 4.0f},
+ (Rectangle){centre.x, centre.y, clockFaceSize*0.5f+4.0f, 4.0f},
(Vector2){ 2.0f, 2.0f },
currentAngles[digit][row*4+col].x,
handsColor
);
-
+
// Little hand
DrawRectanglePro(
- (Rectangle){centre.x, centre.y, clockFaceSize*.5f+2.0f, 4.0f},
+ (Rectangle){centre.x, centre.y, clockFaceSize*0.5f+2.0f, 4.0f},
(Vector2){ 2.0f, 2.0f },
currentAngles[digit][row*4+col].y,
handsColor
);
}
}
-
- xOffset += (clockFaceSize+clockFaceSpacing) * 4;
- if (digit % 2 == 1) {
-
+
+ xOffset += (clockFaceSize+clockFaceSpacing)*4;
+ if (digit%2 == 1)
+ {
DrawRing((Vector2){xOffset + 4.0f, 160.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor);
DrawRing((Vector2){xOffset + 4.0f, 225.0f}, 6.0f, 8.0f, 0.0f, 360.0f, 24, handsColor);
-
xOffset += sectionSpacing;
-
}
}
-
+
DrawFPS(10, 10);
-
EndDrawing();
//----------------------------------------------------------------------------------
@@ -219,7 +198,6 @@ int main(void)
// De-Initialization
//--------------------------------------------------------------------------------------
-
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
diff --git a/examples/shapes/shapes_digital_clock.c b/examples/shapes/shapes_digital_clock.c
index 77b020704..cca3f3c44 100644
--- a/examples/shapes/shapes_digital_clock.c
+++ b/examples/shapes/shapes_digital_clock.c
@@ -116,7 +116,7 @@ int main(void)
ClearBackground(RAYWHITE);
// Draw clock in selected mode
- if (clockMode == CLOCK_ANALOG) DrawClockAnalog(clock, (Vector2){ 400, 240 });
+ if (clockMode == CLOCK_ANALOG) DrawClockAnalog(clock, (Vector2){ 400, 240 });
else if (clockMode == CLOCK_DIGITAL)
{
DrawClockDigital(clock, (Vector2){ 30, 60 });
@@ -128,7 +128,7 @@ int main(void)
DrawText(clockTime, GetScreenWidth()/2 - MeasureText(clockTime, 150)/2, 300, 150, BLACK);
}
- DrawText(TextFormat("Press [SPACE] to switch clock mode: %s",
+ DrawText(TextFormat("Press [SPACE] to switch clock mode: %s",
(clockMode == CLOCK_DIGITAL)? "DIGITAL CLOCK" : "ANALOGUE CLOCK"), 10, 10, 20, DARKGRAY);
EndDrawing();
@@ -183,13 +183,13 @@ static void DrawClockAnalog(Clock clock, Vector2 position)
// Draw clock minutes/seconds lines
for (int i = 0; i < 60; i++)
{
- DrawLineEx((Vector2){ position.x + (clock.second.length + ((i%5)? 10 : 6))*cosf((6.0f*i - 90.0f)*DEG2RAD),
- position.y + (clock.second.length + ((i%5)? 10 : 6))*sinf((6.0f*i - 90.0f)*DEG2RAD) },
- (Vector2){ position.x + (clock.second.length + 20)*cosf((6.0f*i - 90.0f)*DEG2RAD),
+ DrawLineEx((Vector2){ position.x + (clock.second.length + ((i%5)? 10 : 6))*cosf((6.0f*i - 90.0f)*DEG2RAD),
+ position.y + (clock.second.length + ((i%5)? 10 : 6))*sinf((6.0f*i - 90.0f)*DEG2RAD) },
+ (Vector2){ position.x + (clock.second.length + 20)*cosf((6.0f*i - 90.0f)*DEG2RAD),
position.y + (clock.second.length + 20)*sinf((6.0f*i - 90.0f)*DEG2RAD) }, ((i%5)? 1.0f : 3.0f), DARKGRAY);
-
+
// Draw seconds numbers
- //DrawText(TextFormat("%02i", i), centerPosition.x + (clock.second.length + 50)*cosf((6.0f*i - 90.0f)*DEG2RAD) - 10/2,
+ //DrawText(TextFormat("%02i", i), centerPosition.x + (clock.second.length + 50)*cosf((6.0f*i - 90.0f)*DEG2RAD) - 10/2,
// centerPosition.y + (clock.second.length + 50)*sinf((6.0f*i - 90.0f)*DEG2RAD) - 10/2, 10, GRAY);
}
@@ -256,25 +256,25 @@ static void Draw7SDisplay(Vector2 position, char segments, Color colorOn, Color
float offsetYAdjust = segmentThick*0.3f; // HACK: Adjust gap space between segment limits
// Segment A
- DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen/2.0f, position.y + segmentThick },
+ DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen/2.0f, position.y + segmentThick },
segmentLen, segmentThick, false, (segments & 0b00000001)? colorOn : colorOff);
// Segment B
- DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen + segmentThick/2.0f, position.y + 2*segmentThick + segmentLen/2.0f - offsetYAdjust },
+ DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen + segmentThick/2.0f, position.y + 2*segmentThick + segmentLen/2.0f - offsetYAdjust },
segmentLen, segmentThick, true, (segments & 0b00000010)? colorOn : colorOff);
// Segment C
- DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen + segmentThick/2.0f, position.y + 4*segmentThick + segmentLen + segmentLen/2.0f - 3*offsetYAdjust },
+ DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen + segmentThick/2.0f, position.y + 4*segmentThick + segmentLen + segmentLen/2.0f - 3*offsetYAdjust },
segmentLen, segmentThick, true, (segments & 0b00000100)? colorOn : colorOff);
// Segment D
- DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen/2.0f, position.y + 5*segmentThick + 2*segmentLen - 4*offsetYAdjust },
+ DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen/2.0f, position.y + 5*segmentThick + 2*segmentLen - 4*offsetYAdjust },
segmentLen, segmentThick, false, (segments & 0b00001000)? colorOn : colorOff);
// Segment E
- DrawDisplaySegment((Vector2){ position.x + segmentThick/2.0f, position.y + 4*segmentThick + segmentLen + segmentLen/2.0f - 3*offsetYAdjust },
+ DrawDisplaySegment((Vector2){ position.x + segmentThick/2.0f, position.y + 4*segmentThick + segmentLen + segmentLen/2.0f - 3*offsetYAdjust },
segmentLen, segmentThick, true, (segments & 0b00010000)? colorOn : colorOff);
// Segment F
- DrawDisplaySegment((Vector2){ position.x + segmentThick/2.0f, position.y + 2*segmentThick + segmentLen/2.0f - offsetYAdjust },
+ DrawDisplaySegment((Vector2){ position.x + segmentThick/2.0f, position.y + 2*segmentThick + segmentLen/2.0f - offsetYAdjust },
segmentLen, segmentThick, true, (segments & 0b00100000)? colorOn : colorOff);
// Segment G
- DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen/2.0f, position.y + 3*segmentThick + segmentLen - 2*offsetYAdjust },
+ DrawDisplaySegment((Vector2){ position.x + segmentThick + segmentLen/2.0f, position.y + 3*segmentThick + segmentLen - 2*offsetYAdjust },
segmentLen, segmentThick, false, (segments & 0b01000000)? colorOn : colorOff);
}
@@ -284,11 +284,13 @@ static void DrawDisplaySegment(Vector2 center, int length, int thick, bool verti
if (!vertical)
{
// Horizontal segment points
- // 3___________________________5
- // / \
- // /1 x 6\
- // \ /
- // \2___________________________4/
+ /*
+ 3___________________________5
+ / \
+ /1 x 6\
+ \ /
+ \2___________________________4/
+ */
Vector2 segmentPointsH[6] = {
(Vector2){ center.x - length/2.0f - thick/2.0f, center.y }, // Point 1
(Vector2){ center.x - length/2.0f, center.y + thick/2.0f }, // Point 2
diff --git a/examples/shapes/shapes_double_pendulum.c b/examples/shapes/shapes_double_pendulum.c
index 4bcac02f9..cbf487f93 100644
--- a/examples/shapes/shapes_double_pendulum.c
+++ b/examples/shapes/shapes_double_pendulum.c
@@ -76,7 +76,7 @@ int main(void)
float step = dt/SIMULATION_STEPS, step2 = step*step;
// Update Physics - larger steps = better approximation
- for (int i = 0; i < SIMULATION_STEPS; ++i)
+ for (int i = 0; i < SIMULATION_STEPS; i++)
{
float delta = theta1 - theta2;
float sinD = sinf(delta), cosD = cosf(delta), cos2D = cosf(2*delta);
diff --git a/examples/shapes/shapes_kaleidoscope.c b/examples/shapes/shapes_kaleidoscope.c
index 07c96344c..119fca598 100644
--- a/examples/shapes/shapes_kaleidoscope.c
+++ b/examples/shapes/shapes_kaleidoscope.c
@@ -11,13 +11,29 @@
* 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 Hugo ARNAL (@hugoarnal)
+* Copyright (c) 2025 Hugo ARNAL (@hugoarnal) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
+#include
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"
#include "raymath.h"
+#define MAX_DRAW_LINES 8192
+
+// Line data type
+typedef struct {
+ Vector2 start;
+ Vector2 end;
+} Line;
+
+// Lines array as a global static variable to be stored
+// in heap and avoid potential stack overflow (on Web platform)
+static Line lines[MAX_DRAW_LINES] = { 0 };
+
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
@@ -30,22 +46,31 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - kaleidoscope");
+ // Line drawing properties
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 };
+ Vector2 mousePos = { 0 };
Vector2 prevMousePos = { 0 };
-
- SetTargetFPS(60);
- ClearBackground(BLACK);
-
+ Vector2 scaleVector = { 1.0f, -1.0f };
Vector2 offset = { (float)screenWidth/2.0f, (float)screenHeight/2.0f };
+
Camera2D camera = { 0 };
camera.target = (Vector2){ 0 };
camera.offset = offset;
camera.rotation = 0.0f;
camera.zoom = 1.0f;
- Vector2 scaleVector = { 1.0f, -1.0f };
+ int currentLineCounter = 0;
+ int totalLineCounter = 0;
+ int resetButtonClicked = false;
+ int backButtonClicked = false;
+ int nextButtonClicked = false;
+
+ SetTargetFPS(20);
//--------------------------------------------------------------------------------------
// Main game loop
@@ -53,38 +78,93 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
- Vector2 mousePos = GetMousePosition();
+ prevMousePos = mousePos;
+ mousePos = GetMousePosition();
+
Vector2 lineStart = Vector2Subtract(mousePos, offset);
Vector2 lineEnd = Vector2Subtract(prevMousePos, offset);
+
+ if (
+ IsMouseButtonDown(MOUSE_LEFT_BUTTON)
+ && (CheckCollisionPointRec(mousePos, resetButtonRec) == false)
+ && (CheckCollisionPointRec(mousePos, backButtonRec) == false)
+ && (CheckCollisionPointRec(mousePos, nextButtonRec) == false)
+ )
+ {
+ for (int s = 0; (s < symmetry) && (totalLineCounter < (MAX_DRAW_LINES - 1)); s++)
+ {
+ lineStart = Vector2Rotate(lineStart, angle*DEG2RAD);
+ lineEnd = Vector2Rotate(lineEnd, angle*DEG2RAD);
+
+ // Store mouse line
+ lines[totalLineCounter].start = lineStart;
+ lines[totalLineCounter].end = lineEnd;
+
+ // Store reflective line
+ lines[totalLineCounter + 1].start = Vector2Multiply(lineStart, scaleVector);
+ lines[totalLineCounter + 1].end = Vector2Multiply(lineEnd, scaleVector);
+
+ totalLineCounter += 2;
+ currentLineCounter = totalLineCounter;
+ }
+ }
+
+ if (resetButtonClicked)
+ {
+ memset(&lines, 0, sizeof(Line)*MAX_DRAW_LINES);
+ currentLineCounter = 0;
+ totalLineCounter = 0;
+ }
+
+ if (backButtonClicked && (currentLineCounter > 0))
+ {
+ currentLineCounter -= 1;
+ }
+
+ if (nextButtonClicked && (currentLineCounter < MAX_DRAW_LINES) && ((currentLineCounter + 1) <= totalLineCounter))
+ {
+ currentLineCounter += 1;
+ }
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
+
+ ClearBackground(RAYWHITE);
BeginMode2D(camera);
- if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
- for (int i = 0; i < symmetry; i++) {
- lineStart = Vector2Rotate(lineStart, angle*DEG2RAD);
- lineEnd = Vector2Rotate(lineEnd, angle*DEG2RAD);
- DrawLineEx(lineStart, lineEnd, thickness, WHITE);
-
- Vector2 reflectLineStart = Vector2Multiply(lineStart, scaleVector);
- Vector2 reflectLineEnd = Vector2Multiply(lineEnd, scaleVector);
-
- DrawLineEx(reflectLineStart, reflectLineEnd, thickness, WHITE);
+ for (int s = 0; s < symmetry; s++)
+ {
+ for (int i = 0; i < currentLineCounter; i += 2)
+ {
+ DrawLineEx(lines[i].start, lines[i].end, thickness, BLACK);
+ DrawLineEx(lines[i + 1].start, lines[i + 1].end, thickness, BLACK);
}
}
- prevMousePos = mousePos;
EndMode2D();
+
+ if ((currentLineCounter - 1) < 0) GuiDisable();
+
+ backButtonClicked = GuiButton(backButtonRec, "<");
+ GuiEnable();
+
+ if ((currentLineCounter + 1) > totalLineCounter) GuiDisable();
+
+ nextButtonClicked = GuiButton(nextButtonRec, ">");
+ GuiEnable();
+ resetButtonClicked = GuiButton(resetButtonRec, "Reset");
+
+ DrawText(TextFormat("LINES: %i/%i", currentLineCounter, MAX_DRAW_LINES), 10, screenHeight - 30, 20, MAROON);
+ DrawFPS(10, 10);
+
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
-
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
diff --git a/examples/shapes/shapes_kaleidoscope.png b/examples/shapes/shapes_kaleidoscope.png
index d14571ab7..3c15a52b3 100644
Binary files a/examples/shapes/shapes_kaleidoscope.png and b/examples/shapes/shapes_kaleidoscope.png differ
diff --git a/examples/shapes/shapes_lines_drawing.c b/examples/shapes/shapes_lines_drawing.c
index 9347acaf3..76e81abb5 100644
--- a/examples/shapes/shapes_lines_drawing.c
+++ b/examples/shapes/shapes_lines_drawing.c
@@ -11,11 +11,12 @@
* 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-2025 Robin (@RobinsAviary)
+* Copyright (c) 2025 Robin (@RobinsAviary)
*
********************************************************************************************/
#include "raylib.h"
+
#include "raymath.h"
//------------------------------------------------------------------------------------
@@ -23,124 +24,114 @@
//------------------------------------------------------------------------------------
int main(void)
{
- // Initialization
- //--------------------------------------------------------------------------------------
- const int screenWidth = 800;
- const int screenHeight = 450;
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
- InitWindow(screenWidth, screenHeight, "raylib [shapes] example - lines drawing");
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - lines drawing");
- // Hint text that shows before you click the screen
- bool startText = true;
+ // Hint text that shows before you click the screen
+ bool startText = true;
- // The mouse's position on the previous frame
- Vector2 mousePositionPrevious = GetMousePosition();
+ // The mouse's position on the previous frame
+ Vector2 mousePositionPrevious = GetMousePosition();
- // The canvas to draw lines on
- RenderTexture canvas = LoadRenderTexture(screenWidth, screenHeight);
+ // The canvas to draw lines on
+ RenderTexture canvas = LoadRenderTexture(screenWidth, screenHeight);
- // The background color of the canvas
- const Color backgroundColor = RAYWHITE;
+ // The line's thickness
+ float lineThickness = 8.0f;
+ // The lines hue (in HSV, from 0-360)
+ float lineHue = 0.0f;
- // The line's thickness
- float lineThickness = 8.0f;
- // The lines hue (in HSV, from 0-360)
- float lineHue = 0.0f;
+ // Clear the canvas to the background color
+ BeginTextureMode(canvas);
+ ClearBackground(RAYWHITE);
+ EndTextureMode();
- // Clear the canvas to the background color
- BeginTextureMode(canvas);
- ClearBackground(backgroundColor);
- EndTextureMode();
- //--------------------------------------------------------------------------------------
+ SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
- // Main game loop
- while (!WindowShouldClose()) // Detect window close button or ESC key
- {
- // Update
- //----------------------------------------------------------------------------------
- // Disable the hint text once the user clicks
- if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && startText)
- {
- startText = false;
- }
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ // Disable the hint text once the user clicks
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && startText) startText = false;
- // Clear the canvas when the user middle-clicks
- if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))
- {
- BeginTextureMode(canvas);
- ClearBackground(backgroundColor);
- EndTextureMode();
- }
+ // Clear the canvas when the user middle-clicks
+ if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))
+ {
+ BeginTextureMode(canvas);
+ ClearBackground(RAYWHITE);
+ EndTextureMode();
+ }
- // Store whether the left and right buttons are down
- bool leftButtonDown = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
- bool rightButtonDown = IsMouseButtonDown(MOUSE_BUTTON_RIGHT);
+ // Store whether the left and right buttons are down
+ bool leftButtonDown = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
+ bool rightButtonDown = IsMouseButtonDown(MOUSE_BUTTON_RIGHT);
- if (leftButtonDown || rightButtonDown)
- {
- // The color for the line
- Color drawColor;
+ if (leftButtonDown || rightButtonDown)
+ {
+ // The color for the line
+ Color drawColor = WHITE;
- if (leftButtonDown)
- {
- // Increase the hue value by the distance our cursor has moved since the last frame (divided by 3)
- lineHue += Vector2Distance(mousePositionPrevious, GetMousePosition())/3.0f;
+ if (leftButtonDown)
+ {
+ // Increase the hue value by the distance our cursor has moved since the last frame (divided by 3)
+ lineHue += Vector2Distance(mousePositionPrevious, GetMousePosition())/3.0f;
- // While the hue is >=360, subtract it to bring it down into the range 0-360
- // This is more visually accurate than resetting to zero
- while (lineHue >= 360.0f)
- {
- lineHue -= 360.0f;
- }
+ // While the hue is >=360, subtract it to bring it down into the range 0-360
+ // This is more visually accurate than resetting to zero
+ while (lineHue >= 360.0f) lineHue -= 360.0f;
- // Create the final color
- drawColor = ColorFromHSV(lineHue, 1.0f, 1.0f);
- }
- else if (rightButtonDown)
- {
- // Use the background color as an "eraser"
- drawColor = backgroundColor;
- }
+ // Create the final color
+ drawColor = ColorFromHSV(lineHue, 1.0f, 1.0f);
+ }
+ else if (rightButtonDown) drawColor = RAYWHITE; // Use the background color as an "eraser"
- // Draw the line onto the canvas
- BeginTextureMode(canvas);
- // Circles act as "caps", smoothing corners
- DrawCircleV(mousePositionPrevious, lineThickness/2.0f, drawColor);
- DrawCircleV(GetMousePosition(), lineThickness/2.0f, drawColor);
- DrawLineEx(mousePositionPrevious, GetMousePosition(), lineThickness, drawColor);
- EndTextureMode();
- }
+ // Draw the line onto the canvas
+ BeginTextureMode(canvas);
+ // Circles act as "caps", smoothing corners
+ DrawCircleV(mousePositionPrevious, lineThickness/2.0f, drawColor);
+ DrawCircleV(GetMousePosition(), lineThickness/2.0f, drawColor);
+ DrawLineEx(mousePositionPrevious, GetMousePosition(), lineThickness, drawColor);
+ EndTextureMode();
+ }
- // Update line thickness based on mousewheel
- lineThickness += GetMouseWheelMove();
- lineThickness = Clamp(lineThickness, 1.0, 500.0f);
+ // Update line thickness based on mousewheel
+ lineThickness += GetMouseWheelMove();
+ lineThickness = Clamp(lineThickness, 1.0, 500.0f);
- // Update mouse's previous position
- mousePositionPrevious = GetMousePosition();
- //----------------------------------------------------------------------------------
+ // Update mouse's previous position
+ mousePositionPrevious = GetMousePosition();
+ //----------------------------------------------------------------------------------
- // Draw
- //----------------------------------------------------------------------------------
- BeginDrawing();
- // Draw the render texture to the screen, flipped vertically to make it appear top-side up
- DrawTextureRec(canvas.texture, (Rectangle){ 0.0f, 0.0f, (float)canvas.texture.width,(float)-canvas.texture.height }, Vector2Zero(), WHITE);
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
- // Draw the preview circle
- if (!leftButtonDown) DrawCircleLinesV(GetMousePosition(), lineThickness/2.0f, (Color){ 127, 127, 127, 127 });
+ // Draw the render texture to the screen, flipped vertically to make it appear top-side up
+ DrawTextureRec(canvas.texture, (Rectangle){ 0.0f, 0.0f, (float)canvas.texture.width,(float)-canvas.texture.height }, Vector2Zero(), WHITE);
- // Draw the hint text
- if (startText) DrawText("try clicking and dragging!", 275, 215, 20, LIGHTGRAY);
- EndDrawing();
- //----------------------------------------------------------------------------------
- }
+ // Draw the preview circle
+ if (!leftButtonDown) DrawCircleLinesV(GetMousePosition(), lineThickness/2.0f, (Color){ 127, 127, 127, 127 });
- // De-Initialization
- //--------------------------------------------------------------------------------------
- // Unload the canvas render texture
- UnloadRenderTexture(canvas);
+ // Draw the hint text
+ if (startText) DrawText("try clicking and dragging!", 275, 215, 20, LIGHTGRAY);
- CloseWindow(); // Close window and OpenGL context
- //--------------------------------------------------------------------------------------
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
- return 0;
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadRenderTexture(canvas); // Unload the canvas render texture
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
}
\ No newline at end of file
diff --git a/examples/shapes/shapes_math_angle_rotation.c b/examples/shapes/shapes_math_angle_rotation.c
new file mode 100644
index 000000000..63c9aaa91
--- /dev/null
+++ b/examples/shapes/shapes_math_angle_rotation.c
@@ -0,0 +1,105 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - math angle rotation
+*
+* Example complexity rating: [★☆☆☆] 1/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6
+*
+* Example contributed by Kris (@krispy-snacc) 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 Kris (@krispy-snacc)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "raymath.h" // for DEG2RAD
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 720;
+ const int screenHeight = 400;
+
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - math angle rotation");
+ SetTargetFPS(60);
+
+ Vector2 center = { screenWidth/2.0f, screenHeight/2.0f };
+ const float lineLength = 150.0f;
+
+ // Predefined angles for fixed lines
+ int angles[] = { 0, 30, 60, 90 };
+ int numAngles = sizeof(angles)/sizeof(angles[0]);
+
+ float totalAngle = 0.0f; // Animated rotation angle
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose())
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ totalAngle += 1.0f; // degrees per frame
+ if (totalAngle >= 360.0f) totalAngle -= 360.0f;
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(WHITE);
+
+ DrawText("Fixed angles + rotating line", 10, 10, 20, LIGHTGRAY);
+
+ // Draw fixed-angle lines with colorful gradient
+ for (int i = 0; i < numAngles; i++)
+ {
+ float rad = angles[i]*DEG2RAD;
+ Vector2 end = { center.x + cosf(rad)*lineLength,
+ center.y + sinf(rad)*lineLength };
+
+ // Gradient color from green → cyan → blue → magenta
+ Color col;
+ switch(i)
+ {
+ case 0: col = GREEN; break;
+ case 1: col = ORANGE; break;
+ case 2: col = BLUE; break;
+ case 3: col = MAGENTA; break;
+ default: col = WHITE; break;
+ }
+
+ DrawLineEx(center, end, 5.0f, col);
+
+ // Draw angle label slightly offset along the line
+ Vector2 textPos = { center.x + cosf(rad)*(lineLength + 20),
+ center.y + sinf(rad)*(lineLength + 20) };
+ DrawText(TextFormat("%d°", angles[i]), (int)textPos.x, (int)textPos.y, 20, col);
+ }
+
+ // Draw animated rotating line with changing color
+ float animRad = totalAngle*DEG2RAD;
+ Vector2 animEnd = { center.x + cosf(animRad)*lineLength,
+ center.y + sinf(animRad)*lineLength };
+
+ // Cycle through HSV colors for animated line
+ Color animCol = ColorFromHSV(fmodf(totalAngle, 360.0f), 0.8f, 0.9f);
+ DrawLineEx(center, animEnd, 5.0f, animCol);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow();
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
diff --git a/examples/shapes/shapes_math_angle_rotation.png b/examples/shapes/shapes_math_angle_rotation.png
new file mode 100644
index 000000000..fd9a92360
Binary files /dev/null and b/examples/shapes/shapes_math_angle_rotation.png differ
diff --git a/examples/shapes/shapes_math_sine_cosine.c b/examples/shapes/shapes_math_sine_cosine.c
new file mode 100644
index 000000000..c3646cabd
--- /dev/null
+++ b/examples/shapes/shapes_math_sine_cosine.c
@@ -0,0 +1,177 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - math sine cosine
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*
+* Example contributed by Jopestpe (@jopestpe) 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 Jopestpe (@jopestpe)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include
+#include "raymath.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h" // Required for GUI controls
+
+// Wave points for sine/cosine visualization
+#define WAVE_POINTS 36
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ SetConfigFlags(FLAG_MSAA_4X_HINT);
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - math sine cosine");
+
+ Vector2 sinePoints[WAVE_POINTS];
+ Vector2 cosPoints[WAVE_POINTS];
+ Vector2 center = { (screenWidth/2.0f) - 30.0f, screenHeight/2.0f };
+ Rectangle start = { 20.0f, screenHeight - 120.f , 200.0f, 100.0f};
+ float radius = 130.0f;
+ float angle = 0.0f;
+ bool pause = false;
+
+ for (int i = 0; i < WAVE_POINTS; i++)
+ {
+ float t = i/(float)(WAVE_POINTS - 1);
+ float currentAngle = t*360.0f*DEG2RAD;
+ sinePoints[i] = (Vector2){ start.x + t*start.width, start.y + start.height/2.0f - sinf(currentAngle)*(start.height/2.0f) };
+ cosPoints[i] = (Vector2){ start.x + t*start.width, start.y + start.height/2.0f - cosf(currentAngle)*(start.height/2.0f) };
+ }
+
+ 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
+ //----------------------------------------------------------------------------------
+ float angleRad = angle*DEG2RAD;
+ float cosRad = cosf(angleRad);
+ float sinRad = sinf(angleRad);
+
+ Vector2 point = { center.x + cosRad*radius, center.y - sinRad*radius };
+ Vector2 limitMin = { center.x - radius, center.y - radius };
+ Vector2 limitMax = { center.x + radius, center.y + radius };
+
+ float complementary = 90.0f - angle;
+ float supplementary = 180.0f - angle;
+ float explementary = 360.0f - angle;
+
+ float tangent = Clamp(tanf(angleRad), -10.0f, 10.0f);
+ float cotangent = (fabsf(tangent) > 0.001f) ? Clamp(1.0f/tangent, -radius, radius) : 0.0f;
+ Vector2 tangentPoint = { center.x + radius, center.y - tangent*radius };
+ Vector2 cotangentPoint = { center.x + cotangent*radius, center.y - radius };
+
+ angle = Wrap(angle + (!pause ? 1.0f : 0.0f), 0.0f, 360.0f);
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(RAYWHITE);
+
+ // Cotangent (orange)
+ DrawLineEx((Vector2){ center.x , limitMin.y }, (Vector2){ cotangentPoint.x, limitMin.y }, 2.0f, ORANGE);
+ DrawLineDashed(center, cotangentPoint, 10.0f, 4.0f, ORANGE);
+
+ // Side background
+ DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 });
+ DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 232, 232, 232, 255 });
+
+ // Base circle and axes
+ DrawCircleLinesV(center, radius, GRAY);
+ DrawLineEx((Vector2){ center.x, limitMin.y }, (Vector2){ center.x, limitMax.y }, 1.0f, GRAY);
+ DrawLineEx((Vector2){ limitMin.x, center.y }, (Vector2){ limitMax.x, center.y }, 1.0f, GRAY);
+
+ // Wave graph axes
+ DrawLineEx((Vector2){ start.x , start.y }, (Vector2){ start.x , start.y + start.height }, 2.0f, GRAY);
+ DrawLineEx((Vector2){ start.x + start.width, start.y }, (Vector2){ start.x + start.width, start.y + start.height }, 2.0f, GRAY);
+ DrawLineEx((Vector2){ start.x, start.y + start.height/2 }, (Vector2){ start.x + start.width, start.y + start.height/2 }, 2.0f, GRAY);
+
+ // Wave graph axis labels
+ DrawText("1", start.x - 8, start.y, 6, GRAY);
+ DrawText("0", start.x - 8, start.y + start.height/2 - 6, 6, GRAY);
+ DrawText("-1", start.x - 12, start.y + start.height - 8, 6, GRAY);
+ DrawText("0", start.x - 2, start.y + start.height + 4, 6, GRAY);
+ DrawText("360", start.x + start.width - 8, start.y + start.height + 4, 6, GRAY);
+
+ // Sine (red - vertical)
+ DrawLineEx((Vector2){ center.x, center.y }, (Vector2){ center.x, point.y }, 2.0f, RED);
+ DrawLineDashed((Vector2){ point.x, center.y }, (Vector2){ point.x, point.y }, 10.0f, 4.0f, RED);
+ DrawText(TextFormat("Sine %.2f", sinRad), 640, 190, 6, RED);
+ DrawCircleV((Vector2){ start.x + (angle/360.0f)*start.width, start.y + ((-sinRad + 1)*start.height/2.0f) }, 4.0f, RED);
+ DrawSplineLinear(sinePoints, WAVE_POINTS, 1.0f, RED);
+
+ // Cosine (blue - horizontal)
+ DrawLineEx((Vector2){ center.x, center.y }, (Vector2){ point.x, center.y }, 2.0f, BLUE);
+ DrawLineDashed((Vector2){ center.x , point.y }, (Vector2){ point.x, point.y }, 10.0f, 4.0f, BLUE);
+ DrawText(TextFormat("Cosine %.2f", cosRad), 640, 210, 6, BLUE);
+ DrawCircleV((Vector2){ start.x + (angle/360.0f)*start.width, start.y + ((-cosRad + 1)*start.height/2.0f) }, 4.0f, BLUE);
+ DrawSplineLinear(cosPoints, WAVE_POINTS, 1.0f, BLUE);
+
+ // Tangent (purple)
+ DrawLineEx((Vector2){ limitMax.x , center.y }, (Vector2){ limitMax.x, tangentPoint.y }, 2.0f, PURPLE);
+ DrawLineDashed(center, tangentPoint, 10.0f, 4.0f, PURPLE);
+ DrawText(TextFormat("Tangent %.2f", tangent), 640, 230, 6, PURPLE);
+
+ // Cotangent (orange)
+ DrawText(TextFormat("Cotangent %.2f", cotangent), 640, 250, 6, ORANGE);
+
+ // Complementary angle (beige)
+ DrawCircleSectorLines(center, radius*0.6f , -angle, -90.0f , 36.0f, BEIGE);
+ DrawText(TextFormat("Complementary %0.f°",complementary), 640, 150, 6, BEIGE);
+
+ // Supplementary angle (darkblue)
+ DrawCircleSectorLines(center, radius*0.5f , -angle, -180.0f , 36.0f, DARKBLUE);
+ DrawText(TextFormat("Supplementary %0.f°",supplementary), 640, 130, 6, DARKBLUE);
+
+ // Explementary angle (pink)
+ DrawCircleSectorLines(center, radius*0.4f , -angle, -360.0f , 36.0f, PINK);
+ DrawText(TextFormat("Explementary %0.f°",explementary), 640, 170, 6, PINK);
+
+ // Current angle - arc (lime), radius (black), endpoint (black)
+ DrawCircleSectorLines(center, radius*0.7f , -angle, 0.0f, 36.0f, LIME);
+ DrawLineEx((Vector2){ center.x , center.y }, point, 2.0f, BLACK);
+ DrawCircleV(point, 4.0f, BLACK);
+
+ // Draw GUI controls
+ //------------------------------------------------------------------------------
+ GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(GRAY));
+ GuiToggle((Rectangle){ 640, 70, 120, 20}, TextFormat("Pause"), &pause);
+ GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(LIME));
+ GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f°", angle), &angle, 0.0f, 360.0f);
+
+ // Angle values panel
+ GuiGroupBox((Rectangle){ 620, 110, 140, 170}, "Angle Values");
+ //------------------------------------------------------------------------------
+
+ DrawFPS(10, 10);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/shapes/shapes_math_sine_cosine.png b/examples/shapes/shapes_math_sine_cosine.png
new file mode 100644
index 000000000..b561f74fb
Binary files /dev/null and b/examples/shapes/shapes_math_sine_cosine.png differ
diff --git a/examples/shapes/shapes_mouse_trail.c b/examples/shapes/shapes_mouse_trail.c
index e0e5a3c1d..3dd0fbd7f 100644
--- a/examples/shapes/shapes_mouse_trail.c
+++ b/examples/shapes/shapes_mouse_trail.c
@@ -35,7 +35,7 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - mouse trail");
// Array to store the history of mouse positions (our fixed-size queue)
- Vector2 trailPositions[MAX_TRAIL_LENGTH] = { 0 };
+ Vector2 trailPositions[MAX_TRAIL_LENGTH] = { 0 };
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
@@ -62,8 +62,8 @@ int main(void)
//----------------------------------------------------------------------------------
BeginDrawing();
- ClearBackground(BLACK);
-
+ ClearBackground(BLACK);
+
// Draw the trail by looping through the history array
for (int i = 0; i < MAX_TRAIL_LENGTH; i++)
{
@@ -71,22 +71,22 @@ int main(void)
if ((trailPositions[i].x != 0.0f) || (trailPositions[i].y != 0.0f))
{
// Calculate relative trail strength (ratio is near 1.0 for new, near 0.0 for old)
- float ratio = (float)(MAX_TRAIL_LENGTH - i) / MAX_TRAIL_LENGTH;
-
+ float ratio = (float)(MAX_TRAIL_LENGTH - i)/MAX_TRAIL_LENGTH;
+
// Fade effect: oldest positions are more transparent
// Fade (color, alpha) - alpha is 0.5 to 1.0 based on ratio
- Color trailColor = Fade(SKYBLUE, ratio*0.5f + 0.5f);
-
+ Color trailColor = Fade(SKYBLUE, ratio*0.5f + 0.5f);
+
// Size effect: oldest positions are smaller
- float trailRadius = 15.0f*ratio;
-
+ float trailRadius = 15.0f*ratio;
+
DrawCircleV(trailPositions[i], trailRadius, trailColor);
}
}
// Draw a distinct white circle for the current mouse position (Index 0)
DrawCircleV(mousePosition, 15.0f, WHITE);
-
+
DrawText("Move the mouse to see the trail effect!", 10, screenHeight - 30, 20, LIGHTGRAY);
EndDrawing();
diff --git a/examples/shapes/shapes_pie_chart.c b/examples/shapes/shapes_pie_chart.c
index 566e3a4d1..6db7f96da 100644
--- a/examples/shapes/shapes_pie_chart.c
+++ b/examples/shapes/shapes_pie_chart.c
@@ -67,7 +67,7 @@ int main(void)
const Rectangle panelRect = {
panelPos.x, panelPos.y,
(float)panelWidth,
- (float)screenHeight - 2.0f*panelMargin
+ (float)screenHeight - 2.0f*panelMargin
};
// Pie chart geometry
@@ -108,13 +108,13 @@ int main(void)
for (int i = 0; i < sliceCount; i++)
{
float sweep = (totalValue > 0)? (values[i]/totalValue)*360.0f : 0.0f;
-
+
if ((angle >= currentAngle) && (angle < (currentAngle + sweep)))
{
hoveredSlice = i;
break;
}
-
+
currentAngle += sweep;
}
}
@@ -182,11 +182,11 @@ int main(void)
GuiLine((Rectangle){ panelPos.x + 10, (float)panelPos.y + 12 + 170, panelRect.width - 20, 1 }, NULL);
// Scrollable area for slice editors
- scrollPanelBounds = (Rectangle){
- panelPos.x + panelMargin,
- (float)panelPos.y + 12 + 190,
- panelRect.width - panelMargin*2,
- panelRect.y + panelRect.height - panelPos.y + 12 + 190 - panelMargin
+ scrollPanelBounds = (Rectangle){
+ panelPos.x + panelMargin,
+ (float)panelPos.y + 12 + 190,
+ panelRect.width - panelMargin*2,
+ panelRect.y + panelRect.height - panelPos.y + 12 + 190 - panelMargin
};
int contentHeight = sliceCount*35;
diff --git a/examples/shapes/shapes_rectangle_advanced.c b/examples/shapes/shapes_rectangle_advanced.c
index 15487ee55..c274cb6f8 100644
--- a/examples/shapes/shapes_rectangle_advanced.c
+++ b/examples/shapes/shapes_rectangle_advanced.c
@@ -184,7 +184,7 @@ static void DrawRectangleRoundedGradientH(Rectangle rec, float roundnessLeft, fl
}
// End one even segments
- if ( segments % 2)
+ if ( segments%2)
{
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(center.x, center.y);
diff --git a/examples/shapes/shapes_recursive_tree.c b/examples/shapes/shapes_recursive_tree.c
index e9cadd8ec..f15758773 100644
--- a/examples/shapes/shapes_recursive_tree.c
+++ b/examples/shapes/shapes_recursive_tree.c
@@ -45,7 +45,7 @@ int main(void)
Vector2 start = { (screenWidth/2.0f) - 125.0f, (float)screenHeight };
float angle = 40.0f;
- float thick = 1.0f;
+ float thick = 1.0f;
float treeDepth = 10.0f;
float branchDecay = 0.66f;
float length = 120.0f;
@@ -67,21 +67,21 @@ int main(void)
Vector2 initialEnd = { start.x + length*sinf(0.0f), start.y - length*cosf(0.0f) };
branches[count++] = (Branch){start, initialEnd, 0.0f, length};
- for (int i = 0; i < count; i++)
+ for (int i = 0; i < count; i++)
{
Branch branch = branches[i];
if (branch.length < 2) continue;
float nextLength = branch.length*branchDecay;
- if (count < maxBranches && nextLength >= 2)
+ if (count < maxBranches && nextLength >= 2)
{
Vector2 branchStart = branch.end;
float angle1 = branch.angle + theta;
Vector2 branchEnd1 = { branchStart.x + nextLength*sinf(angle1), branchStart.y - nextLength*cosf(angle1) };
branches[count++] = (Branch){branchStart, branchEnd1, angle1, nextLength};
-
+
float angle2 = branch.angle - theta;
Vector2 branchEnd2 = { branchStart.x + nextLength*sinf(angle2), branchStart.y - nextLength*cosf(angle2) };
branches[count++] = (Branch){branchStart, branchEnd2, angle2, nextLength};
@@ -94,10 +94,10 @@ int main(void)
ClearBackground(RAYWHITE);
- for (int i = 0; i < count; i++)
+ for (int i = 0; i < count; i++)
{
Branch branch = branches[i];
- if (branch.length >= 2)
+ if (branch.length >= 2)
{
if (bezier) DrawLineBezier(branch.start, branch.end, thick, RED);
else DrawLineEx(branch.start, branch.end, thick, RED);
@@ -112,7 +112,7 @@ int main(void)
GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f", angle), &angle, 0, 180);
GuiSliderBar((Rectangle){ 640, 70, 120, 20 }, "Length", TextFormat("%.0f", length), &length, 12.0f, 240.0f);
GuiSliderBar((Rectangle){ 640, 100, 120, 20}, "Decay", TextFormat("%.2f", branchDecay), &branchDecay, 0.1f, 0.78f);
- GuiSliderBar((Rectangle){ 640, 130, 120, 20 }, "Depth", TextFormat("%.0f", treeDepth), &treeDepth, 1.0f, 10.f);
+ GuiSliderBar((Rectangle){ 640, 130, 120, 20 }, "Depth", TextFormat("%.0f", treeDepth), &treeDepth, 1.0f, 10.0f);
GuiSliderBar((Rectangle){ 640, 160, 120, 20}, "Thick", TextFormat("%.0f", thick), &thick, 1, 8);
GuiCheckBox((Rectangle){ 640, 190, 20, 20 }, "Bezier", &bezier);
//------------------------------------------------------------------------------
diff --git a/examples/shapes/shapes_rlgl_color_wheel.c b/examples/shapes/shapes_rlgl_color_wheel.c
new file mode 100644
index 000000000..f02226a83
--- /dev/null
+++ b/examples/shapes/shapes_rlgl_color_wheel.c
@@ -0,0 +1,274 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - rlgl color wheel
+*
+* Example complexity rating: [★★★☆] 3/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*
+* Example contributed by Robin (@RobinsAviary) 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 Robin (@RobinsAviary)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "rlgl.h"
+#include "raymath.h"
+#include
+#include
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h"
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ // The minimum/maximum points the circle can have
+ const unsigned int pointsMin = 3;
+ const unsigned int pointsMax = 256;
+
+ // The current number of points and the radius of the circle
+ unsigned int triangleCount = 64;
+ float pointScale = 150.0f;
+
+ // Slider value, literally maps to value in HSV
+ float value = 1.0f;
+
+ // The center of the screen
+ Vector2 center = { (float)screenWidth/2.0f, (float)screenHeight/2.0f };
+ // The location of the color wheel
+ Vector2 circlePosition = center;
+
+ // The currently selected color
+ Color color = { 255, 255, 255, 255 };
+
+ // Indicates if the slider is being clicked
+ bool sliderClicked = false;
+
+ // Indicates if the current color going to be updated, as well as the handle position
+ bool settingColor = false;
+
+ // How the color wheel will be rendered
+ unsigned int renderType = RL_TRIANGLES;
+
+ // Enable anti-aliasing
+ SetConfigFlags(FLAG_MSAA_4X_HINT);
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rlgl color wheel");
+
+ SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ triangleCount += (unsigned int)GetMouseWheelMove();
+ triangleCount = (unsigned int)Clamp((float)triangleCount, (float)pointsMin, (float)pointsMax);
+
+ Rectangle sliderRectangle = { 42.0f, 16.0f + 64.0f + 45.0f, 64.0f, 16.0f };
+ Vector2 mousePosition = GetMousePosition();
+
+ // Checks if the user is hovering over the value slider
+ bool sliderHover = (mousePosition.x >= sliderRectangle.x && mousePosition.y >= sliderRectangle.y && mousePosition.x < sliderRectangle.x + sliderRectangle.width && mousePosition.y < sliderRectangle.y + sliderRectangle.height);
+
+ // Copy color as hex
+ if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_C))
+ {
+ if (IsKeyPressed(KEY_C))
+ {
+ SetClipboardText(TextFormat("#%02X%02X%02X", color.r, color.g, color.b));
+ }
+ }
+
+ // Scale up the color wheel, adjusting the handle visually
+ if (IsKeyDown(KEY_UP))
+ {
+ pointScale *= 1.025f;
+
+ if (pointScale > (float)screenHeight/2.0f)
+ {
+ pointScale = (float)screenHeight/2.0f;
+ }
+ else
+ {
+ circlePosition = Vector2Add(Vector2Multiply(Vector2Subtract(circlePosition, center), (Vector2){ 1.025f, 1.025f }), center);
+ }
+ }
+
+ // Scale down the wheel, adjusting the handle visually
+ if (IsKeyDown(KEY_DOWN))
+ {
+ pointScale *= 0.975f;
+
+ if (pointScale < 32.0f)
+ {
+ pointScale = 32.0f;
+ }
+ else
+ {
+ circlePosition = Vector2Add(Vector2Multiply(Vector2Subtract(circlePosition, center), (Vector2){ 0.975f, 0.975f }), center);
+ }
+
+ float distance = Vector2Distance(center, circlePosition)/pointScale;
+ float angle = ((Vector2Angle((Vector2){ 0.0f, -pointScale }, Vector2Subtract(center, circlePosition))/PI + 1.0f)/2.0f);
+
+ if (distance > 1.0f)
+ {
+ circlePosition = Vector2Add((Vector2){ sinf(angle*(PI*2.0f))*pointScale, -cosf(angle*(PI*2.0f))*pointScale }, center);
+ }
+ }
+
+ // Checks if the user clicked on the color wheel
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && Vector2Distance(GetMousePosition(), center) <= pointScale + 10.0f)
+ {
+ settingColor = true;
+ }
+
+ // Update flag when mouse button is released
+ if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) settingColor = false;
+
+ // Check if the user clicked/released the slider for the color's value
+ if (sliderHover && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) sliderClicked = true;
+
+ if (sliderClicked && IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) sliderClicked = false;
+
+ // Update render mode accordingly
+ if (IsKeyPressed(KEY_SPACE)) renderType = RL_LINES;
+
+ if (IsKeyReleased(KEY_SPACE)) renderType = RL_TRIANGLES;
+
+ // If the slider or the wheel was clicked, update the current color
+ if (settingColor || sliderClicked)
+ {
+ if (settingColor) circlePosition = GetMousePosition();
+
+ float distance = Vector2Distance(center, circlePosition)/pointScale;
+
+ float angle = ((Vector2Angle((Vector2){ 0.0f, -pointScale }, Vector2Subtract(center, circlePosition))/PI + 1.0f)/2.0f);
+ if (settingColor && distance > 1.0f) circlePosition = Vector2Add((Vector2){ sinf(angle*(PI*2.0f))*pointScale, -cosf(angle*(PI* 2.0f))*pointScale }, center);
+
+ float angle360 = angle*360.0f;
+ float valueActual = Clamp(distance, 0.0f, 1.0f);
+ color = ColorLerp((Color){ (int)(value*255.0f), (int)(value*255.0f), (int)(value*255.0f), 255 }, ColorFromHSV(angle360, Clamp(distance, 0.0f, 1.0f), 1.0f), valueActual);
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ // Begin rendering color wheel
+ rlBegin(renderType);
+ for (unsigned int i = 0; i < triangleCount; i++)
+ {
+ float angleOffset = ((PI*2.0f)/(float)triangleCount);
+ float angle = angleOffset*(float)i;
+ float angleOffsetCalculated = ((float)i + 1)*angleOffset;
+ Vector2 scale = (Vector2){ pointScale, pointScale };
+
+ Vector2 offset = Vector2Multiply((Vector2){ sinf(angle), -cosf(angle) }, scale);
+ Vector2 offset2 = Vector2Multiply((Vector2){ sinf(angleOffsetCalculated), -cosf(angleOffsetCalculated) }, scale);
+
+ Vector2 position = Vector2Add(center, offset);
+ Vector2 position2 = Vector2Add(center, offset2);
+
+ float angleNonRadian = (angle/(2.0f*PI))*360.0f;
+ float angleNonRadianOffset = (angleOffset/(2.0f*PI))*360.0f;
+
+ Color currentColor = ColorFromHSV(angleNonRadian, 1.0f, 1.0f);
+ Color offsetColor = ColorFromHSV(angleNonRadian + angleNonRadianOffset, 1.0f, 1.0f);
+
+ // Input vertices differently depending on mode
+ if (renderType == RL_TRIANGLES)
+ {
+ // RL_TRIANGLES expects three vertices per triangle
+ rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
+ rlVertex2f(position.x, position.y);
+ rlColor4f(value, value, value, 1.0f);
+ rlVertex2f(center.x, center.y);
+ rlColor4ub(offsetColor.r, offsetColor.g, offsetColor.b, offsetColor.a);
+ rlVertex2f(position2.x, position2.y);
+ }
+ else if (renderType == RL_LINES)
+ {
+ // RL_LINES expects two vertices per line
+ rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
+ rlVertex2f(position.x, position.y);
+ rlColor4ub(WHITE.r, WHITE.g, WHITE.b, WHITE.a);
+ rlVertex2f(center.x, center.y);
+
+ rlVertex2f(center.x, center.y);
+ rlColor4ub(offsetColor.r, offsetColor.g, offsetColor.b, offsetColor.a);
+ rlVertex2f(position2.x, position2.y);
+
+ rlVertex2f(position2.x, position2.y);
+ rlColor4ub(currentColor.r, currentColor.g, currentColor.b, currentColor.a);
+ rlVertex2f(position.x, position.y);
+ }
+ }
+ rlEnd();
+
+ // Make the handle slightly more visible overtop darker colors
+ Color handleColor = BLACK;
+
+ if (Vector2Distance(center, circlePosition)/pointScale <= 0.5f && value <= 0.5f)
+ {
+ handleColor = DARKGRAY;
+ }
+
+ // Draw the color handle
+ DrawCircleLinesV(circlePosition, 4.0f, handleColor);
+
+ // Draw the color in a preview, with a darkened outline.
+ DrawRectangleV((Vector2){ 8.0f, 8.0f }, (Vector2){ 64.0f, 64.0f }, color);
+ DrawRectangleLinesEx((Rectangle){ 8.0f, 8.0f, 64.0f, 64.0f }, 2.0f, ColorLerp(color, BLACK, 0.5f));
+
+ // Draw current color as hex and decimal
+ DrawText(TextFormat("#%02X%02X%02X\n(%d, %d, %d)", color.r, color.g, color.b, color.r, color.g, color.b), 8, 8 + 64 + 8, 20, DARKGRAY);
+
+ // Update the visuals for the copying text
+ Color copyColor = DARKGRAY;
+ unsigned int offset = 0;
+ if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyDown(KEY_C))
+ {
+ copyColor = DARKGREEN;
+ offset = 4;
+ }
+
+ // Draw the copying text
+ DrawText("press ctrl+c to copy!", 8, 425 - offset, 20, copyColor);
+
+ // Display the number of rendered triangles
+ DrawText(TextFormat("triangle count: %d", triangleCount), 8, 395, 20, DARKGRAY);
+
+ // Slider to change color's value
+ GuiSliderBar(sliderRectangle, "value: ", "", &value, 0.0f, 1.0f);
+
+ // Draw FPS next to outlined color preview
+ DrawFPS(64 + 16, 8);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/shapes/shapes_rlgl_color_wheel.png b/examples/shapes/shapes_rlgl_color_wheel.png
new file mode 100644
index 000000000..43344da59
Binary files /dev/null and b/examples/shapes/shapes_rlgl_color_wheel.png differ
diff --git a/examples/shapes/shapes_rlgl_triangle.c b/examples/shapes/shapes_rlgl_triangle.c
new file mode 100644
index 000000000..56cdc43bc
--- /dev/null
+++ b/examples/shapes/shapes_rlgl_triangle.c
@@ -0,0 +1,169 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - rlgl triangle
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*
+* Example contributed by Robin (@RobinsAviary) 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 Robin (@RobinsAviary)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "rlgl.h"
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ SetConfigFlags(FLAG_MSAA_4X_HINT);
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - rlgl triangle");
+
+ // Starting postions and rendered triangle positions
+ Vector2 startingPositions[3] = {{ 400.0f, 150.0f }, { 300.0f, 300.0f }, { 500.0f, 300.0f }};
+ Vector2 trianglePositions[3] = { startingPositions[0], startingPositions[1], startingPositions[2] };
+
+ // Currently selected vertex, -1 means none
+ int triangleIndex = -1;
+ bool linesMode = false;
+ float handleRadius = 8.0f;
+
+ SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ if (IsKeyPressed(KEY_SPACE)) linesMode = !linesMode;
+
+ // Check selected vertex
+ for (unsigned int i = 0; i < 3; i++)
+ {
+ // If the mouse is within the handle circle
+ if (CheckCollisionPointCircle(GetMousePosition(), trianglePositions[i], handleRadius) &&
+ IsMouseButtonDown(MOUSE_BUTTON_LEFT))
+ {
+ triangleIndex = i;
+ break;
+ }
+ }
+
+ // If the user has selected a vertex, offset it by the mouse's delta this frame
+ if (triangleIndex != -1)
+ {
+ Vector2 *position = &trianglePositions[triangleIndex];
+
+ Vector2 mouseDelta = GetMouseDelta();
+ position->x += mouseDelta.x;
+ position->y += mouseDelta.y;
+ }
+
+ // Reset index on release
+ if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) triangleIndex = -1;
+
+ // Enable/disable backface culling (2-sided triangles, slower to render)
+ if (IsKeyPressed(KEY_LEFT)) rlEnableBackfaceCulling();
+ if (IsKeyPressed(KEY_RIGHT)) rlDisableBackfaceCulling();
+
+ // Reset triangle vertices to starting positions and reset backface culling
+ if (IsKeyPressed(KEY_R))
+ {
+ trianglePositions[0] = startingPositions[0];
+ trianglePositions[1] = startingPositions[1];
+ trianglePositions[2] = startingPositions[2];
+
+ rlEnableBackfaceCulling();
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ if (linesMode)
+ {
+ // Draw triangle with lines
+ rlBegin(RL_LINES);
+ // Three lines, six points
+ // Define color for next vertex
+ rlColor4ub(255, 0, 0, 255);
+ // Define vertex
+ rlVertex2f(trianglePositions[0].x, trianglePositions[0].y);
+ rlColor4ub(0, 255, 0, 255);
+ rlVertex2f(trianglePositions[1].x, trianglePositions[1].y);
+
+ rlColor4ub(0, 255, 0, 255);
+ rlVertex2f(trianglePositions[1].x, trianglePositions[1].y);
+ rlColor4ub(0, 0, 255, 255);
+ rlVertex2f(trianglePositions[2].x, trianglePositions[2].y);
+
+ rlColor4ub(0, 0, 255, 255);
+ rlVertex2f(trianglePositions[2].x, trianglePositions[2].y);
+ rlColor4ub(255, 0, 0, 255);
+ rlVertex2f(trianglePositions[0].x, trianglePositions[0].y);
+ rlEnd();
+ }
+ else
+ {
+ // Draw triangle as a triangle
+ rlBegin(RL_TRIANGLES);
+ // One triangle, three points
+ // Define color for next vertex
+ rlColor4ub(255, 0, 0, 255);
+ // Define vertex
+ rlVertex2f(trianglePositions[0].x, trianglePositions[0].y);
+ rlColor4ub(0, 255, 0, 255);
+ rlVertex2f(trianglePositions[1].x, trianglePositions[1].y);
+ rlColor4ub(0, 0, 255, 255);
+ rlVertex2f(trianglePositions[2].x, trianglePositions[2].y);
+ rlEnd();
+ }
+
+ // Render the vertex handles, reacting to mouse movement/input
+ for (unsigned int i = 0; i < 3; i++)
+ {
+ // Draw handle fill focused by mouse
+ if (CheckCollisionPointCircle(GetMousePosition(), trianglePositions[i], handleRadius))
+ DrawCircleV(trianglePositions[i], handleRadius, ColorAlpha(DARKGRAY, 0.5f));
+
+ // Draw handle fill selected
+ if (i == triangleIndex) DrawCircleV(trianglePositions[i], handleRadius, DARKGRAY);
+
+ // Draw handle outline
+ DrawCircleLinesV(trianglePositions[i], handleRadius, BLACK);
+ }
+
+ // Draw controls
+ DrawText("SPACE: Toggle lines mode", 10, 10, 20, DARKGRAY);
+ DrawText("LEFT-RIGHT: Toggle backface culling", 10, 40, 20, DARKGRAY);
+ DrawText("MOUSE: Click and drag vertex points", 10, 70, 20, DARKGRAY);
+ DrawText("R: Reset triangle to start positions", 10, 100, 20, DARKGRAY);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/shapes/shapes_rlgl_triangle.png b/examples/shapes/shapes_rlgl_triangle.png
new file mode 100644
index 000000000..9fec558ff
Binary files /dev/null and b/examples/shapes/shapes_rlgl_triangle.png differ
diff --git a/examples/shapes/shapes_simple_particles.c b/examples/shapes/shapes_simple_particles.c
index c5d9612c3..f8151e7ad 100644
--- a/examples/shapes/shapes_simple_particles.c
+++ b/examples/shapes/shapes_simple_particles.c
@@ -36,7 +36,7 @@ static const char particleTypeNames[3][10] = { "WATER", "SMOKE", "FIRE" };
typedef struct Particle {
ParticleType type; // Particle type (WATER, SMOKE, FIRE)
Vector2 position; // Particle position on screen
- Vector2 velocity; // Particle current speed and direction
+ Vector2 velocity; // Particle current speed and direction
float radius; // Particle radius
Color color; // Particle color
@@ -45,9 +45,9 @@ typedef struct Particle {
} Particle;
typedef struct CircularBuffer {
- int head; // Index for the next write
- int tail; // Index for the next read
- Particle *buffer; // Particle buffer array
+ int head; // Index for the next write
+ int tail; // Index for the next read
+ Particle *buffer; // Particle buffer array
} CircularBuffer;
//----------------------------------------------------------------------------------
@@ -73,12 +73,12 @@ int main(void)
// Definition of particles
Particle *particles = (Particle*)RL_CALLOC(MAX_PARTICLES, sizeof(Particle)); // Particle array
- CircularBuffer circularBuffer = { 0, 0, particles };
+ CircularBuffer circularBuffer = { 0, 0, particles };
- // Particle emitter parameters
+ // Particle emitter parameters
int emissionRate = -2; // Negative: on average every -X frames. Positive: particles per frame
- ParticleType currentType = WATER;
- Vector2 emitterPosition = { screenWidth/2.0f, screenHeight/2.0f };
+ ParticleType currentType = WATER;
+ Vector2 emitterPosition = { screenWidth/2.0f, screenHeight/2.0f };
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
@@ -88,17 +88,17 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
- // Emit new particles: when emissionRate is 1, emit every frame
+ // Emit new particles: when emissionRate is 1, emit every frame
if (emissionRate < 0)
{
if (rand()%(-emissionRate) == 0) EmitParticle(&circularBuffer, emitterPosition, currentType);
}
else
{
- for (int i = 0; i <= emissionRate; ++i) EmitParticle(&circularBuffer, emitterPosition, currentType);
- }
+ for (int i = 0; i <= emissionRate; i++) EmitParticle(&circularBuffer, emitterPosition, currentType);
+ }
- // Update the parameters of each particle
+ // Update the parameters of each particle
UpdateParticles(&circularBuffer, screenWidth, screenHeight);
// Remove dead particles from the circular buffer
@@ -112,7 +112,7 @@ int main(void)
if (IsKeyPressed(KEY_RIGHT)) (currentType == FIRE)? (currentType = WATER) : currentType++;
if (IsKeyPressed(KEY_LEFT)) (currentType == WATER)? (currentType = FIRE) : currentType--;
- if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) emitterPosition = GetMousePosition();
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) emitterPosition = GetMousePosition();
//----------------------------------------------------------------------------------
// Draw
@@ -121,7 +121,7 @@ int main(void)
ClearBackground(RAYWHITE);
- // Call the function with a loop to draw all particles
+ // Call the function with a loop to draw all particles
DrawParticles(&circularBuffer);
// Draw UI and Instructions
@@ -133,7 +133,7 @@ int main(void)
DrawText("LEFT/RIGHT: Change Particle Type (Water, Smoke, Fire)", 15, 55, 10, BLACK);
if (emissionRate < 0) DrawText(TextFormat("Particles every %d frames | Type: %s", -emissionRate, particleTypeNames[currentType]), 15, 95, 10, DARKGRAY);
- else DrawText(TextFormat("%d Particles per frame | Type: %s", emissionRate + 1, particleTypeNames[currentType]), 15, 95, 10, DARKGRAY);
+ else DrawText(TextFormat("%d Particles per frame | Type: %s", emissionRate + 1, particleTypeNames[currentType]), 15, 95, 10, DARKGRAY);
DrawFPS(screenWidth - 80, 10);
@@ -200,12 +200,12 @@ static Particle *AddToCircularBuffer(CircularBuffer *circularBuffer)
// Check if buffer full
if (((circularBuffer->head + 1)%MAX_PARTICLES) != circularBuffer->tail)
{
- // Add new particle to the head position and advance head
+ // Add new particle to the head position and advance head
particle = &circularBuffer->buffer[circularBuffer->head];
circularBuffer->head = (circularBuffer->head + 1)%MAX_PARTICLES;
}
- return particle;
+ return particle;
}
static void UpdateParticles(CircularBuffer *circularBuffer, int screenWidth, int screenHeight)
@@ -213,7 +213,7 @@ static void UpdateParticles(CircularBuffer *circularBuffer, int screenWidth, int
for (int i = circularBuffer->tail; i != circularBuffer->head; i = (i + 1)%MAX_PARTICLES)
{
// Update particle life and positions
- circularBuffer->buffer[i].lifeTime += 1.0f/60.0f; // 60 FPS -> 1/60 seconds per frame
+ circularBuffer->buffer[i].lifeTime += 1.0f/60.0f; // 60 FPS -> 1/60 seconds per frame
switch (circularBuffer->buffer[i].type)
{
@@ -226,32 +226,32 @@ static void UpdateParticles(CircularBuffer *circularBuffer, int screenWidth, int
case SMOKE:
{
circularBuffer->buffer[i].position.x += circularBuffer->buffer[i].velocity.x;
- circularBuffer->buffer[i].velocity.y -= 0.05f; // Upwards
+ circularBuffer->buffer[i].velocity.y -= 0.05f; // Upwards
circularBuffer->buffer[i].position.y += circularBuffer->buffer[i].velocity.y;
circularBuffer->buffer[i].radius += 0.5f; // Increment radius: smoke expands
- circularBuffer->buffer[i].color.a -= 4; // Decrement alpha: smoke fades
-
+ circularBuffer->buffer[i].color.a -= 4; // Decrement alpha: smoke fades
+
// If alpha transparent, particle dies
if (circularBuffer->buffer[i].color.a < 4) circularBuffer->buffer[i].alive = false;
} break;
case FIRE:
{
- // Add a little horizontal oscillation to fire particles
+ // Add a little horizontal oscillation to fire particles
circularBuffer->buffer[i].position.x += circularBuffer->buffer[i].velocity.x + cosf(circularBuffer->buffer[i].lifeTime*215.0f);
circularBuffer->buffer[i].velocity.y -= 0.05f; // Upwards
circularBuffer->buffer[i].position.y += circularBuffer->buffer[i].velocity.y;
- circularBuffer->buffer[i].radius -= 0.15f; // Decrement radius: fire shrinks
- circularBuffer->buffer[i].color.g -= 3; // Decrement green: fire turns reddish starting from yellow
-
+ circularBuffer->buffer[i].radius -= 0.15f; // Decrement radius: fire shrinks
+ circularBuffer->buffer[i].color.g -= 3; // Decrement green: fire turns reddish starting from yellow
+
// If radius too small, particle dies
if (circularBuffer->buffer[i].radius <= 0.02f) circularBuffer->buffer[i].alive = false;
} break;
default: break;
}
- // Disable particle when out of screen
+ // Disable particle when out of screen
Vector2 center = circularBuffer->buffer[i].position;
- float radius = circularBuffer->buffer[i].radius;
+ float radius = circularBuffer->buffer[i].radius;
if ((center.x < -radius) || (center.x > (screenWidth + radius)) ||
(center.y < -radius) || (center.y > (screenHeight + radius)))
@@ -267,7 +267,7 @@ static void UpdateCircularBuffer(CircularBuffer *circularBuffer)
while ((circularBuffer->tail != circularBuffer->head) && !circularBuffer->buffer[circularBuffer->tail].alive)
{
circularBuffer->tail = (circularBuffer->tail + 1)%MAX_PARTICLES;
- }
+ }
}
static void DrawParticles(CircularBuffer *circularBuffer)
diff --git a/examples/shapes/shapes_starfield_effect.c b/examples/shapes/shapes_starfield_effect.c
index 8dd90fe0b..ca409c926 100644
--- a/examples/shapes/shapes_starfield_effect.c
+++ b/examples/shapes/shapes_starfield_effect.c
@@ -32,18 +32,18 @@ int main(void)
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - starfield effect");
-
+
Color bgColor = ColorLerp(DARKBLUE, BLACK, 0.69f);
-
+
// Speed at which we fly forward
float speed = 10.0f/9.0f;
-
+
// We're either drawing lines or circles
bool drawLines = true;
-
+
Vector3 stars[STAR_COUNT] = { 0 };
Vector2 starsScreenPos[STAR_COUNT] = { 0 };
-
+
// Setup the stars with a random position
for (int i = 0; i < STAR_COUNT; i++)
{
@@ -65,22 +65,22 @@ int main(void)
if ((int)mouseMove != 0) speed += 2.0f*mouseMove/9.0f;
if (speed < 0.0f) speed = 0.1f;
else if (speed > 2.0f) speed = 2.0f;
-
+
// Toggle lines / points with space bar
if (IsKeyPressed(KEY_SPACE)) drawLines = !drawLines;
-
+
float dt = GetFrameTime();
- for (int i = 0; i < STAR_COUNT; i++)
+ for (int i = 0; i < STAR_COUNT; i++)
{
// Update star's timer
stars[i].z -= dt*speed;
-
+
// Calculate the screen position
starsScreenPos[i] = (Vector2){
screenWidth*0.5f + stars[i].x/stars[i].z,
screenHeight*0.5f + stars[i].y/stars[i].z,
};
-
+
// If the star is too old, or offscreen, it dies and we make a new random one
if ((stars[i].z < 0.0f) || (starsScreenPos[i].x < 0) || (starsScreenPos[i].y < 0.0f) ||
(starsScreenPos[i].x > screenWidth) || (starsScreenPos[i].y > screenHeight))
@@ -97,14 +97,14 @@ int main(void)
BeginDrawing();
ClearBackground(bgColor);
-
+
for (int i = 0; i < STAR_COUNT; i++)
{
if (drawLines)
{
// Get the time a little while ago for this star, but clamp it
float t = Clamp(stars[i].z + 1.0f/32.0f, 0.0f, 1.0f);
-
+
// If it's different enough from the current time, we proceed
if ((t - stars[i].z) > 1e-3)
{
@@ -113,26 +113,26 @@ int main(void)
screenWidth*0.5f + stars[i].x/t,
screenHeight*0.5f + stars[i].y/t,
};
-
+
// Draw a line connecting the old point to the current point
DrawLineV(startPos, starsScreenPos[i], RAYWHITE);
}
}
- else
+ else
{
// Make the radius grow as the star ages
float radius = Lerp(stars[i].z, 1.0f, 5.0f);
-
+
// Draw the circle
DrawCircleV(starsScreenPos[i], radius, RAYWHITE);
}
}
-
+
DrawText(TextFormat("[MOUSE WHEEL] Current Speed: %.0f", 9.0f*speed/2.0f), 10, 40, 20, RAYWHITE);
DrawText(TextFormat("[SPACE] Current draw mode: %s", drawLines ? "Lines" : "Circles"), 10, 70, 20, RAYWHITE);
-
+
DrawFPS(10, 10);
-
+
EndDrawing();
//----------------------------------------------------------------------------------
}
diff --git a/examples/shapes/shapes_triangle_strip.c b/examples/shapes/shapes_triangle_strip.c
index 3172e1f7f..de712270c 100644
--- a/examples/shapes/shapes_triangle_strip.c
+++ b/examples/shapes/shapes_triangle_strip.c
@@ -34,12 +34,12 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - triangle strip");
Vector2 points[122] = { 0 };
- Vector2 center = { (screenWidth/2.0f) - 125.f, screenHeight/2.0f };
+ Vector2 center = { (screenWidth/2.0f) - 125.0f, screenHeight/2.0f };
float segments = 6.0f;
float insideRadius = 100.0f;
float outsideRadius = 150.0f;
bool outline = true;
-
+
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
@@ -79,20 +79,20 @@ int main(void)
float angle1 = i*angleStep;
DrawTriangle(c, b, a, ColorFromHSV(angle1*RAD2DEG, 1.0f, 1.0f));
DrawTriangle(d, b, c, ColorFromHSV((angle1 + angleStep/2)*RAD2DEG, 1.0f, 1.0f));
-
+
if (outline)
{
DrawTriangleLines(a, b, c, BLACK);
DrawTriangleLines(c, b, d, BLACK);
}
}
-
+
DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 });
DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 232, 232, 232, 255 });
// Draw GUI controls
//------------------------------------------------------------------------------
- GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Segments", TextFormat("%.0f", segments), &segments, 6.0f, 60.f);
+ GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Segments", TextFormat("%.0f", segments), &segments, 6.0f, 60.0f);
GuiCheckBox((Rectangle){ 640, 70, 20, 20 }, "Outline", &outline);
//------------------------------------------------------------------------------
diff --git a/examples/shapes/shapes_vector_angle.c b/examples/shapes/shapes_vector_angle.c
index b5faf4c78..464af1bd1 100644
--- a/examples/shapes/shapes_vector_angle.c
+++ b/examples/shapes/shapes_vector_angle.c
@@ -25,7 +25,7 @@ int main(void)
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
-
+
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - vector angle");
diff --git a/examples/text/text_3d_drawing.c b/examples/text/text_3d_drawing.c
index 202494bf7..80b617b2e 100644
--- a/examples/text/text_3d_drawing.c
+++ b/examples/text/text_3d_drawing.c
@@ -231,7 +231,7 @@ int main(void)
if (multicolor)
{
// Fill color array with random colors
- for (int i = 0; i < TEXT_MAX_LAYERS; ++i)
+ for (int i = 0; i < TEXT_MAX_LAYERS; i++)
{
multi[i] = GenerateRandomColor(0.5f, 0.8f);
multi[i].a = GetRandomValue(0, 255);
@@ -296,7 +296,7 @@ int main(void)
rlRotatef(90.0f, 1.0f, 0.0f, 0.0f);
rlRotatef(90.0f, 0.0f, 0.0f, -1.0f);
- for (int i = 0; i < layers; ++i)
+ for (int i = 0; i < layers; i++)
{
Color clr = light;
if (multicolor) clr = multi[i];
diff --git a/examples/text/text_font_loading.c b/examples/text/text_font_loading.c
index f1582348b..151b63d45 100644
--- a/examples/text/text_font_loading.c
+++ b/examples/text/text_font_loading.c
@@ -9,7 +9,7 @@
* - TTF/OTF > Sprite font atlas is generated on loading, user can configure
* some of the generation parameters (size, characters to include)
* - BMFonts > Angel code font fileformat, sprite font image must be provided
-* together with the .fnt file, font generation cna not be configured
+* together with the .fnt file, font generation can not be configured
* - XNA Spritefont > Sprite font image, following XNA Spritefont conventions,
* Characters in image must follow some spacing and order rules
*
diff --git a/examples/text/text_inline_styling.c b/examples/text/text_inline_styling.c
index b221c7e6f..aeebe0abc 100644
--- a/examples/text/text_inline_styling.c
+++ b/examples/text/text_inline_styling.c
@@ -36,11 +36,11 @@ int main(void)
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [text] example - inline styling");
-
+
Vector2 textSize = { 0 }; // Measure text box for provided font and text
Color colRandom = RED; // Random color used on text
int frameCounter = 0; // Used to generate a new random color every certain frames
-
+
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
@@ -50,7 +50,7 @@ int main(void)
// Update
//----------------------------------------------------------------------------------
frameCounter++;
-
+
if ((frameCounter%20) == 0)
{
colRandom.r = (unsigned char)GetRandomValue(0, 255);
@@ -67,12 +67,12 @@ int main(void)
ClearBackground(RAYWHITE);
// Text inline styling strategy used: [ ] delimiters for format
- // - Define foreground color: [cRRGGBBAA]
+ // - Define foreground color: [cRRGGBBAA]
// - Define background color: [bRRGGBBAA]
// - Reset formating: [r]
// Example: [bAA00AAFF][cFF0000FF]red text on gray background[r] normal text
-
- DrawTextStyled(GetFontDefault(), "This changes the [cFF0000FF]foreground color[r] of provided text!!!",
+
+ DrawTextStyled(GetFontDefault(), "This changes the [cFF0000FF]foreground color[r] of provided text!!!",
(Vector2){ 100, 80 }, 20.0f, 2.0f, BLACK);
DrawTextStyled(GetFontDefault(), "This changes the [bFF00FFFF]background color[r] of provided text!!!",
@@ -80,11 +80,11 @@ int main(void)
DrawTextStyled(GetFontDefault(), "This changes the [c00ff00ff][bff0000ff]foreground and background colors[r]!!!",
(Vector2){ 100, 160 }, 20.0f, 2.0f, BLACK);
-
+
// Get pointer to formated text
const char *text = TextFormat("Let's be [c%02x%02x%02xFF]CREATIVE[r] !!!", colRandom.r, colRandom.g, colRandom.b);
DrawTextStyled(GetFontDefault(), text, (Vector2){ 100, 220 }, 40.0f, 2.0f, BLACK);
-
+
textSize = MeasureTextStyled(GetFontDefault(), text, 40.0f, 2.0f);
DrawRectangleLines(100, 220, (int)textSize.x, (int)textSize.y, GREEN);
@@ -108,13 +108,13 @@ int main(void)
static void DrawTextStyled(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color color)
{
// Text inline styling strategy used: [ ] delimiters for format
- // - Define foreground color: [cRRGGBBAA]
+ // - Define foreground color: [cRRGGBBAA]
// - Define background color: [bRRGGBBAA]
// - Reset formating: [r]
// Example: [bAA00AAFF][cFF0000FF]red text on gray background[r] normal text
-
+
if (font.texture.id == 0) font = GetFontDefault();
-
+
int textLen = TextLength(text);
Color colFront = color;
@@ -144,14 +144,14 @@ static void DrawTextStyled(Font font, const char *text, Vector2 position, float
{
colFront = color;
colBack = BLANK;
-
+
i += 3; // Skip "[r]"
continue; // Do not draw characters
}
else if (((i + 1) < textLen) && ((text[i + 1] == 'c') || (text[i + 1] == 'b')))
{
i += 2; // Skip "[c" or "[b" to start parsing color
-
+
// Parse following color
char colHexText[9] = { 0 };
const char *textPtr = &text[i]; // Color should start here, let's see...
@@ -168,12 +168,12 @@ static void DrawTextStyled(Font font, const char *text, Vector2 position, float
}
else break; // Only affects while loop
}
-
+
// Convert hex color text into actual Color
unsigned int colHexValue = strtoul(colHexText, NULL, 16);
if (text[i - 1] == 'c') colFront = GetColor(colHexValue);
else if (text[i - 1] == 'b') colBack = GetColor(colHexValue);
-
+
i += (colHexCount + 1); // Skip color value retrieved and ']'
continue; // Do not draw characters
}
@@ -186,7 +186,7 @@ static void DrawTextStyled(Font font, const char *text, Vector2 position, float
else increaseX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing);
// Draw background rectangle color (if required)
- if (colBack.a > 0) DrawRectangleRec((Rectangle) { position.x + textOffsetX, position.y + textOffsetY - backRecPadding, increaseX, fontSize + 2 * backRecPadding }, colBack);
+ if (colBack.a > 0) DrawRectangleRec((Rectangle) { position.x + textOffsetX, position.y + textOffsetY - backRecPadding, increaseX, fontSize + 2*backRecPadding }, colBack);
if ((codepoint != ' ') && (codepoint != '\t'))
{
@@ -210,7 +210,7 @@ static Vector2 MeasureTextStyled(Font font, const char *text, float fontSize, fl
if ((font.texture.id == 0) || (text == NULL) || (text[0] == '\0')) return textSize; // Security check
int textLen = TextLength(text); // Get size in bytes of text
- float textLineSpacing = fontSize*1.5f;
+ //float textLineSpacing = fontSize*1.5f; // Not used...
float textWidth = 0.0f;
float textHeight = fontSize;
@@ -249,7 +249,7 @@ static Vector2 MeasureTextStyled(Font font, const char *text, float fontSize, fl
}
else break; // Only affects while loop
}
-
+
i += (colHexCount + 1); // Skip color value retrieved and ']'
continue; // Do not measure characters
}
@@ -260,7 +260,7 @@ static Vector2 MeasureTextStyled(Font font, const char *text, float fontSize, fl
if (font.glyphs[index].advanceX > 0) textWidth += font.glyphs[index].advanceX;
else textWidth += (font.recs[index].width + font.glyphs[index].offsetX);
-
+
validCodepointCounter++;
i += codepointByteCount;
}
diff --git a/examples/text/text_unicode_emojis.c b/examples/text/text_unicode_emojis.c
index 30fcaa8b7..00712745d 100644
--- a/examples/text/text_unicode_emojis.c
+++ b/examples/text/text_unicode_emojis.c
@@ -210,7 +210,7 @@ int main(void)
// Draw random emojis in the background
//------------------------------------------------------------------------------
- for (int i = 0; i < SIZEOF(emoji); ++i)
+ for (int i = 0; i < SIZEOF(emoji); i++)
{
const char *txt = &emojiCodepoints[emoji[i].index];
Rectangle emojiRect = { position.x, position.y, (float)fontEmoji.baseSize, (float)fontEmoji.baseSize };
@@ -316,7 +316,7 @@ static void RandomizeEmoji(void)
hovered = selected = -1;
int start = GetRandomValue(45, 360);
- for (int i = 0; i < SIZEOF(emoji); ++i)
+ for (int i = 0; i < SIZEOF(emoji); i++)
{
// 0-179 emoji codepoints (from emoji char array) each 4bytes + null char
emoji[i].index = GetRandomValue(0, 179)*5;
diff --git a/examples/text/text_unicode_ranges.c b/examples/text/text_unicode_ranges.c
index e54c052b1..76ee75f8d 100644
--- a/examples/text/text_unicode_ranges.c
+++ b/examples/text/text_unicode_ranges.c
@@ -58,7 +58,7 @@ int main(void)
// Load font with default Unicode range: Basic ASCII [32-127]
font = LoadFont("resources/NotoSansTC-Regular.ttf");
-
+
// Add required ranges to loaded font
switch (unicodeRange)
{
@@ -128,11 +128,11 @@ int main(void)
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
-
+
ClearBackground(RAYWHITE);
DrawText("ADD CODEPOINTS: [1][2][3][4]", 20, 20, 20, MAROON);
-
+
// Render test strings in different languages
DrawTextEx(font, "> English: Hello World!", (Vector2){ 50, 70 }, 32, 1, DARKGRAY); // English
DrawTextEx(font, "> Español: Hola mundo!", (Vector2){ 50, 120 }, 32, 1, DARKGRAY); // Spanish
@@ -141,7 +141,7 @@ int main(void)
DrawTextEx(font, "> 中文: 你好世界!", (Vector2){ 50, 270 }, 32, 1, DARKGRAY); // Chinese
DrawTextEx(font, "> 日本語: こんにちは世界!", (Vector2){ 50, 320 }, 32, 1, DARKGRAY); // Japanese
//DrawTextEx(font, "देवनागरी: होला मुंडो!", (Vector2){ 50, 350 }, 32, 1, DARKGRAY); // Devanagari (glyphs not available in font)
-
+
// Draw font texture scaled to screen
float atlasScale = 380.0f/font.texture.width;
DrawRectangleRec((Rectangle) { 400.0f, 16.0f, font.texture.width* atlasScale, font.texture.height* atlasScale }, BLACK);
@@ -161,7 +161,7 @@ int main(void)
DrawRectangle(0, 125, screenWidth, 200, GRAY);
DrawText("GENERATING FONT ATLAS...", 120, 210, 40, BLACK);
}
-
+
EndDrawing();
//----------------------------------------------------------------------------------
}
@@ -184,10 +184,10 @@ static void AddCodepointRange(Font *font, const char *fontPath, int start, int s
{
int rangeSize = stop - start + 1;
int currentRangeSize = font->glyphCount;
-
+
// TODO: Load glyphs from provided vector font (if available),
// add them to existing font, regenerating font image and texture
-
+
int updatedCodepointCount = currentRangeSize + rangeSize;
int *updatedCodepoints = (int *)RL_CALLOC(updatedCodepointCount, sizeof(int));
diff --git a/examples/text/text_words_alignment.c b/examples/text/text_words_alignment.c
index 352b3cd37..6cfd2a85c 100644
--- a/examples/text/text_words_alignment.c
+++ b/examples/text/text_words_alignment.c
@@ -39,25 +39,25 @@ int main(void)
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [text] example - words alignment");
-
+
// Define the rectangle we will draw the text in
Rectangle textContainerRect = (Rectangle){ screenWidth/2-screenWidth/4, screenHeight/2-screenHeight/3, screenWidth/2, screenHeight*2/3 };
// Some text to display the current alignment
const char *textAlignNameH[] = { "Left", "Centre", "Right" };
const char *textAlignNameV[] = { "Top", "Middle", "Bottom" };
-
+
// Define the text we're going to draw in the rectangle
int wordIndex = 0;
int wordCount = 0;
char **words = TextSplit("raylib is a simple and easy-to-use library to enjoy videogames programming", ' ', &wordCount);
-
+
// Initialize the font size we're going to use
int fontSize = 40;
-
+
// And of course the font...
Font font = GetFontDefault();
-
+
// Intialize the alignment variables
TextAlignment hAlign = TEXT_ALIGN_CENTRE;
TextAlignment vAlign = TEXT_ALIGN_MIDDLE;
@@ -70,27 +70,32 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
-
- if (IsKeyPressed(KEY_LEFT)) {
+ if (IsKeyPressed(KEY_LEFT))
+ {
hAlign = hAlign - 1;
if (hAlign < 0) hAlign = 0;
}
- if (IsKeyPressed(KEY_RIGHT)) {
+
+ if (IsKeyPressed(KEY_RIGHT))
+ {
hAlign = hAlign + 1;
if (hAlign > 2) hAlign = 2;
}
- if (IsKeyPressed(KEY_UP)) {
+
+ if (IsKeyPressed(KEY_UP))
+ {
vAlign = vAlign - 1;
if (vAlign < 0) vAlign = 0;
}
- if (IsKeyPressed(KEY_DOWN)) {
+
+ if (IsKeyPressed(KEY_DOWN))
+ {
vAlign = vAlign + 1;
if (vAlign > 2) vAlign = 2;
}
-
+
// One word per second
- wordIndex = (int)GetTime() % wordCount;
-
+ wordIndex = (int)GetTime()%wordCount;
//----------------------------------------------------------------------------------
// Draw
@@ -103,16 +108,16 @@ int main(void)
DrawText(TextFormat("Alignment: Horizontal = %s, Vertical = %s", textAlignNameH[hAlign], textAlignNameV[vAlign]), 20, 40, 20, LIGHTGRAY);
DrawRectangleRec(textContainerRect, BLUE);
-
+
// Get the size of the text to draw
Vector2 textSize = MeasureTextEx(font, words[wordIndex], fontSize, fontSize*.1f);
-
+
// Calculate the top-left text position based on the rectangle and alignment
- Vector2 textPos = (Vector2) {
- textContainerRect.x + Lerp(0.0f, textContainerRect.width - textSize.x, ((float)hAlign) * 0.5f),
- textContainerRect.y + Lerp(0.0f, textContainerRect.height - textSize.y, ((float)vAlign) * 0.5f)
+ Vector2 textPos = (Vector2){
+ textContainerRect.x + Lerp(0.0f, textContainerRect.width - textSize.x, ((float)hAlign)*0.5f),
+ textContainerRect.y + Lerp(0.0f, textContainerRect.height - textSize.y, ((float)vAlign)*0.5f)
};
-
+
// Draw the text
DrawTextEx(font, words[wordIndex], textPos, fontSize, fontSize*.1f, RAYWHITE);
diff --git a/examples/textures/resources/LICENSE.md b/examples/textures/resources/LICENSE.md
index e4ee45304..7d67572c7 100644
--- a/examples/textures/resources/LICENSE.md
+++ b/examples/textures/resources/LICENSE.md
@@ -8,7 +8,7 @@
| explosion.png | [Unity Labs Paris](https://blogs.unity3d.com/2016/11/28/free-vfx-image-sequences-flipbooks/) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) |
| parrots.png | [Kodak set](http://r0k.us/graphics/kodak/) | ❔ | Original name: `kodim23.png`
| cat.png | ❔ | ❔ | - |
-| wabbit_alpha.png | ❔ | ❔ | - |
+| raybunny.png | [VoidSrc*](https://x.com/voidsrc) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |
| custom_jupiter_crash.png | [Brian Kent (AEnigma)](https://www.dafont.com/es/aenigma.d188) | [Freeware](https://www.dafont.com/es/jupiter-crash.font) | Atlas created by [@raysan5](https://github.com/raysan5) |
| KAISG.ttf | [Dieter Steffmann](http://www.steffmann.de/wordpress/) | [Freeware](https://www.1001fonts.com/users/steffmann/) | [Kaiserzeit Gotisch](https://www.dafont.com/es/kaiserzeit-gotisch.font) font |
| fudesumi.png | [Eiden Marsal](https://www.artstation.com/marshall_z) | [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/) | - |
diff --git a/examples/textures/resources/booth.png b/examples/textures/resources/booth.png
new file mode 100644
index 000000000..b4147f77b
Binary files /dev/null and b/examples/textures/resources/booth.png differ
diff --git a/examples/textures/resources/raybunny.png b/examples/textures/resources/raybunny.png
new file mode 100644
index 000000000..b608147bc
Binary files /dev/null and b/examples/textures/resources/raybunny.png differ
diff --git a/examples/textures/resources/wabbit_alpha.png b/examples/textures/resources/wabbit_alpha.png
deleted file mode 100644
index db4081fec..000000000
Binary files a/examples/textures/resources/wabbit_alpha.png and /dev/null differ
diff --git a/examples/textures/textures_bunnymark.c b/examples/textures/textures_bunnymark.c
index 7789602b5..a95181ed6 100644
--- a/examples/textures/textures_bunnymark.c
+++ b/examples/textures/textures_bunnymark.c
@@ -45,7 +45,7 @@ int main(void)
InitWindow(screenWidth, screenHeight, "raylib [textures] example - bunnymark");
// Load bunny texture
- Texture2D texBunny = LoadTexture("resources/wabbit_alpha.png");
+ Texture2D texBunny = LoadTexture("resources/raybunny.png");
Bunny *bunnies = (Bunny *)malloc(MAX_BUNNIES*sizeof(Bunny)); // Bunnies array
diff --git a/examples/textures/textures_bunnymark.png b/examples/textures/textures_bunnymark.png
index 4431ccec4..74ecfb115 100644
Binary files a/examples/textures/textures_bunnymark.png and b/examples/textures/textures_bunnymark.png differ
diff --git a/examples/textures/textures_mouse_painting.c b/examples/textures/textures_mouse_painting.c
index 2575c4450..6996ddac4 100644
--- a/examples/textures/textures_mouse_painting.c
+++ b/examples/textures/textures_mouse_painting.c
@@ -179,7 +179,7 @@ int main(void)
ClearBackground(RAYWHITE);
// NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom)
- DrawTextureRec(target.texture, (Rectangle) { 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2) { 0, 0 }, WHITE);
+ DrawTextureRec(target.texture, (Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height }, (Vector2) { 0, 0 }, WHITE);
// Draw drawing circle for reference
if (mousePos.y > 50)
diff --git a/examples/textures/textures_screen_buffer.c b/examples/textures/textures_screen_buffer.c
new file mode 100644
index 000000000..e620aab31
--- /dev/null
+++ b/examples/textures/textures_screen_buffer.c
@@ -0,0 +1,150 @@
+/*******************************************************************************************
+*
+* raylib [textures] example - screen buffer
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.5, last time updated with raylib 5.5
+*
+* Example contributed by Agnis Aldiņš (@nezvers) 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 Agnis Aldiņš (@nezvers)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include // Required for: calloc(), free()
+
+#define MAX_COLORS 256
+#define SCALE_FACTOR 2
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [textures] example - screen buffer");
+
+ int imageWidth = screenWidth/SCALE_FACTOR;
+ int imageHeight = screenHeight/SCALE_FACTOR;
+ int flameWidth = screenWidth/SCALE_FACTOR;
+
+ Color palette[MAX_COLORS] = { 0 };
+ unsigned char *indexBuffer = RL_CALLOC(imageWidth*imageWidth, sizeof(unsigned char));
+ unsigned char *flameRootBuffer = RL_CALLOC(flameWidth, sizeof(unsigned char));
+
+ Image screenImage = GenImageColor(imageWidth, imageHeight, BLACK);
+ Texture screenTexture = LoadTextureFromImage(screenImage);
+
+ // Generate flame color palette
+ for (int i = 0; i < MAX_COLORS; i++)
+ {
+ float t = (float)i/(float)(MAX_COLORS - 1);
+ float hue = t*t;
+ float saturation = t;
+ float value = t;
+ palette[i] = ColorFromHSV(250.0f + 150.0f*hue, saturation, value);
+ }
+
+ SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ // Grow flameRoot
+ for (int x = 2; x < flameWidth; x++)
+ {
+ unsigned short flame = flameRootBuffer[x];
+ if (flame == 255) continue;
+ flame += GetRandomValue(0, 2);
+ if (flame > 255) flame = 255;
+ flameRootBuffer[x] = flame;
+ }
+
+ // Transfer flameRoot to indexBuffer
+ for (int x = 0; x < flameWidth; x++)
+ {
+ int i = x + (imageHeight - 1)*imageWidth;
+ indexBuffer[i] = flameRootBuffer[x];
+ }
+
+ // Clear top row, because it can't move any higher
+ for (int x = 0; x < imageWidth; x++)
+ {
+ if (indexBuffer[x] == 0) continue;
+ indexBuffer[x] = 0;
+ }
+
+ // Skip top row, it is already cleared
+ for (int y = 1; y < imageHeight; y++)
+ {
+ for (int x = 0; x < imageWidth; x++)
+ {
+ unsigned int i = x + y*imageWidth;
+ unsigned char colorIndex = indexBuffer[i];
+ if (colorIndex == 0) continue;
+
+ // Move pixel a row above
+ indexBuffer[i] = 0;
+ int moveX = GetRandomValue(0, 2) - 1;
+ int newX = x + moveX;
+ if (newX < 0 || newX >= imageWidth) continue;
+
+ unsigned int iabove = i - imageWidth + moveX;
+ int decay = GetRandomValue(0, 3);
+ colorIndex -= (decay < colorIndex)? decay : colorIndex;
+ indexBuffer[iabove] = colorIndex;
+ }
+ }
+
+ // Update screenImage with palette colors
+ for (int y = 1; y < imageHeight; y++)
+ {
+ for (int x = 0; x < imageWidth; x++)
+ {
+ unsigned int i = x + y*imageWidth;
+ unsigned char colorIndex = indexBuffer[i];
+ Color col = palette[colorIndex];
+ ImageDrawPixel(&screenImage, x, y, col);
+ }
+ }
+
+ UpdateTexture(screenTexture, screenImage.data);
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ DrawTextureEx(screenTexture, (Vector2){ 0, 0 }, 0.0f, 2.0f, WHITE);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ RL_FREE(indexBuffer);
+ RL_FREE(flameRootBuffer);
+ UnloadTexture(screenTexture);
+ UnloadImage(screenImage);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
diff --git a/examples/textures/textures_screen_buffer.png b/examples/textures/textures_screen_buffer.png
new file mode 100644
index 000000000..b93bba989
Binary files /dev/null and b/examples/textures/textures_screen_buffer.png differ
diff --git a/examples/textures/textures_sprite_stacking.c b/examples/textures/textures_sprite_stacking.c
new file mode 100644
index 000000000..b20474711
--- /dev/null
+++ b/examples/textures/textures_sprite_stacking.c
@@ -0,0 +1,105 @@
+/*******************************************************************************************
+*
+* raylib [textures] example - sprite stacking
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 6.0
+*
+* Example contributed by Robin (@RobinsAviary) 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
+*
+* Redbooth model (c) 2017-2025 @kluchek under https://creativecommons.org/licenses/by/4.0/ https://github.com/kluchek/vox-models/
+* Copyright (c) 2025 Robin (@RobinsAviary)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h" // Required for: Clamp()
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [textures] example - sprite stacking");
+
+ Texture2D booth = LoadTexture("resources/booth.png");
+
+ float stackScale = 3.0f; // Overall scale of the stacked sprite
+ float stackSpacing = 2.0f; // Vertical spacing between each layer
+ unsigned int stackCount = 122; // Number of layers, used for calculating the size of a single slice
+ float rotationSpeed = 30.0f; // Stacked sprites rotation speed
+ float rotation = 0.0f; // Current rotation of the stacked sprite
+ const float speedChange = 0.25f; // Amount speed will change by when the user presses A/D
+
+ SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ // Use mouse wheel to affect stack separation
+ stackSpacing += GetMouseWheelMove()*0.1f;
+ stackSpacing = Clamp(stackSpacing, 0.0f, 5.0f);
+
+ // Add a positive/negative offset to spin right/left at different speeds
+ if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) rotationSpeed -= speedChange;
+ if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) rotationSpeed += speedChange;
+
+ rotation += rotationSpeed*GetFrameTime();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ // Get the size of a single slice
+ float frameWidth = (float)booth.width;
+ float frameHeight = (float)booth.height/(float)stackCount;
+
+ // Get the scaled resolution to draw at
+ float scaledWidth = frameWidth*stackScale;
+ float scaledHeight = frameHeight*stackScale;
+
+ // Draw the stacked sprite, rotated to the correct angle, with an vertical offset applied based on its y location
+ for (int i = stackCount - 1; i >= 0; i--)
+ {
+ // Center vertically
+ Rectangle source = { 0.0f, (float)i*frameHeight, frameWidth, frameHeight };
+ Rectangle dest = { screenWidth/2.0f, (screenHeight/2.0f) + (i*stackSpacing) - (stackSpacing*stackCount/2.0f), scaledWidth, scaledHeight };
+ Vector2 origin = { scaledWidth/2.0f, scaledHeight/2.0f };
+
+ DrawTexturePro(booth, source, dest, origin, rotation, WHITE);
+ }
+
+ DrawText("A/D to spin\nmouse wheel to change separation (aka 'angle')", 10, 10, 20, DARKGRAY);
+ DrawText(TextFormat("current spacing: %.01f", stackSpacing), 10, 50, 20, DARKGRAY);
+ DrawText(TextFormat("current speed: %.02f", rotationSpeed), 10, 70, 20, DARKGRAY);
+ DrawText("redbooth model (c) kluchek under cc 4.0", 10, 420, 20, DARKGRAY);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadTexture(booth);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/textures/textures_sprite_stacking.png b/examples/textures/textures_sprite_stacking.png
new file mode 100644
index 000000000..53b986823
Binary files /dev/null and b/examples/textures/textures_sprite_stacking.png differ
diff --git a/examples/textures/textures_textured_curve.c b/examples/textures/textures_textured_curve.c
index feeefc7b6..abf78c88a 100644
--- a/examples/textures/textures_textured_curve.c
+++ b/examples/textures/textures_textured_curve.c
@@ -49,7 +49,7 @@ static void DrawTexturedCurve(void);
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
-int main()
+int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
diff --git a/examples/textures/textures_tiled_drawing.c b/examples/textures/textures_tiled_drawing.c
index 10bcad1ad..9e5285035 100644
--- a/examples/textures/textures_tiled_drawing.c
+++ b/examples/textures/textures_tiled_drawing.c
@@ -40,7 +40,7 @@ int main(void)
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
Texture texPattern = LoadTexture("resources/patterns.png");
- SetTextureFilter(texPattern, TEXTURE_FILTER_TRILINEAR); // Makes the texture smoother when upscaled
+ SetTextureFilter(texPattern, TEXTURE_FILTER_BILINEAR); // Makes the texture smoother when upscaled
// Coordinates for all patterns inside the texture
const Rectangle recPattern[] = {
@@ -100,7 +100,7 @@ int main(void)
}
// Check to see which color was clicked and set it as the active color
- for (int i = 0; i < MAX_COLORS; ++i)
+ for (int i = 0; i < MAX_COLORS; i++)
{
if (CheckCollisionPointRec(mouse, colorRec[i]))
{
@@ -110,19 +110,17 @@ int main(void)
}
}
- // Handle keys
-
- // Change scale
+ // Handle keys: change scale
if (IsKeyPressed(KEY_UP)) scale += 0.25f;
if (IsKeyPressed(KEY_DOWN)) scale -= 0.25f;
if (scale > 10.0f) scale = 10.0f;
else if ( scale <= 0.0f) scale = 0.25f;
- // Change rotation
+ // Handle keys: change rotation
if (IsKeyPressed(KEY_LEFT)) rotation -= 25.0f;
if (IsKeyPressed(KEY_RIGHT)) rotation += 25.0f;
- // Reset
+ // Handle keys: reset
if (IsKeyPressed(KEY_SPACE)) { rotation = 0.0f; scale = 1.0f; }
//----------------------------------------------------------------------------------
@@ -165,7 +163,7 @@ int main(void)
// De-Initialization
//--------------------------------------------------------------------------------------
- UnloadTexture(texPattern); // Unload texture
+ UnloadTexture(texPattern); // Unload texture
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
diff --git a/projects/VS2022/examples/audio_spectrum_visualizer.vcxproj b/projects/VS2022/examples/audio_spectrum_visualizer.vcxproj
new file mode 100644
index 000000000..f8e5005fd
--- /dev/null
+++ b/projects/VS2022/examples/audio_spectrum_visualizer.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
+
+
+
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}
+ Win32Proj
+ audio_spectrum_visualizer
+ 10.0
+ audio_spectrum_visualizer
+
+
+
+ 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\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\audio
+ 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/core_compute_hash.vcxproj b/projects/VS2022/examples/core_compute_hash.vcxproj
new file mode 100644
index 000000000..bbca36d86
--- /dev/null
+++ b/projects/VS2022/examples/core_compute_hash.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
+
+
+
+ {6C897101-BE52-4387-8AA2-062123A76BA1}
+ Win32Proj
+ core_compute_hash
+ 10.0
+ core_compute_hash
+
+
+
+ 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/core_viewport_scaling.vcxproj b/projects/VS2022/examples/core_viewport_scaling.vcxproj
new file mode 100644
index 000000000..712cfe2a4
--- /dev/null
+++ b/projects/VS2022/examples/core_viewport_scaling.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
+
+
+
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}
+ Win32Proj
+ core_viewport_scaling
+ 10.0
+ core_viewport_scaling
+
+
+
+ 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/models_decals.vcxproj b/projects/VS2022/examples/models_decals.vcxproj
new file mode 100644
index 000000000..a7a5e2f2b
--- /dev/null
+++ b/projects/VS2022/examples/models_decals.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
+
+
+
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}
+ Win32Proj
+ models_decals
+ 10.0
+ models_decals
+
+
+
+ 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\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ 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;shcore.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/models_directional_billboard.vcxproj b/projects/VS2022/examples/models_directional_billboard.vcxproj
new file mode 100644
index 000000000..2e6c0e8b2
--- /dev/null
+++ b/projects/VS2022/examples/models_directional_billboard.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
+
+
+
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}
+ Win32Proj
+ models_directional_billboard
+ 10.0
+ models_directional_billboard
+
+
+
+ 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\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ 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/shaders_color_correction.vcxproj b/projects/VS2022/examples/shaders_color_correction.vcxproj
new file mode 100644
index 000000000..520c041cb
--- /dev/null
+++ b/projects/VS2022/examples/shaders_color_correction.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
+
+
+
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}
+ Win32Proj
+ shaders_color_correction
+ 10.0
+ shaders_color_correction
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shapes_lines_drawing.vcxproj b/projects/VS2022/examples/shapes_lines_drawing.vcxproj
new file mode 100644
index 000000000..49159676b
--- /dev/null
+++ b/projects/VS2022/examples/shapes_lines_drawing.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
+
+
+
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}
+ Win32Proj
+ shapes_lines_drawing
+ 10.0
+ shapes_lines_drawing
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;shcore.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_math_angle_rotation.vcxproj b/projects/VS2022/examples/shapes_math_angle_rotation.vcxproj
new file mode 100644
index 000000000..48da9d846
--- /dev/null
+++ b/projects/VS2022/examples/shapes_math_angle_rotation.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
+
+
+
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}
+ Win32Proj
+ shapes_math_angle_rotation
+ 10.0
+ shapes_math_angle_rotation
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shapes_math_sine_cosine.vcxproj b/projects/VS2022/examples/shapes_math_sine_cosine.vcxproj
new file mode 100644
index 000000000..8b2457b83
--- /dev/null
+++ b/projects/VS2022/examples/shapes_math_sine_cosine.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
+
+
+
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}
+ Win32Proj
+ shapes_math_sine_cosine
+ 10.0
+ shapes_math_sine_cosine
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;shcore.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_rlgl_color_wheel.vcxproj b/projects/VS2022/examples/shapes_rlgl_color_wheel.vcxproj
new file mode 100644
index 000000000..b22703577
--- /dev/null
+++ b/projects/VS2022/examples/shapes_rlgl_color_wheel.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
+
+
+
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}
+ Win32Proj
+ shapes_rlgl_color_wheel
+ 10.0
+ shapes_rlgl_color_wheel
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shapes_rlgl_triangle.vcxproj b/projects/VS2022/examples/shapes_rlgl_triangle.vcxproj
new file mode 100644
index 000000000..780f514a0
--- /dev/null
+++ b/projects/VS2022/examples/shapes_rlgl_triangle.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
+
+
+
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}
+ Win32Proj
+ shapes_rlgl_triangle
+ 10.0
+ shapes_rlgl_triangle
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/textures_screen_buffer.vcxproj b/projects/VS2022/examples/textures_screen_buffer.vcxproj
new file mode 100644
index 000000000..1697481ce
--- /dev/null
+++ b/projects/VS2022/examples/textures_screen_buffer.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
+
+
+
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}
+ Win32Proj
+ textures_screen_buffer
+ 10.0
+ textures_screen_buffer
+
+
+
+ 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/examples/textures_sprite_stacking.vcxproj b/projects/VS2022/examples/textures_sprite_stacking.vcxproj
new file mode 100644
index 000000000..a3e5be045
--- /dev/null
+++ b/projects/VS2022/examples/textures_sprite_stacking.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
+
+
+
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}
+ Win32Proj
+ textures_sprite_stacking
+ 10.0
+ textures_sprite_stacking
+
+
+
+ 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 ec35ed5e5..07068d34c 100644
--- a/projects/VS2022/raylib.sln
+++ b/projects/VS2022/raylib.sln
@@ -395,6 +395,32 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_text_file_loading", "e
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_mandelbrot_set", "examples\shaders_mandelbrot_set.vcxproj", "{1C829D1A-892C-451C-AF0B-AC65C85F5CC6}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_math_angle_rotation", "examples\shapes_math_angle_rotation.vcxproj", "{84DE22BB-C25F-425C-A7FE-0120CF107B83}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_color_correction", "examples\shaders_color_correction.vcxproj", "{98152EDD-7E28-4FA3-89D8-B636ED5D5F65}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_math_sine_cosine", "examples\shapes_math_sine_cosine.vcxproj", "{B7FDD40F-DDA4-468E-9C40-EEB175964A26}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_decals", "examples\models_decals.vcxproj", "{028F0967-B253-45DA-B1C4-FACCE45D0D8D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_lines_drawing", "examples\shapes_lines_drawing.vcxproj", "{666346D7-C84B-498D-AE17-53B20C62DB1A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_viewport_scaling", "examples\core_viewport_scaling.vcxproj", "{AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_compute_hash", "examples\core_compute_hash.vcxproj", "{6C897101-BE52-4387-8AA2-062123A76BA1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_screen_buffer", "examples\textures_screen_buffer.vcxproj", "{4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "audio_spectrum_visualizer", "examples\audio_spectrum_visualizer.vcxproj", "{2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_directional_billboard", "examples\models_directional_billboard.vcxproj", "{30011884-25EE-42C9-BB15-888CAFB1AA6E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_rlgl_color_wheel", "examples\shapes_rlgl_color_wheel.vcxproj", "{32FE2658-1D70-442E-8672-0AC5C6F0BD7B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_rlgl_triangle", "examples\shapes_rlgl_triangle.vcxproj", "{842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_sprite_stacking", "examples\textures_sprite_stacking.vcxproj", "{FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug.DLL|ARM64 = Debug.DLL|ARM64
@@ -4897,6 +4923,318 @@ Global
{1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x64.Build.0 = Release|x64
{1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x86.ActiveCfg = Release|Win32
{1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x86.Build.0 = Release|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|ARM64.Build.0 = Debug|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|x64.ActiveCfg = Debug|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|x64.Build.0 = Debug|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|x86.ActiveCfg = Debug|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|x86.Build.0 = Debug|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|ARM64.ActiveCfg = Release|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|ARM64.Build.0 = Release|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|x64.ActiveCfg = Release|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|x64.Build.0 = Release|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|x86.ActiveCfg = Release|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|x86.Build.0 = Release|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|ARM64.Build.0 = Debug|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|x64.ActiveCfg = Debug|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|x64.Build.0 = Debug|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|x86.ActiveCfg = Debug|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|x86.Build.0 = Debug|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|ARM64.ActiveCfg = Release|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|ARM64.Build.0 = Release|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|x64.ActiveCfg = Release|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|x64.Build.0 = Release|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|x86.ActiveCfg = Release|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|x86.Build.0 = Release|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|ARM64.Build.0 = Debug|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|x64.ActiveCfg = Debug|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|x64.Build.0 = Debug|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|x86.ActiveCfg = Debug|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|x86.Build.0 = Debug|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|ARM64.ActiveCfg = Release|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|ARM64.Build.0 = Release|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|x64.ActiveCfg = Release|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|x64.Build.0 = Release|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|x86.ActiveCfg = Release|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|x86.Build.0 = Release|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|x64.ActiveCfg = Debug|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|x64.Build.0 = Debug|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|x86.ActiveCfg = Debug|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|x86.Build.0 = Debug|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|ARM64.Build.0 = Release|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|x64.ActiveCfg = Release|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|x64.Build.0 = Release|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|x86.ActiveCfg = Release|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|x86.Build.0 = Release|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|ARM64.Build.0 = Debug|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|x64.ActiveCfg = Debug|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|x64.Build.0 = Debug|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|x86.ActiveCfg = Debug|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|x86.Build.0 = Debug|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|ARM64.ActiveCfg = Release|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|ARM64.Build.0 = Release|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|x64.ActiveCfg = Release|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|x64.Build.0 = Release|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|x86.ActiveCfg = Release|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|x86.Build.0 = Release|Win32
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug|ARM64.Build.0 = Debug|ARM64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug|x64.ActiveCfg = Debug|x64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug|x64.Build.0 = Debug|x64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug|x86.ActiveCfg = Debug|Win32
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Debug|x86.Build.0 = Debug|Win32
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release|ARM64.ActiveCfg = Release|ARM64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release|ARM64.Build.0 = Release|ARM64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release|x64.ActiveCfg = Release|x64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release|x64.Build.0 = Release|x64
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release|x86.ActiveCfg = Release|Win32
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91}.Release|x86.Build.0 = Release|Win32
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug|ARM64.Build.0 = Debug|ARM64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug|x64.ActiveCfg = Debug|x64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug|x64.Build.0 = Debug|x64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug|x86.ActiveCfg = Debug|Win32
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Debug|x86.Build.0 = Debug|Win32
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release|ARM64.ActiveCfg = Release|ARM64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release|ARM64.Build.0 = Release|ARM64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release|x64.ActiveCfg = Release|x64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release|x64.Build.0 = Release|x64
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release|x86.ActiveCfg = Release|Win32
+ {6C897101-BE52-4387-8AA2-062123A76BA1}.Release|x86.Build.0 = Release|Win32
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug|ARM64.Build.0 = Debug|ARM64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug|x64.ActiveCfg = Debug|x64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug|x64.Build.0 = Debug|x64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug|x86.ActiveCfg = Debug|Win32
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Debug|x86.Build.0 = Debug|Win32
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release|ARM64.ActiveCfg = Release|ARM64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release|ARM64.Build.0 = Release|ARM64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release|x64.ActiveCfg = Release|x64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release|x64.Build.0 = Release|x64
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release|x86.ActiveCfg = Release|Win32
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD}.Release|x86.Build.0 = Release|Win32
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug|ARM64.Build.0 = Debug|ARM64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug|x64.ActiveCfg = Debug|x64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug|x64.Build.0 = Debug|x64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug|x86.ActiveCfg = Debug|Win32
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Debug|x86.Build.0 = Debug|Win32
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release|ARM64.ActiveCfg = Release|ARM64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release|ARM64.Build.0 = Release|ARM64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release|x64.ActiveCfg = Release|x64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release|x64.Build.0 = Release|x64
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release|x86.ActiveCfg = Release|Win32
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68}.Release|x86.Build.0 = Release|Win32
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug|ARM64.Build.0 = Debug|ARM64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug|x64.ActiveCfg = Debug|x64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug|x64.Build.0 = Debug|x64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug|x86.ActiveCfg = Debug|Win32
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Debug|x86.Build.0 = Debug|Win32
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release|ARM64.ActiveCfg = Release|ARM64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release|ARM64.Build.0 = Release|ARM64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release|x64.ActiveCfg = Release|x64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release|x64.Build.0 = Release|x64
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release|x86.ActiveCfg = Release|Win32
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E}.Release|x86.Build.0 = Release|Win32
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug|ARM64.Build.0 = Debug|ARM64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug|x64.ActiveCfg = Debug|x64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug|x64.Build.0 = Debug|x64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug|x86.ActiveCfg = Debug|Win32
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Debug|x86.Build.0 = Debug|Win32
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release|ARM64.ActiveCfg = Release|ARM64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release|ARM64.Build.0 = Release|ARM64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release|x64.ActiveCfg = Release|x64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release|x64.Build.0 = Release|x64
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release|x86.ActiveCfg = Release|Win32
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B}.Release|x86.Build.0 = Release|Win32
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug|ARM64.Build.0 = Debug|ARM64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug|x64.ActiveCfg = Debug|x64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug|x64.Build.0 = Debug|x64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug|x86.ActiveCfg = Debug|Win32
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Debug|x86.Build.0 = Debug|Win32
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release|ARM64.ActiveCfg = Release|ARM64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release|ARM64.Build.0 = Release|ARM64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release|x64.ActiveCfg = Release|x64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release|x64.Build.0 = Release|x64
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release|x86.ActiveCfg = Release|Win32
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F}.Release|x86.Build.0 = Release|Win32
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug|ARM64.Build.0 = Debug|ARM64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug|x64.ActiveCfg = Debug|x64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug|x64.Build.0 = Debug|x64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug|x86.ActiveCfg = Debug|Win32
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Debug|x86.Build.0 = Debug|Win32
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|ARM64.ActiveCfg = Release|ARM64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|ARM64.Build.0 = Release|ARM64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|x64.ActiveCfg = Release|x64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|x64.Build.0 = Release|x64
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|x86.ActiveCfg = Release|Win32
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -5064,7 +5402,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} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}
{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}
@@ -5073,7 +5411,7 @@ 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} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
{9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {278D8859-20B1-428F-8448-064F46E1F021}
{52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {278D8859-20B1-428F-8448-064F46E1F021}
{8E132D5A-2C00-48D0-8747-97E41356F26F} = {278D8859-20B1-428F-8448-064F46E1F021}
@@ -5091,11 +5429,24 @@ 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} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}
{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}
{1C829D1A-892C-451C-AF0B-AC65C85F5CC6} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
+ {666346D7-C84B-498D-AE17-53B20C62DB1A} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {AD66AA6A-1E36-4FF0-8670-4F9834BCDB91} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {6C897101-BE52-4387-8AA2-062123A76BA1} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {4E9D2828-EE83-40C8-97E0-137EEDFBAAAD} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}
+ {2B3CED91-973F-4936-9DD4-CC8B1C8ACC68} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}
+ {30011884-25EE-42C9-BB15-888CAFB1AA6E} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
+ {32FE2658-1D70-442E-8672-0AC5C6F0BD7B} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}
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 7721a669a..3a7082d77 100644
--- a/projects/VS2022/raylib/raylib.vcxproj
+++ b/projects/VS2022/raylib/raylib.vcxproj
@@ -242,7 +242,7 @@
Level3
Disabled
- _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP
+ _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_LIB;GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
CompileAsC
$(ProjectDir)..\..\..\src\external\glfw\include
@@ -295,7 +295,7 @@
Level3
Disabled
- _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP;BUILD_LIBTYPE_SHARED
+ _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_LIB;GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP;BUILD_LIBTYPE_SHARED;%(PreprocessorDefinitions)
CompileAsC
$(ProjectDir)..\..\..\src\external\glfw\include
MultiThreadedDebug
@@ -353,10 +353,11 @@
MaxSpeed
true
true
- _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP
+ _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_LIB;GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
$(ProjectDir)..\..\..\src\external\glfw\include
CompileAsC
+ AdvancedVectorExtensions2
Windows
@@ -412,7 +413,7 @@
MaxSpeed
true
true
- _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP;BUILD_LIBTYPE_SHARED
+ _CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_LIB;GRAPHICS_API_OPENGL_33;PLATFORM_DESKTOP;BUILD_LIBTYPE_SHARED;%(PreprocessorDefinitions)
$(ProjectDir)..\..\..\src\external\glfw\include
CompileAsC
MultiThreaded
@@ -532,6 +533,20 @@
true
true
+
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+
true
true
diff --git a/projects/VS2022/raylib/raylib.vcxproj.filters b/projects/VS2022/raylib/raylib.vcxproj.filters
index 4588f0521..33030fc9c 100644
--- a/projects/VS2022/raylib/raylib.vcxproj.filters
+++ b/projects/VS2022/raylib/raylib.vcxproj.filters
@@ -49,6 +49,9 @@
Source Files\Platform Files
+
+ Source Files\Platform Files
+
diff --git a/src/Makefile b/src/Makefile
index 0d4ca9ac7..41867da1c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -130,7 +130,7 @@ HOST_PLATFORM_OS ?= WINDOWS
PLATFORM_OS ?= WINDOWS
# Determine PLATFORM_OS when required
-ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW PLATFORM_WEB PLATFORM_WEB_RGFW PLATFORM_ANDROID))
+ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW PLATFORM_DESKTOP_WIN32 PLATFORM_WEB PLATFORM_WEB_RGFW PLATFORM_ANDROID))
# No uname.exe on MinGW!, but OS=Windows_NT on Windows!
# ifeq ($(UNAME),Msys) -> Windows
ifeq ($(OS),Windows_NT)
@@ -228,7 +228,6 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
ifeq ($(ANDROID_ARCH),x86_64)
ANDROID_COMPILER_ARCH = x86_64
endif
-
endif
# Define raylib graphics api depending on selected platform
@@ -252,18 +251,26 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
#GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
endif
+ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32)
+ GRAPHICS ?= GRAPHICS_API_OPENGL_33
+ #GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering
+ #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
+ #GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
+ #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
+ #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
+endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
- # On DRM OpenGL ES 2.0 must be used
- GRAPHICS = GRAPHICS_API_OPENGL_ES2
+ GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
+ #GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering
endif
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
# On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0
- GRAPHICS = GRAPHICS_API_OPENGL_ES2
+ GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
#GRAPHICS = GRAPHICS_API_OPENGL_ES3
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
# By default use OpenGL ES 2.0 on Android
- GRAPHICS = GRAPHICS_API_OPENGL_ES2
+ GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
endif
# Define default C compiler and archiver to pack library: CC, AR
@@ -283,7 +290,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
- ifeq ($(USE_RPI_CROSS_COMPILER),TRUE)
+ ifeq ($(USE_RPI_CROSSCOMPILER),TRUE)
# Define RPI cross-compiler
#CC = armv6j-hardfloat-linux-gnueabi-gcc
CC = $(RPI_TOOLCHAIN)/bin/$(RPI_TOOLCHAIN_NAME)-gcc
@@ -519,7 +526,7 @@ endif
#------------------------------------------------------------------------------------------------
LDFLAGS = $(CUSTOM_LDFLAGS) -L. -L$(RAYLIB_RELEASE_PATH)
-ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW))
+ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW PLATFORM_DESKTOP_WIN32))
ifeq ($(PLATFORM_OS),WINDOWS)
ifneq ($(CC), tcc)
LDFLAGS += -Wl,--out-implib,$(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME)dll.a
@@ -628,13 +635,19 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
- LDLIBS = -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl
+ LDLIBS = -ldrm -lgbm -lpthread -lrt -lm -ldl
+ ifeq ($(GRAPHICS),GRAPHICS_API_OPENGL_ES2)
+ LDLIBS += -lGLESv2 -lEGL
+ endif
ifeq ($(RAYLIB_MODULE_AUDIO),TRUE)
LDLIBS += -latomic
endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32)
- LDLIBS = -lgdi32 -lwinmm -lopengl32 -lshcore
+ LDLIBS = -lgdi32 -lwinmm -lshcore
+ ifneq ($(GRAPHICS),GRAPHICS_API_OPENGL_11_SOFTWARE)
+ LDLIBS += -lopengl32
+ endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
LDLIBS = -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lc -lm
diff --git a/src/config.h b/src/config.h
index b87e199dc..b749f8952 100644
--- a/src/config.h
+++ b/src/config.h
@@ -49,19 +49,18 @@
#define SUPPORT_RPRAND_GENERATOR 1
// Mouse gestures are directly mapped like touches and processed by gestures system
#define SUPPORT_MOUSE_GESTURES 1
-// Reconfigure standard input to receive key inputs, works with SSH connection.
+// Reconfigure standard input to receive key inputs, works with SSH connection
#define SUPPORT_SSH_KEYBOARD_RPI 1
-// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
-// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
+// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions
+// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often
#define SUPPORT_WINMM_HIGHRES_TIMER 1
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used
//#define SUPPORT_BUSY_WAIT_LOOP 1
// Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy
#define SUPPORT_PARTIALBUSY_WAIT_LOOP 1
// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
+// WARNING: It also requires SUPPORT_IMAGE_EXPORT and SUPPORT_FILEFORMAT_PNG flags
#define SUPPORT_SCREEN_CAPTURE 1
-// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
-#define SUPPORT_GIF_RECORDING 1
// Support CompressData() and DecompressData() functions
#define SUPPORT_COMPRESSION_API 1
// Support automatic generated events, loading and recording of those events when required
@@ -76,7 +75,7 @@
#define SUPPORT_CLIPBOARD_IMAGE 1
// NOTE: Clipboard image loading requires support for some image file formats
-// TODO: Those defines should probably be removed from here, I prefer to let the user manage them
+// TODO: Those defines should probably be removed from here, letting the user manage them
#if defined(SUPPORT_CLIPBOARD_IMAGE)
#ifndef SUPPORT_MODULE_RTEXTURES
#define SUPPORT_MODULE_RTEXTURES 1
@@ -226,7 +225,7 @@
// On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
// at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
-// drawing text and shapes with a single draw call [SetShapesTexture()].
+// drawing text and shapes with a single draw call [SetShapesTexture()]
#define SUPPORT_FONT_ATLAS_WHITE_REC 1
// Support conservative font atlas size estimation
diff --git a/src/external/rlsw.h b/src/external/rlsw.h
index 904bf1210..025216e39 100644
--- a/src/external/rlsw.h
+++ b/src/external/rlsw.h
@@ -7,7 +7,7 @@
* functionality available on rlgl.h library used by raylib, becoming a direct software
* rendering replacement for OpenGL 1.1 backend and allowing to run raylib on GPU-less
* devices when required
-*
+*
* FEATURES:
* - Rendering to custom internal framebuffer with multiple color modes supported:
* - Color buffer: RGB - 8-bit (3:3:2) | RGB - 16-bit (5:6:5) | RGB - 24-bit (8:8:8)
@@ -40,9 +40,17 @@
* 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 RLSW_USE_SIMD_INTRINSICS
+* Detect and use SIMD intrinsics on the host compilation platform
+* SIMD could improve rendering considerable vectorizing some raster operations
+* but the target platforms running the compiled program with SIMD enabled
+* must support the SIMD the program has been built for, making them only
+* recommended under specific situations and only if the developers know
+* what are they doing; this flag is not defined by default
+*
* rlsw capabilities could be customized just defining some internal
* values before library inclusion (default values listed):
-*
+*
* #define SW_GL_FRAMEBUFFER_COPY_BGRA true
* #define SW_GL_BINDING_COPY_TEXTURE true
* #define SW_COLOR_BUFFER_BITS 24
@@ -52,7 +60,7 @@
* #define SW_MAX_TEXTURE_STACK_SIZE 2
* #define SW_MAX_TEXTURES 128
*
-*
+*
* LICENSE: MIT
*
* Copyright (c) 2025-2026 Le Juez Victor (@Bigfoot71), reviewed by Ramon Santamaria (@raysan5)
@@ -63,10 +71,10 @@
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
-*
+*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
-*
+*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -94,11 +102,9 @@
#ifndef SW_MALLOC
#define SW_MALLOC(sz) malloc(sz)
#endif
-
#ifndef SW_REALLOC
#define SW_REALLOC(ptr, newSz) realloc(ptr, newSz)
#endif
-
#ifndef SW_FREE
#define SW_FREE(ptr) free(ptr)
#endif
@@ -115,16 +121,12 @@
#define SW_GL_FRAMEBUFFER_COPY_BGRA true
#endif
-#ifndef SW_GL_BINDING_COPY_TEXTURE
- #define SW_GL_BINDING_COPY_TEXTURE true
-#endif
-
#ifndef SW_COLOR_BUFFER_BITS
- #define SW_COLOR_BUFFER_BITS 24
+ #define SW_COLOR_BUFFER_BITS 32 //< 32 (rgba), 16 (rgb packed) or 8 (rgb packed)
#endif
#ifndef SW_DEPTH_BUFFER_BITS
- #define SW_DEPTH_BUFFER_BITS 16
+ #define SW_DEPTH_BUFFER_BITS 16 //< 32, 24 or 16
#endif
#ifndef SW_MAX_PROJECTION_STACK_SIZE
@@ -143,7 +145,7 @@
#define SW_MAX_TEXTURES 128
#endif
-// Under normal circumstances, clipping a polygon can add at most one vertex per clipping plane.
+// Under normal circumstances, clipping a polygon can add at most one vertex per clipping plane
// Considering the largest polygon involved is a quadrilateral (4 vertices),
// and that clipping occurs against both the frustum (6 planes) and the scissors (4 planes),
// the maximum number of vertices after clipping is:
@@ -196,6 +198,7 @@ typedef double GLclampd;
//#define GL_ATTRIB_STACK_DEPTH 0x0BB0
//#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1
#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
//#define GL_COLOR_WRITEMASK 0x0C23
//#define GL_CURRENT_INDEX 0x0B01
#define GL_CURRENT_COLOR 0x0B00
@@ -330,6 +333,7 @@ typedef double GLclampd;
#define glViewport(x, y, w, h) swViewport((x), (y), (w), (h))
#define glScissor(x, y, w, h) swScissor((x), (y), (w), (h))
#define glClearColor(r, g, b, a) swClearColor((r), (g), (b), (a))
+#define glClearDepth(d) swClearDepth((d))
#define glClear(bitmask) swClear((bitmask))
#define glBlendFunc(sfactor, dfactor) swBlendFunc((sfactor), (dfactor))
#define glPolygonMode(face, mode) swPolygonMode((mode))
@@ -374,14 +378,14 @@ typedef double GLclampd;
#define glTexCoordPointer(sz, t, s, p) swBindArray(SW_TEXTURE_COORD_ARRAY, (p))
#define glColorPointer(sz, t, s, p) swBindArray(SW_COLOR_ARRAY, (p))
#define glDrawArrays(m, o, c) swDrawArrays((m), (o), (c))
+#define glDrawElements(m,c,t,i) swDrawElements((m),(c),(t),(i))
#define glGenTextures(c, v) swGenTextures((c), (v))
#define glDeleteTextures(c, v) swDeleteTextures((c), (v))
-#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), SW_GL_BINDING_COPY_TEXTURE, (p))
+#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), (p))
#define glTexParameteri(tr, pname, param) swTexParameteri((pname), (param))
#define glBindTexture(tr, id) swBindTexture((id))
// OpenGL functions NOT IMPLEMENTED by rlsw
-#define glClearDepth(X) ((void)(X))
#define glDepthMask(X) ((void)(X))
#define glColorMask(X,Y,Z,W) ((void)(X),(void)(Y),(void)(Z),(void)(W))
#define glPixelStorei(X,Y) ((void)(X),(void)(Y))
@@ -391,7 +395,6 @@ typedef double GLclampd;
#define glDepthFunc(X) ((void)(X))
#define glTexSubImage2D(X,Y,Z,W,A,B,C,D,E) ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A),(void)(B),(void)(C),(void)(D),(void)(E))
#define glGetTexImage(X,Y,Z,W,A) ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A))
-#define glDrawElements(X,Y,Z,W) ((void)(X),(void)(Y),(void)(Z),(void)(W))
#define glNormal3f(X,Y,Z) ((void)(X),(void)(Y),(void)(Z))
#define glNormal3fv(X) ((void)(X))
#define glNormalPointer(X,Y,Z) ((void)(X),(void)(Y),(void)(Z))
@@ -413,6 +416,7 @@ typedef enum {
SW_VERSION = GL_VERSION,
SW_EXTENSIONS = GL_EXTENSIONS,
SW_COLOR_CLEAR_VALUE = GL_COLOR_CLEAR_VALUE,
+ SW_DEPTH_CLEAR_VALUE = GL_DEPTH_CLEAR_VALUE,
SW_CURRENT_COLOR = GL_CURRENT_COLOR,
SW_CURRENT_TEXTURE_COORDS = GL_CURRENT_TEXTURE_COORDS,
SW_POINT_SIZE = GL_POINT_SIZE,
@@ -527,7 +531,6 @@ SWAPI void swClose(void);
SWAPI bool swResizeFramebuffer(int w, int h);
SWAPI void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels);
SWAPI void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels);
-SWAPI void *swGetColorBuffer(int *w, int *h);
SWAPI void swEnable(SWstate state);
SWAPI void swDisable(SWstate state);
@@ -540,6 +543,7 @@ SWAPI void swViewport(int x, int y, int width, int height);
SWAPI void swScissor(int x, int y, int width, int height);
SWAPI void swClearColor(float r, float g, float b, float a);
+SWAPI void swClearDepth(float depth);
SWAPI void swClear(uint32_t bitmask);
SWAPI void swBlendFunc(SWfactor sfactor, SWfactor dfactor);
@@ -587,11 +591,12 @@ SWAPI void swTexCoord2fv(const float *v);
SWAPI void swBindArray(SWarray type, void *buffer);
SWAPI void swDrawArrays(SWdraw mode, int offset, int count);
+SWAPI void swDrawElements(SWdraw mode, int count, int type, const void *indices);
SWAPI void swGenTextures(int count, uint32_t *textures);
SWAPI void swDeleteTextures(int count, uint32_t *textures);
-SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void *data);
+SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data);
SWAPI void swTexParameteri(int param, int value);
SWAPI void swBindTexture(uint32_t id);
@@ -605,21 +610,181 @@ SWAPI void swBindTexture(uint32_t id);
#define RLSW_IMPLEMENTATION
#if defined(RLSW_IMPLEMENTATION)
-#include
-#include
-#include // Required for: floorf(), fabsf()
+#include // Required for: malloc(), free()
+#include // Required for: NULL, size_t, uint8_t, uint16_t, uint32_t...
+#include // Required for: sinf(), cosf(), floorf(), fabsf(), sqrtf(), roundf()
+
+// Simple log system to avoid printf() calls if required
+// NOTE: Avoiding those calls, also avoids const strings memory usage
+#define SW_SUPPORT_LOG_INFO
+#if defined(SW_SUPPORT_LOG_INFO) //&& defined(_DEBUG) // WARNING: LOG() output required for this tool
+ #include
+ #define SW_LOG(...) printf(__VA_ARGS__)
+#else
+ #define SW_LOG(...)
+#endif
+
+#if defined(_MSC_VER)
+ #define SW_ALIGN(x) __declspec(align(x))
+#elif defined(__GNUC__) || defined(__clang__)
+ #define SW_ALIGN(x) __attribute__((aligned(x)))
+#else
+ #define SW_ALIGN(x) // Do nothing if not available
+#endif
+
+#if defined(_M_X64) || defined(__x86_64__)
+ #define SW_ARCH_X86_64
+#elif defined(_M_IX86) || defined(__i386__)
+ #define SW_ARCH_X86
+#elif defined(_M_ARM) || defined(__arm__)
+ #define SW_ARCH_ARM32
+#elif defined(_M_ARM64) || defined(__aarch64__)
+ #define SW_ARCH_ARM64
+#elif defined(__riscv)
+ #define SW_ARCH_RISCV
+#endif
+
+#if defined(RLSW_USE_SIMD_INTRINSICS)
+ // Check for SIMD vector instructions
+ // NOTE: Compiler is responsible to enable required flags for host device,
+ // supported features are detected at compiler init but varies depending on compiler
+ // TODO: This logic must be reviewed to avoid the inclusion of multiple headers
+ // and enable the higher level of SIMD available
+ #if defined(__FMA__) && defined(__AVX2__)
+ #define SW_HAS_FMA_AVX2
+ #include
+ #elif defined(__FMA__) && defined(__AVX__)
+ #define SW_HAS_FMA_AVX
+ #include
+ #elif defined(__AVX2__)
+ #define SW_HAS_AVX2
+ #include
+ #elif defined(__AVX__)
+ #define SW_HAS_AVX
+ #include
+ #endif
+ #if defined(__SSE4_2__)
+ #define SW_HAS_SSE42
+ #include
+ #elif defined(__SSE4_1__)
+ #define SW_HAS_SSE41
+ #include
+ #elif defined(__SSSE3__)
+ #define SW_HAS_SSSE3
+ #include
+ #elif defined(__SSE3__)
+ #define SW_HAS_SSE3
+ #include
+ #elif defined(__SSE2__) || (defined(_M_AMD64) || defined(_M_X64)) // SSE2 x64
+ #define SW_HAS_SSE2
+ #include
+ #elif defined(__SSE__)
+ #define SW_HAS_SSE
+ #include
+ #endif
+ #if defined(__ARM_NEON) || defined(__aarch64__)
+ #if defined(__ARM_FEATURE_FMA)
+ #define SW_HAS_NEON_FMA
+ #else
+ #define SW_HAS_NEON
+ #endif
+ #include
+ #endif
+ #if defined(__riscv_vector)
+ // NOTE: Requires compilation flags: -march=rv64gcv -mabi=lp64d
+ #define SW_HAS_RVV
+ #include
+ #endif
+#endif // RLSW_USE_SIMD_INTRINSICS
+
+#ifdef __cplusplus
+ #define SW_CURLY_INIT(name) name
+#else
+ #define SW_CURLY_INIT(name) (name)
+#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define SW_PI 3.14159265358979323846f
+#define SW_INV_255 0.00392156862745098f // 1.0f/255.0f
#define SW_DEG2RAD (SW_PI/180.0f)
#define SW_RAD2DEG (180.0f/SW_PI)
-#define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS/8)
-#define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS/8)
+#define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS >> 3)
+#define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS >> 3)
+#define SW_PIXEL_SIZE (SW_COLOR_PIXEL_SIZE + SW_DEPTH_PIXEL_SIZE)
-#define SW_STATE_CHECK(flags) ((RLSW.stateFlags & (flags)) == (flags))
+#if (SW_PIXEL_SIZE <= 4)
+ #define SW_PIXEL_ALIGNMENT 4
+#else // if (SW_PIXEL_SIZE <= 8)
+ #define SW_PIXEL_ALIGNMENT 8
+#endif
+
+#if (SW_COLOR_BUFFER_BITS == 8)
+ #define SW_COLOR_TYPE uint8_t
+ #define SW_COLOR_IS_PACKED 1
+ #define SW_COLOR_PACK_COMP 1
+ #define SW_PACK_COLOR(r,g,b) ((((uint8_t)((r)*7+0.5f))&0x07)<<5 | (((uint8_t)((g)*7+0.5f))&0x07)<<2 | ((uint8_t)((b)*3+0.5f))&0x03)
+ #define SW_UNPACK_R(p) (((p)>>5)&0x07)
+ #define SW_UNPACK_G(p) (((p)>>2)&0x07)
+ #define SW_UNPACK_B(p) ((p)&0x03)
+ #define SW_SCALE_R(v) ((v)*255+3)/7
+ #define SW_SCALE_G(v) ((v)*255+3)/7
+ #define SW_SCALE_B(v) ((v)*255+1)/3
+ #define SW_TO_FLOAT_R(v) ((v)*(1.0f/7.0f))
+ #define SW_TO_FLOAT_G(v) ((v)*(1.0f/7.0f))
+ #define SW_TO_FLOAT_B(v) ((v)*(1.0f/3.0f))
+#elif (SW_COLOR_BUFFER_BITS == 16)
+ #define SW_COLOR_TYPE uint16_t
+ #define SW_COLOR_IS_PACKED 1
+ #define SW_COLOR_PACK_COMP 1
+ #define SW_PACK_COLOR(r,g,b) ((((uint16_t)((r)*31+0.5f))&0x1F)<<11 | (((uint16_t)((g)*63+0.5f))&0x3F)<<5 | ((uint16_t)((b)*31+0.5f))&0x1F)
+ #define SW_UNPACK_R(p) (((p)>>11)&0x1F)
+ #define SW_UNPACK_G(p) (((p)>>5)&0x3F)
+ #define SW_UNPACK_B(p) ((p)&0x1F)
+ #define SW_SCALE_R(v) ((v)*255+15)/31
+ #define SW_SCALE_G(v) ((v)*255+31)/63
+ #define SW_SCALE_B(v) ((v)*255+15)/31
+ #define SW_TO_FLOAT_R(v) ((v)*(1.0f/31.0f))
+ #define SW_TO_FLOAT_G(v) ((v)*(1.0f/63.0f))
+ #define SW_TO_FLOAT_B(v) ((v)*(1.0f/31.0f))
+#else // 32 bits
+ #define SW_COLOR_TYPE uint8_t
+ #define SW_COLOR_IS_PACKED 0
+ #define SW_COLOR_PACK_COMP 4
+#endif
+
+#if (SW_DEPTH_BUFFER_BITS == 16)
+ #define SW_DEPTH_TYPE uint16_t
+ #define SW_DEPTH_IS_PACKED 1
+ #define SW_DEPTH_PACK_COMP 1
+ #define SW_DEPTH_MAX UINT16_MAX
+ #define SW_DEPTH_SCALE (1.0f/UINT16_MAX)
+ #define SW_PACK_DEPTH(d) ((SW_DEPTH_TYPE)((d)*SW_DEPTH_MAX))
+ #define SW_UNPACK_DEPTH(p) (p)
+#elif (SW_DEPTH_BUFFER_BITS == 24)
+ #define SW_DEPTH_TYPE uint8_t
+ #define SW_DEPTH_IS_PACKED 0
+ #define SW_DEPTH_PACK_COMP 3
+ #define SW_DEPTH_MAX 0xFFFFFFU
+ #define SW_DEPTH_SCALE (1.0f/0xFFFFFFU)
+ #define SW_PACK_DEPTH_0(d) ((uint8_t)(((uint32_t)((d)*SW_DEPTH_MAX)>>16)&0xFFU))
+ #define SW_PACK_DEPTH_1(d) ((uint8_t)(((uint32_t)((d)*SW_DEPTH_MAX)>>8)&0xFFU))
+ #define SW_PACK_DEPTH_2(d) ((uint8_t)((uint32_t)((d)*SW_DEPTH_MAX)&0xFFU))
+ #define SW_UNPACK_DEPTH(p) ((((uint32_t)(p)[0]<<16)|((uint32_t)(p)[1]<<8)|(uint32_t)(p)[2]))
+#else // 32 bits
+ #define SW_DEPTH_TYPE float
+ #define SW_DEPTH_IS_PACKED 1
+ #define SW_DEPTH_PACK_COMP 1
+ #define SW_DEPTH_MAX 1.0f
+ #define SW_DEPTH_SCALE 1.0f
+ #define SW_PACK_DEPTH(d) ((SW_DEPTH_TYPE)(d))
+ #define SW_UNPACK_DEPTH(p) (p)
+#endif
+
+#define SW_STATE_CHECK(flags) (SW_STATE_CHECK_EX(RLSW.stateFlags, (flags)))
+#define SW_STATE_CHECK_EX(state, flags) (((state) & (flags)) == (flags))
#define SW_STATE_SCISSOR_TEST (1 << 0)
#define SW_STATE_TEXTURE_2D (1 << 1)
@@ -668,16 +833,10 @@ typedef struct {
} sw_vertex_t;
typedef struct {
- // Dirty hack for copied data
- // TODO: Rework copied image handling
- union {
- const void *cptr; // NOTE: Is used for all data reads
- void *ptr; // WARNING: Should only be used to allocate and free data
- } pixels;
+ uint8_t *pixels; // Texture pixels (RGBA32)
int width, height; // Dimensions of the texture
int wMinus1, hMinus1; // Dimensions minus one
- sw_pixelformat_t format; // Pixel format (internal representation)
SWfilter minFilter; // Minification filter
SWfilter magFilter; // Magnification filter
@@ -687,14 +846,19 @@ typedef struct {
float tx; // Texel width
float ty; // Texel height
-
- bool copy; // Flag indicating whether memory has been allocated
-
} sw_texture_t;
+// Pixel data type
+typedef SW_ALIGN(SW_PIXEL_ALIGNMENT) struct {
+ SW_COLOR_TYPE color[SW_COLOR_PACK_COMP];
+ SW_DEPTH_TYPE depth[SW_DEPTH_PACK_COMP];
+#if (SW_PIXEL_SIZE % SW_PIXEL_ALIGNMENT != 0)
+ uint8_t padding[SW_PIXEL_ALIGNMENT - SW_PIXEL_SIZE % SW_PIXEL_ALIGNMENT];
+#endif
+} sw_pixel_t;
+
typedef struct {
- void *color;
- void *depth;
+ sw_pixel_t *pixels;
int width;
int height;
int allocSz;
@@ -702,11 +866,10 @@ typedef struct {
typedef struct {
sw_framebuffer_t framebuffer; // Main framebuffer
- float clearColor[4]; // Color used to clear the screen
- float clearDepth; // Depth value used to clear the screen
+ sw_pixel_t clearValue; // Clear value of the framebuffer
- int vpCenter[2]; // Viewport center
- int vpHalfSize[2]; // Viewport half dimensions
+ float vpCenter[2]; // Viewport center
+ float vpHalf[2]; // Viewport half dimensions
int vpSize[2]; // Viewport dimensions (minus one)
int vpMin[2]; // Viewport minimum renderable point (top-left)
int vpMax[2]; // Viewport maximum renderable point (bottom-right)
@@ -733,7 +896,7 @@ typedef struct {
int vertexCounter; // Number of vertices in 'ctx.vertexBuffer'
SWdraw drawMode; // Current primitive mode (e.g., lines, triangles)
- SWpoly polyMode; // Current polygon filling mode (e.g., lines, triangles)
+ SWpoly polyMode; // Current polygon filling mode (e.g., lines, triangles)
int reqVertices; // Number of vertices required for the primitive being drawn
float pointRadius; // Rasterized point radius
float lineWidth; // Rasterized line width
@@ -765,7 +928,6 @@ typedef struct {
int freeTextureIdCount;
uint32_t stateFlags;
-
} sw_context_t;
//----------------------------------------------------------------------------------
@@ -850,11 +1012,7 @@ static inline int sw_clampi(int v, int min, int max)
return v;
}
-static inline void sw_lerp_vertex_PTCH(
- sw_vertex_t *SW_RESTRICT out,
- const sw_vertex_t *SW_RESTRICT a,
- const sw_vertex_t *SW_RESTRICT b,
- float t)
+static inline void sw_lerp_vertex_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t)
{
const float tInv = 1.0f - t;
@@ -881,11 +1039,7 @@ static inline void sw_lerp_vertex_PTCH(
out->homogeneous[3] = a->homogeneous[3]*tInv + b->homogeneous[3]*t;
}
-static inline void sw_get_vertex_grad_PTCH(
- sw_vertex_t *SW_RESTRICT out,
- const sw_vertex_t *SW_RESTRICT a,
- const sw_vertex_t *SW_RESTRICT b,
- float scale)
+static inline void sw_get_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale)
{
// Calculate gradients for Position
out->position[0] = (b->position[0] - a->position[0])*scale;
@@ -910,9 +1064,7 @@ static inline void sw_get_vertex_grad_PTCH(
out->homogeneous[3] = (b->homogeneous[3] - a->homogeneous[3])*scale;
}
-static inline void sw_add_vertex_grad_PTCH(
- sw_vertex_t *SW_RESTRICT out,
- const sw_vertex_t *SW_RESTRICT gradients)
+static inline void sw_add_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients)
{
// Add gradients to Position
out->position[0] += gradients->position[0];
@@ -937,8 +1089,131 @@ static inline void sw_add_vertex_grad_PTCH(
out->homogeneous[3] += gradients->homogeneous[3];
}
-// Half floating point management functions
-static inline uint32_t sw_f16_to_f32_ui(uint16_t h)
+static inline void sw_add_vertex_grad_scaled_PTCH(
+ sw_vertex_t *SW_RESTRICT out,
+ const sw_vertex_t *SW_RESTRICT gradients,
+ float scale)
+{
+ // Add gradients to Position
+ out->position[0] += gradients->position[0]*scale;
+ out->position[1] += gradients->position[1]*scale;
+ out->position[2] += gradients->position[2]*scale;
+ out->position[3] += gradients->position[3]*scale;
+
+ // Add gradients to Texture coordinates
+ out->texcoord[0] += gradients->texcoord[0]*scale;
+ out->texcoord[1] += gradients->texcoord[1]*scale;
+
+ // Add gradients to Color
+ out->color[0] += gradients->color[0]*scale;
+ out->color[1] += gradients->color[1]*scale;
+ out->color[2] += gradients->color[2]*scale;
+ out->color[3] += gradients->color[3]*scale;
+
+ // Add gradients to Homogeneous coordinates
+ out->homogeneous[0] += gradients->homogeneous[0]*scale;
+ out->homogeneous[1] += gradients->homogeneous[1]*scale;
+ out->homogeneous[2] += gradients->homogeneous[2]*scale;
+ out->homogeneous[3] += gradients->homogeneous[3]*scale;
+}
+
+static inline void sw_float_to_unorm8_simd(uint8_t dst[4], const float src[4])
+{
+#if defined(SW_HAS_NEON)
+ float32x4_t values = vld1q_f32(src);
+ float32x4_t scaled = vmulq_n_f32(values, 255.0f);
+ int32x4_t clamped_s32 = vcvtq_s32_f32(scaled); // f32 -> s32 (truncated)
+ int16x4_t narrow16_s = vqmovn_s32(clamped_s32);
+ int16x8_t combined16_s = vcombine_s16(narrow16_s, narrow16_s);
+ uint8x8_t narrow8_u = vqmovun_s16(combined16_s);
+ vst1_lane_u32((uint32_t*)dst, vreinterpret_u32_u8(narrow8_u), 0);
+#elif defined(SW_HAS_SSE41)
+ __m128 values = _mm_loadu_ps(src);
+ __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f));
+ __m128i clamped = _mm_cvtps_epi32(scaled); // f32 -> s32 (truncated)
+ clamped = _mm_packus_epi32(clamped, clamped); // s32 -> u16 (saturated < 0 to 0)
+ clamped = _mm_packus_epi16(clamped, clamped); // u16 -> u8 (saturated > 255 to 255)
+ *(uint32_t*)dst = _mm_cvtsi128_si32(clamped);
+#elif defined(SW_HAS_SSE2)
+ __m128 values = _mm_loadu_ps(src);
+ __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f));
+ __m128i clamped = _mm_cvtps_epi32(scaled); // f32 -> s32 (truncated)
+ clamped = _mm_packs_epi32(clamped, clamped); // s32 -> s16 (saturated)
+ clamped = _mm_packus_epi16(clamped, clamped); // s16 -> u8 (saturated < 0 to 0)
+ *(uint32_t*)dst = _mm_cvtsi128_si32(clamped);
+#elif defined(SW_HAS_RVV)
+ // TODO: Sample code generated by AI, needs testing and review
+ // NOTE: RVV 1.0 specs define the use of __riscv_ prefix for instrinsic functions
+ size_t vl = __riscv_vsetvl_e32m1(4); // Load up to 4 floats into a vector register
+ vfloat32m1_t vsrc = __riscv_vle32_v_f32m1(src, vl); // Load float32 values
+
+ // Clamp to [0.0f, 1.0f]
+ vfloat32m1_t vzero = __riscv_vfmv_v_f_f32m1(0.0f, vl);
+ vfloat32m1_t vone = __riscv_vfmv_v_f_f32m1(1.0f, vl);
+ vsrc = __riscv_vfmin_vv_f32m1(vsrc, vone, vl);
+ vsrc = __riscv_vfmax_vv_f32m1(vsrc, vzero, vl);
+
+ // Multiply by 255.0f and add 0.5f for rounding
+ vfloat32m1_t vscaled = __riscv_vfmul_vf_f32m1(vsrc, 255.0f, vl);
+ vscaled = __riscv_vfadd_vf_f32m1(vscaled, 0.5f, vl);
+
+ // Convert to unsigned integer (truncate toward zero)
+ vuint32m1_t vu32 = __riscv_vfcvt_xu_f_v_u32m1(vscaled, vl);
+
+ // Narrow from u32 -> u8
+ vuint8m1_t vu8 = __riscv_vnclipu_wx_u8m1(vu32, 0, vl); // Round toward zero
+ __riscv_vse8_v_u8m1(dst, vu8, vl); // Store result
+#else
+ for (int i = 0; i < 4; i++)
+ {
+ float val = src[i]*255.0f;
+ val = (val > 255.0f)? 255.0f : val;
+ val = (val < 0.0f)? 0.0f : val;
+ dst[i] = (uint8_t)val;
+ }
+#endif
+}
+
+static inline void sw_float_from_unorm8_simd(float dst[4], const uint8_t src[4])
+{
+#if defined(SW_HAS_NEON)
+ uint8x8_t bytes8 = vld1_u8(src); //< Read 8 bytes, faster, but let's hope we're not at the end of the page (unlikely)...
+ uint16x8_t bytes16 = vmovl_u8(bytes8);
+ uint32x4_t ints = vmovl_u16(vget_low_u16(bytes16));
+ float32x4_t floats = vcvtq_f32_u32(ints);
+ floats = vmulq_n_f32(floats, SW_INV_255);
+ vst1q_f32(dst, floats);
+#elif defined(SW_HAS_SSE41)
+ __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t *)src);
+ __m128i ints = _mm_cvtepu8_epi32(bytes);
+ __m128 floats = _mm_cvtepi32_ps(ints);
+ floats = _mm_mul_ps(floats, _mm_set1_ps(SW_INV_255));
+ _mm_storeu_ps(dst, floats);
+#elif defined(SW_HAS_SSE2)
+ __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t *)src);
+ bytes = _mm_unpacklo_epi8(bytes, _mm_setzero_si128());
+ __m128i ints = _mm_unpacklo_epi16(bytes, _mm_setzero_si128());
+ __m128 floats = _mm_cvtepi32_ps(ints);
+ floats = _mm_mul_ps(floats, _mm_set1_ps(SW_INV_255));
+ _mm_storeu_ps(dst, floats);
+#elif defined(SW_HAS_RVV)
+ // TODO: Sample code generated by AI, needs testing and review
+ size_t vl = __riscv_vsetvl_e8m1(4); // Set vector length for 8-bit input elements
+ vuint8m1_t vsrc_u8 = __riscv_vle8_v_u8m1(src, vl); // Load 4 unsigned 8-bit integers
+ vuint32m1_t vsrc_u32 = __riscv_vwcvt_xu_u_v_u32m1(vsrc_u8, vl); // Widen to 32-bit unsigned integers
+ vfloat32m1_t vsrc_f32 = __riscv_vfcvt_f_xu_v_f32m1(vsrc_u32, vl); // Convert to float32
+ vfloat32m1_t vnorm = __riscv_vfmul_vf_f32m1(vsrc_f32, SW_INV_255, vl); // Multiply by 1/255.0 to normalize
+ __riscv_vse32_v_f32m1(dst, vnorm, vl); // Store result
+#else
+ dst[0] = (float)src[0]*SW_INV_255;
+ dst[1] = (float)src[1]*SW_INV_255;
+ dst[2] = (float)src[2]*SW_INV_255;
+ dst[3] = (float)src[3]*SW_INV_255;
+#endif
+}
+
+// Half conversion functions
+static inline uint32_t sw_half_to_float_ui(uint16_t h)
{
uint32_t s = (uint32_t)(h & 0x8000) << 16;
int32_t em = h & 0x7fff;
@@ -956,14 +1231,14 @@ static inline uint32_t sw_f16_to_f32_ui(uint16_t h)
return s | r;
}
-static inline float sw_f16_to_f32(sw_half_t y)
+static inline float sw_half_to_float(sw_half_t y)
{
- union { float f; uint32_t i; } v = { .i = sw_f16_to_f32_ui(y) };
+ union { float f; uint32_t i; } v = { .i = sw_half_to_float_ui(y) };
return v.f;
}
-static inline uint16_t sw_f16_from_f32_ui(uint32_t ui)
+static inline uint16_t sw_half_from_float_ui(uint32_t ui)
{
int32_t s = (ui >> 16) & 0x8000;
int32_t em = ui & 0x7fffffff;
@@ -983,23 +1258,21 @@ static inline uint16_t sw_f16_from_f32_ui(uint32_t ui)
return (uint16_t)(s | h);
}
-static inline sw_half_t sw_f16_from_f32(float i)
+static inline sw_half_t sw_half_from_float(float i)
{
union { float f; uint32_t i; } v;
v.f = i;
- return sw_f16_from_f32_ui(v.i);
+ return sw_half_from_float_ui(v.i);
}
// Framebuffer management functions
+//-------------------------------------------------------------------------------------------
static inline bool sw_framebuffer_load(int w, int h)
{
int size = w*h;
- RLSW.framebuffer.color = SW_MALLOC(SW_COLOR_PIXEL_SIZE*size);
- if (RLSW.framebuffer.color == NULL) return false;
-
- RLSW.framebuffer.depth = SW_MALLOC(SW_DEPTH_PIXEL_SIZE*size);
- if (RLSW.framebuffer.depth == NULL) return false;
+ RLSW.framebuffer.pixels = SW_MALLOC(sizeof(sw_pixel_t)*size);
+ if (RLSW.framebuffer.pixels == NULL) return false;
RLSW.framebuffer.width = w;
RLSW.framebuffer.height = h;
@@ -1019,14 +1292,10 @@ static inline bool sw_framebuffer_resize(int w, int h)
return true;
}
- void *newColor = SW_REALLOC(RLSW.framebuffer.color, newSize);
- if (newColor == NULL) return false;
+ void *newPixels = SW_REALLOC(RLSW.framebuffer.pixels, sizeof(sw_pixel_t)*newSize);
+ if (newPixels == NULL) return false;
- void *newDepth = SW_REALLOC(RLSW.framebuffer.depth, newSize);
- if (newDepth == NULL) return false;
-
- RLSW.framebuffer.color = newColor;
- RLSW.framebuffer.depth = newDepth;
+ RLSW.framebuffer.pixels = newPixels;
RLSW.framebuffer.width = w;
RLSW.framebuffer.height = h;
@@ -1035,481 +1304,175 @@ static inline bool sw_framebuffer_resize(int w, int h)
return true;
}
-static inline void *sw_framebuffer_get_color_addr(const void *ptr, uint32_t offset)
+static inline void sw_framebuffer_read_color(float dst[4], const sw_pixel_t *src)
{
- return (uint8_t *)ptr + offset*SW_COLOR_PIXEL_SIZE;
-}
-
-static inline void sw_framebuffer_inc_color_addr(void **ptr)
-{
- *ptr = (void *)(((uint8_t *)*ptr) + SW_COLOR_PIXEL_SIZE);
-}
-
-static inline void sw_framebuffer_inc_const_color_addr(const void **ptr)
-{
- *ptr = (const void *)(((const uint8_t *)*ptr) + SW_COLOR_PIXEL_SIZE);
-}
-
-static inline void *sw_framebuffer_get_depth_addr(const void *ptr, uint32_t offset)
-{
- return (uint8_t *)ptr + offset*SW_DEPTH_PIXEL_SIZE;
-}
-
-static inline void sw_framebuffer_inc_depth_addr(void* *ptr)
-{
- *ptr = (void*)(((uint8_t *)*ptr) + SW_DEPTH_PIXEL_SIZE);
-}
-
-#if (SW_COLOR_BUFFER_BITS == 8) // RGB - (3:3:2)
-static inline void sw_framebuffer_read_color(float dst[4], const void *src)
-{
- uint8_t pixel = ((uint8_t *)src)[0];
-
- dst[0] = ((pixel >> 5) & 0x07)*(1.0f/7.0f);
- dst[1] = ((pixel >> 2) & 0x07)*(1.0f/7.0f);
- dst[2] = (pixel & 0x03)*(1.0f/3.0f);
+#if SW_COLOR_IS_PACKED
+ SW_COLOR_TYPE pixel = src->color[0];
+ dst[0] = SW_TO_FLOAT_R(SW_UNPACK_R(pixel));
+ dst[1] = SW_TO_FLOAT_G(SW_UNPACK_G(pixel));
+ dst[2] = SW_TO_FLOAT_B(SW_UNPACK_B(pixel));
dst[3] = 1.0f;
+#else
+ sw_float_from_unorm8_simd(dst, src->color);
+#endif
}
-static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src)
+static inline void sw_framebuffer_read_color8(uint8_t dst[4], const sw_pixel_t *src)
{
- uint8_t pixel = ((const uint8_t *)src)[0];
-
- uint8_t r = (pixel >> 5) & 0x07;
- uint8_t g = (pixel >> 2) & 0x07;
- uint8_t b = pixel & 0x03;
-
- dst[0] = (r*255 + 3)/7;
- dst[1] = (g*255 + 3)/7;
- dst[2] = (b*255 + 1)/3;
+#if SW_COLOR_IS_PACKED
+ SW_COLOR_TYPE pixel = src->color[0];
+ dst[0] = SW_SCALE_R(SW_UNPACK_R(pixel));
+ dst[1] = SW_SCALE_G(SW_UNPACK_G(pixel));
+ dst[2] = SW_SCALE_B(SW_UNPACK_B(pixel));
dst[3] = 255;
+#else
+ const SW_COLOR_TYPE *p = src->color;
+ dst[0] = p[0];
+ dst[1] = p[1];
+ dst[2] = p[2];
+ dst[3] = p[3];
+#endif
}
-static inline void sw_framebuffer_write_color(void *dst, const float color[3])
+static inline float sw_framebuffer_read_depth(const sw_pixel_t *src)
{
- uint8_t r = ((uint8_t)(color[0]*UINT8_MAX) >> 5) & 0x07;
- uint8_t g = ((uint8_t)(color[1]*UINT8_MAX) >> 5) & 0x07;
- uint8_t b = ((uint8_t)(color[2]*UINT8_MAX) >> 6) & 0x03;
-
- ((uint8_t *)dst)[0] = (r << 5) | (g << 2) | b;
+#if SW_DEPTH_IS_PACKED
+ return src->depth[0]*SW_DEPTH_SCALE;
+#else
+ return SW_UNPACK_DEPTH(src->depth)*SW_DEPTH_SCALE;
+#endif
}
-static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3])
+static inline void sw_framebuffer_write_color(sw_pixel_t *dst, const float src[4])
{
- uint8_t r8 = (uint8_t)(color[0]*7.0f + 0.5f);
- uint8_t g8 = (uint8_t)(color[1]*7.0f + 0.5f);
- uint8_t b8 = (uint8_t)(color[2]*3.0f + 0.5f);
+#if SW_COLOR_IS_PACKED
+ dst->color[0] = SW_PACK_COLOR(src[0], src[1], src[2]);
+#else
+ sw_float_to_unorm8_simd(dst->color, src);
+#endif
+}
- uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03);
+static inline void sw_framebuffer_write_depth(sw_pixel_t *dst, float depth)
+{
+ depth = sw_saturate(depth); // REVIEW: An overflow can occur in certain circumstances with clipping, and needs to be reviewed...
- uint8_t *p = (uint8_t *)ptr;
+#if SW_DEPTH_IS_PACKED
+ dst->depth[0] = SW_PACK_DEPTH(depth);
+#else
+ dst->depth[0] = SW_PACK_DEPTH_0(depth);
+ dst->depth[1] = SW_PACK_DEPTH_1(depth);
+ dst->depth[2] = SW_PACK_DEPTH_2(depth);
+#endif
+}
+static inline void sw_framebuffer_fill_color(sw_pixel_t *ptr, int size, const SW_COLOR_TYPE color[SW_COLOR_PACK_COMP])
+{
if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
{
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
+ int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
{
- uint8_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = packedColor;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = packedColor;
- }
-}
-
-#elif (SW_COLOR_BUFFER_BITS == 16) // RGB - (5:6:5)
-
-static inline void sw_framebuffer_read_color(float dst[4], const void *src)
-{
- uint16_t pixel = ((uint16_t *)src)[0];
-
- dst[0] = ((pixel >> 11) & 0x1F)*(1.0f/31.0f);
- dst[1] = ((pixel >> 5) & 0x3F)*(1.0f/63.0f);
- dst[2] = (pixel & 0x1F)*(1.0f/31.0f);
- dst[3] = 1.0f;
-}
-
-static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src)
-{
- uint16_t pixel = ((const uint16_t *)src)[0];
-
- uint8_t r = (pixel >> 11) & 0x1F;
- uint8_t g = (pixel >> 5) & 0x3F;
- uint8_t b = pixel & 0x1F;
-
- dst[0] = (r*255 + 15)/31;
- dst[1] = (g*255 + 31)/63;
- dst[2] = (b*255 + 15)/31;
- dst[3] = 255;
-}
-
-static inline void sw_framebuffer_write_color(void *dst, const float color[3])
-{
- uint8_t r = (uint8_t)(color[0]*31.0f + 0.5f) & 0x1F;
- uint8_t g = (uint8_t)(color[1]*63.0f + 0.5f) & 0x3F;
- uint8_t b = (uint8_t)(color[2]*31.0f + 0.5f) & 0x1F;
-
- ((uint16_t *)dst)[0] = (r << 11) | (g << 5) | b;
-}
-
-static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3])
-{
- uint16_t r16 = (uint16_t)(color[0]*31.0f + 0.5f);
- uint16_t g_16 = (uint16_t)(color[1]*63.0f + 0.5f);
- uint16_t b_16 = (uint16_t)(color[2]*31.0f + 0.5f);
-
- uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g_16 & 0x3F) << 5) | (b_16 & 0x1F);
-
- uint16_t *p = (uint16_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint16_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = packedColor;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = packedColor;
- }
-}
-
-#elif (SW_COLOR_BUFFER_BITS == 24) // RGB - (8:8:8)
-
-static inline void sw_framebuffer_read_color(float dst[4], const void *src)
-{
- dst[0] = ((uint8_t *)src)[0]*(1.0f/255.0f);
- dst[1] = ((uint8_t *)src)[1]*(1.0f/255.0f);
- dst[2] = ((uint8_t *)src)[2]*(1.0f/255.0f);
- dst[3] = 1.0f;
-}
-
-static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src)
-{
- dst[0] = ((uint8_t *)src)[0];
- dst[1] = ((uint8_t *)src)[1];
- dst[2] = ((uint8_t *)src)[2];
- dst[3] = 255;
-}
-
-static inline void sw_framebuffer_write_color(void *dst, const float color[3])
-{
- ((uint8_t *)dst)[0] = (uint8_t)(color[0]*UINT8_MAX);
- ((uint8_t *)dst)[1] = (uint8_t)(color[1]*UINT8_MAX);
- ((uint8_t *)dst)[2] = (uint8_t)(color[2]*UINT8_MAX);
-}
-
-static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3])
-{
- uint8_t r = (uint8_t)(color[0]*255.0f);
- uint8_t g = (uint8_t)(color[1]*255.0f);
- uint8_t b = (uint8_t)(color[2]*255.0f);
-
- uint8_t *p = (uint8_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint8_t *curPtr = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]);
- for (int xCount = 0; xCount < wScissor; xCount++)
+ sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0];
+ for (int x = 0; x < w; x++, row++)
{
- *curPtr++ = r;
- *curPtr++ = g;
- *curPtr++ = b;
+ for (int i = 0; i < SW_COLOR_PACK_COMP; i++) row->color[i] = color[i];
}
}
}
else
{
+ for (int i = 0; i < size; i++, ptr++)
+ {
+ for (int j = 0; j < SW_COLOR_PACK_COMP; j++) ptr->color[j] = color[j];
+ }
+ }
+}
+
+static inline void sw_framebuffer_fill_depth(sw_pixel_t *ptr, int size, const SW_DEPTH_TYPE depth[SW_DEPTH_PACK_COMP])
+{
+ if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
+ {
+ int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
+ for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
+ {
+ sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0];
+ for (int x = 0; x < w; x++, row++)
+ {
+ for (int i = 0; i < SW_DEPTH_PACK_COMP; i++) row->depth[i] = depth[i];
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < size; i++, ptr++)
+ {
+ for (int j = 0; j < SW_DEPTH_PACK_COMP; j++) ptr->depth[j] = depth[j];
+ }
+ }
+}
+
+static inline void sw_framebuffer_fill(sw_pixel_t *ptr, int size, sw_pixel_t value)
+{
+ if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
+ {
+ int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
+ for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
+ {
+ sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0];
+ for (int x = 0; x < w; x++, row++) *row = value;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < size; i++, ptr++) *ptr = value;
+ }
+}
+
+static inline void sw_framebuffer_copy_fast(void* dst)
+{
+ int size = RLSW.framebuffer.width*RLSW.framebuffer.height;
+ const sw_pixel_t *pixels = RLSW.framebuffer.pixels;
+
+#if SW_COLOR_BUFFER_BITS == 8
+ uint8_t *dst8 = (uint8_t*)dst;
+ for (int i = 0; i < size; i++) dst8[i] = pixels[i].color[0];
+#elif SW_COLOR_BUFFER_BITS == 16
+ uint16_t *dst16 = (uint16_t*)dst;
+ for (int i = 0; i < size; i++) dst16[i] = *(uint16_t*)pixels[i].color;
+#else // 32 bits
+ uint32_t *dst32 = (uint32_t*)dst;
+ #if SW_GL_FRAMEBUFFER_COPY_BGRA
for (int i = 0; i < size; i++)
{
- *p++ = r;
- *p++ = g;
- *p++ = b;
+ const uint8_t *c = pixels[i].color;
+ dst32[i] = (uint32_t)c[2] | ((uint32_t)c[1] << 8) | ((uint32_t)c[0] << 16) | ((uint32_t)c[3] << 24);
}
- }
-}
-
-#endif // SW_COLOR_BUFFER_BITS
-
-#if (SW_DEPTH_BUFFER_BITS == 8)
-
-static inline float sw_framebuffer_read_depth(const void *src)
-{
- return (float)((uint8_t *)src)[0]*(1.0f/UINT8_MAX);
-}
-
-static inline void sw_framebuffer_write_depth(void *dst, float depth)
-{
- ((uint8_t *)dst)[0] = (uint8_t)(depth*UINT8_MAX);
-}
-
-static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value)
-{
- uint8_t d8 = (uint8_t)(value*UINT8_MAX);
- uint8_t *p = (uint8_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint8_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = d8;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = d8;
- }
-}
-
-#elif (SW_DEPTH_BUFFER_BITS == 16)
-
-static inline float sw_framebuffer_read_depth(const void *src)
-{
- return (float)((uint16_t *)src)[0]*(1.0f/UINT16_MAX);
-}
-
-static inline void sw_framebuffer_write_depth(void *dst, float depth)
-{
- ((uint16_t *)dst)[0] = (uint16_t)(depth*UINT16_MAX);
-}
-
-static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value)
-{
- uint16_t d16 = (uint16_t)(value*UINT16_MAX);
- uint16_t *p = (uint16_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint16_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = d16;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = d16;
- }
-}
-
-#elif (SW_DEPTH_BUFFER_BITS == 24)
-
-static inline float sw_framebuffer_read_depth(const void *src)
-{
- uint32_t depth24 = (((uint8_t *)src)[0] << 16) |
- (((uint8_t *)src)[1] << 8) |
- ((uint8_t *)src)[2];
-
- return depth24/(float)0xFFFFFF;
-}
-
-static inline void sw_framebuffer_write_depth(void *dst, float depth)
-{
- uint32_t depth24 = (uint32_t)(depth*0xFFFFFF);
-
- ((uint8_t *)dst)[0] = (depth24 >> 16) & 0xFF;
- ((uint8_t *)dst)[1] = (depth24 >> 8) & 0xFF;
- ((uint8_t *)dst)[2] = depth24 & 0xFF;
-}
-
-static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value)
-{
- uint32_t d32 = (uint32_t)(value*UINT32_MAX);
- uint8_t d_byte0 = (uint8_t)((d32 >> 16) & 0xFF);
- uint8_t d_byte1 = (uint8_t)((d32 >> 8) & 0xFF);
- uint8_t d_byte2 = (uint8_t)(d32 & 0xFF);
-
- uint8_t *p = (uint8_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint8_t *curPtr = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]);
- for (int xCount = 0; xCount < wScissor; xCount++)
- {
- *curPtr++ = d_byte0;
- *curPtr++ = d_byte1;
- *curPtr++ = d_byte2;
- }
- }
- }
- else
- {
- for (int i = 0; i < size; i++)
- {
- *p++ = d_byte0;
- *p++ = d_byte1;
- *p++ = d_byte2;
- }
- }
-}
-
-#endif // SW_DEPTH_BUFFER_BITS
-
-static inline void sw_framebuffer_fill(void *colorPtr, void *depthPtr, int size, float color[4], float depth_value)
-{
-#if (SW_COLOR_BUFFER_BITS == 8)
- // Calculate and pack 3:3:2 color
- // Scale color components to the max value for each bit depth and round
- uint8_t r8 = (uint8_t)(color[0]*7.0f + 0.5f);
- uint8_t g8 = (uint8_t)(color[1]*7.0f + 0.5f);
- uint8_t b8 = (uint8_t)(color[2]*3.0f + 0.5f);
- // Pack the components into a single byte
- uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03);
- uint8_t *cptr = (uint8_t *)colorPtr;
-#elif (SW_COLOR_BUFFER_BITS == 16)
- // Calculate and pack 5:6:5 color
- // Scale color components to the max value for each bit depth and round
- uint16_t r16 = (uint16_t)(color[0]*31.0f + 0.5f);
- uint16_t g16 = (uint16_t)(color[1]*63.0f + 0.5f);
- uint16_t b16 = (uint16_t)(color[2]*31.0f + 0.5f);
- // Pack the components into a 16-bit value
- uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g16 & 0x3F) << 5) | (b16 & 0x1F);
- uint16_t *cptr = (uint16_t *)colorPtr;
-#elif (SW_COLOR_BUFFER_BITS == 24)
- // Calculate 8:8:8 color components
- uint8_t r24 = (uint8_t)(color[0]*255.0f);
- uint8_t g24 = (uint8_t)(color[1]*255.0f);
- uint8_t b24 = (uint8_t)(color[2]*255.0f);
- uint8_t *cptr = (uint8_t *)colorPtr;
-#endif
-
-#if (SW_DEPTH_BUFFER_BITS == 8)
- // Calculate 8-bit depth
- uint8_t d8 = (uint8_t)(depth_value*UINT8_MAX);
- uint8_t *dptr = (uint8_t *)depthPtr;
-#elif (SW_DEPTH_BUFFER_BITS == 16)
- // Calculate 16-bit depth
- uint16_t d16 = (uint16_t)(depth_value*UINT16_MAX);
- uint16_t *dptr = (uint16_t *)depthPtr;
-#elif (SW_DEPTH_BUFFER_BITS == 24)
- // Calculate 24-bit depth and pre-calculate bytes
- uint32_t d32 = (uint32_t)(depth_value*UINT32_MAX);
- uint8_t dByte0 = (uint8_t)((d32 >> 16) & 0xFF);
- uint8_t dByte1 = (uint8_t)((d32 >> 8) & 0xFF);
- uint8_t dByte2 = (uint8_t)(d32 & 0xFF);
- uint8_t *dptr = (uint8_t *)depthPtr;
-#endif
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- int rowStartIdx = y*RLSW.framebuffer.width + RLSW.scMin[0];
-
- // Calculate starting pointers for the current row within the scissor rectangle
- #if (SW_COLOR_BUFFER_BITS == 8)
- uint8_t *curCPtr = cptr + rowStartIdx;
- #elif (SW_COLOR_BUFFER_BITS == 16)
- uint16_t *curCPtr = cptr + rowStartIdx;
- #elif (SW_COLOR_BUFFER_BITS == 24)
- uint8_t *curCPtr = cptr + 3*rowStartIdx;
- #endif
-
- #if (SW_DEPTH_BUFFER_BITS == 8)
- uint8_t *curDPtr = dptr + rowStartIdx;
- #elif (SW_DEPTH_BUFFER_BITS == 16)
- uint16_t *curDPtr = dptr + rowStartIdx;
- #elif (SW_DEPTH_BUFFER_BITS == 24)
- uint8_t *curDPtr = dptr + 3*rowStartIdx;
- #endif
-
- // Fill the current row within the scissor rectangle
- for (int xCount = 0; xCount < wScissor; xCount++)
- {
- // Write color
- #if (SW_COLOR_BUFFER_BITS == 8)
- *curCPtr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 16)
- *curCPtr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 24)
- *curCPtr++ = r24;
- *curCPtr++ = g24;
- *curCPtr++ = b24;
- #endif
-
- // Write depth
- #if (SW_DEPTH_BUFFER_BITS == 8)
- *curDPtr++ = d8;
- #elif (SW_DEPTH_BUFFER_BITS == 16)
- *curDPtr++ = d16;
- #elif (SW_DEPTH_BUFFER_BITS == 24)
- *curDPtr++ = dByte0;
- *curDPtr++ = dByte1;
- *curDPtr++ = dByte2;
- #endif
- }
- }
- return;
- }
-
- for (int i = 0; i < size; i++)
- {
- // Write color
- #if (SW_COLOR_BUFFER_BITS == 8)
- *cptr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 16)
- *cptr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 24)
- *cptr++ = r24;
- *cptr++ = g24;
- *cptr++ = b24;
+ #else // RGBA
+ for (int i = 0; i < size; i++) dst32[i] = *(uint32_t*)pixels[i].color;
#endif
-
- // Write depth
- #if (SW_DEPTH_BUFFER_BITS == 8)
- *dptr++ = d8;
- #elif (SW_DEPTH_BUFFER_BITS == 16)
- *dptr++ = d16;
- #elif (SW_DEPTH_BUFFER_BITS == 24)
- *dptr++ = dByte0;
- *dptr++ = dByte1;
- *dptr++ = dByte2;
- #endif
- }
+#endif
}
-#define DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(name, DST_PTR_T) \
-static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \
+#define DEFINE_FRAMEBUFFER_COPY_BEGIN(name, DST_PTR_T) \
+static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \
{ \
- const void *src = RLSW.framebuffer.color; \
+ const int stride = RLSW.framebuffer.width; \
+ const sw_pixel_t *src = RLSW.framebuffer.pixels + (y*stride + x); \
\
- for (int iy = y; iy < h; iy++) { \
- for (int ix = x; ix < w; ix++) { \
+ for (int iy = 0; iy < h; iy++) { \
+ const sw_pixel_t *line = src; \
+ for (int ix = 0; ix < w; ix++) { \
uint8_t color[4]; \
- sw_framebuffer_read_color8(color, src); \
-
-#define DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(name, DST_PTR_T) \
-static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \
-{ \
- const void *src = RLSW.framebuffer.color; \
- \
- for (int iy = y; iy < h; iy++) { \
- for (int ix = x; ix < w; ix++) { \
- float color[4]; \
- sw_framebuffer_read_color(color, src); \
+ sw_framebuffer_read_color8(color, line); \
#define DEFINE_FRAMEBUFFER_COPY_END() \
- sw_framebuffer_inc_const_color_addr(&src); \
+ ++line; \
} \
+ src += stride; \
} \
}
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYSCALE, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYSCALE, uint8_t)
{
// NTSC grayscale conversion: Y = 0.299R + 0.587G + 0.114B
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
@@ -1517,7 +1480,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYSCALE, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYALPHA, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYALPHA, uint8_t)
{
// Convert RGB to grayscale using NTSC formula
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
@@ -1529,7 +1492,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYALPHA, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G6B5, uint16_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G6B5, uint16_t)
{
// Convert 8-bit RGB to 5:6:5 format
uint8_t r5 = (color[0]*31 + 127)/255;
@@ -1546,7 +1509,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G6B5, uint16_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1562,12 +1525,12 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G5B5A1, uint16_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G5B5A1, uint16_t)
{
uint8_t r5 = (color[0]*31 + 127)/255;
uint8_t g5 = (color[1]*31 + 127)/255;
uint8_t b5 = (color[2]*31 + 127)/255;
- uint8_t a1 = color[3] >= 128 ? 1 : 0;
+ uint8_t a1 = (color[3] >= 128)? 1 : 0;
#if SW_GL_FRAMEBUFFER_COPY_BGRA
uint16_t pixel = (b5 << 11) | (g5 << 6) | (r5 << 1) | a1;
@@ -1579,7 +1542,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G5B5A1, uint16_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R4G4B4A4, uint16_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R4G4B4A4, uint16_t)
{
uint8_t r4 = (color[0]*15 + 127)/255;
uint8_t g4 = (color[1]*15 + 127)/255;
@@ -1596,7 +1559,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R4G4B4A4, uint16_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8A8, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8A8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1613,145 +1576,44 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8A8, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32, float)
-{
- dst[0] = color[0];
- dst++;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32G32B32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32G32B32A32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
- dst[3] = color[3];
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16, sw_half_t)
-{
- dst[0] = sw_f16_from_f32(color[0]);
- dst++;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16G16B16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16G16B16A16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
- dst[3] = sw_f16_from_f32(color[3]);
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-#define DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(name, DST_PTR_T) \
+#define DEFINE_FRAMEBUFFER_BLIT_BEGIN(name, DST_PTR_T) \
static inline void sw_framebuffer_blit_to_##name( \
int xDst, int yDst, int wDst, int hDst, \
int xSrc, int ySrc, int wSrc, int hSrc, \
DST_PTR_T *dst) \
{ \
- const uint8_t *srcBase = RLSW.framebuffer.color; \
- int fbWidth = RLSW.framebuffer.width; \
+ const sw_pixel_t *srcBase = RLSW.framebuffer.pixels; \
+ const int fbWidth = RLSW.framebuffer.width; \
\
- uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \
- uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \
+ const uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \
+ const uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \
\
for (int dy = 0; dy < hDst; dy++) { \
- uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \
+ uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \
int sy = yFix >> 16; \
+ const sw_pixel_t *srcLine = srcBase + sy*fbWidth + xSrc; \
\
+ const sw_pixel_t *srcPtr = srcLine; \
for (int dx = 0; dx < wDst; dx++) { \
- uint32_t xFix = dx*xScale; \
+ uint32_t xFix = dx*xScale; \
int sx = xFix >> 16; \
- const void *srcPtr = sw_framebuffer_get_color_addr(srcBase, sy*fbWidth + sx); \
+ const sw_pixel_t *pixel = srcPtr + sx; \
uint8_t color[4]; \
- sw_framebuffer_read_color8(color, srcPtr); \
-
-#define DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(name, DST_PTR_T) \
-static inline void sw_framebuffer_blit_to_##name( \
- int xDst, int yDst, int wDst, int hDst, \
- int xSrc, int ySrc, int wSrc, int hSrc, \
- DST_PTR_T *dst) \
-{ \
- const uint8_t *srcBase = RLSW.framebuffer.color; \
- int fbWidth = RLSW.framebuffer.width; \
- \
- uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \
- uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \
- \
- for (int dy = 0; dy < hDst; dy++) { \
- uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \
- int sy = yFix >> 16; \
- \
- for (int dx = 0; dx < wDst; dx++) { \
- uint32_t xFix = dx*xScale; \
- int sx = xFix >> 16; \
- const void *srcPtr = sw_framebuffer_get_color_addr(srcBase, sy*fbWidth + sx); \
- float color[4]; \
- sw_framebuffer_read_color(color, srcPtr); \
+ sw_framebuffer_read_color8(color, pixel);
#define DEFINE_FRAMEBUFFER_BLIT_END() \
} \
} \
}
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYSCALE, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYSCALE, uint8_t)
{
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
*dst++ = gray;
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYALPHA, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYALPHA, uint8_t)
{
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
@@ -1762,7 +1624,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYALPHA, uint8_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G6B5, uint16_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G6B5, uint16_t)
{
uint8_t r5 = (color[0]*31 + 127)/255;
uint8_t g6 = (color[1]*63 + 127)/255;
@@ -1778,7 +1640,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G6B5, uint16_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1794,12 +1656,12 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8, uint8_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G5B5A1, uint16_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G5B5A1, uint16_t)
{
uint8_t r5 = (color[0]*31 + 127)/255;
uint8_t g5 = (color[1]*31 + 127)/255;
uint8_t b5 = (color[2]*31 + 127)/255;
- uint8_t a1 = color[3] >= 128 ? 1 : 0;
+ uint8_t a1 = (color[3] >= 128)? 1 : 0;
#if SW_GL_FRAMEBUFFER_COPY_BGRA
uint16_t pixel = (b5 << 11) | (g5 << 6) | (r5 << 1) | a1;
@@ -1811,7 +1673,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G5B5A1, uint16_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R4G4B4A4, uint16_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R4G4B4A4, uint16_t)
{
uint8_t r4 = (color[0]*15 + 127)/255;
uint8_t g4 = (color[1]*15 + 127)/255;
@@ -1828,7 +1690,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R4G4B4A4, uint16_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8A8, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8A8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1844,89 +1706,10 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8A8, uint8_t)
dst += 4;
}
DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32, uint8_t)
-{
- dst[0] = color[0];
- dst++;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32G32B32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32G32B32A32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
- dst[3] = color[3];
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16, sw_half_t)
-{
- dst[0] = sw_f16_from_f32(color[0]);
- dst++;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16A16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
- dst[3] = sw_f16_from_f32(color[3]);
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
+//-------------------------------------------------------------------------------------------
// Pixel format management functions
-
+//-------------------------------------------------------------------------------------------
static inline int sw_get_pixel_format(SWformat format, SWtype type)
{
int channels = 0;
@@ -1979,210 +1762,179 @@ static inline int sw_get_pixel_format(SWformat format, SWtype type)
return SW_PIXELFORMAT_UNKNOWN;
}
-int sw_get_pixel_bytes(sw_pixelformat_t format)
+static inline void sw_get_pixel(uint8_t *color, const void *pixels, uint32_t offset, sw_pixelformat_t format)
{
- int bpp = 0;
-
switch (format)
{
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 1; break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
+ {
+ uint8_t gray = ((const uint8_t*)pixels)[offset];
+ color[0] = gray;
+ color[1] = gray;
+ color[2] = gray;
+ color[3] = 255;
+ break;
+ }
case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+ {
+ const uint8_t *src = &((const uint8_t*)pixels)[offset*2];
+ color[0] = src[0];
+ color[1] = src[0];
+ color[2] = src[0];
+ color[3] = src[1];
+ break;
+ }
case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+ {
+ uint16_t pixel = ((const uint16_t*)pixels)[offset];
+ color[0] = ((pixel >> 11) & 0x1F)*255/31; // R (5 bits)
+ color[1] = ((pixel >> 5) & 0x3F)*255/63; // G (6 bits)
+ color[2] = (pixel & 0x1F)*255/31; // B (5 bits)
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8:
+ {
+ const uint8_t *src = &((const uint8_t*)pixels)[offset*3];
+ color[0] = src[0];
+ color[1] = src[1];
+ color[2] = src[2];
+ color[3] = 255;
+ break;
+ }
case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 2; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 4; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 3; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 4; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 4*3; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 4*4; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: bpp = 2; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 2*3; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 2*4; break;
- default: break;
- }
-
- return bpp;
-}
-
-static inline void sw_get_pixel_grayscale(float *color, const void *pixels, uint32_t offset)
-{
- float gray = (float)((uint8_t *)pixels)[offset]*(1.0f/255);
-
- color[0] = gray;
- color[1] = gray;
- color[2] = gray;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_red_16(float *color, const void *pixels, uint32_t offset)
-{
- float value = sw_f16_to_f32(((sw_half_t *)pixels)[offset]);
-
- color[0] = value;
- color[1] = value;
- color[2] = value;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_red_32(float *color, const void *pixels, uint32_t offset)
-{
- float value = ((float *)pixels)[offset];
-
- color[0] = value;
- color[1] = value;
- color[2] = value;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_grayscale_alpha(float *color, const void *pixels, uint32_t offset)
-{
- const uint8_t *pixelData = (const uint8_t *)pixels + 2*offset;
-
- color[0] = color[1] = color[2] = (float)pixelData[0]*(1.0f/255);
- color[3] = (float)pixelData[1]*(1.0f/255);
-}
-
-static inline void sw_get_pixel_rgb_565(float *color, const void *pixels, uint32_t offset)
-{
- uint16_t pixel = ((uint16_t *)pixels)[offset];
-
- color[0] = (float)((pixel & 0xF800) >> 11)/31;
- color[1] = (float)((pixel & 0x7E0) >> 5)/63;
- color[2] = (float)(pixel & 0x1F)/31;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgb_888(float *color, const void *pixels, uint32_t offset)
-{
- const uint8_t *pixel = (const uint8_t *)pixels + 3*offset;
-
- color[0] = (float)pixel[0]*(1.0f/255);
- color[1] = (float)pixel[1]*(1.0f/255);
- color[2] = (float)pixel[2]*(1.0f/255);
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgb_161616(float *color, const void *pixels, uint32_t offset)
-{
- const sw_half_t *pixel = (sw_half_t *)pixels + 3*offset;
-
- color[0] = sw_f16_to_f32(pixel[0]);
- color[1] = sw_f16_to_f32(pixel[1]);
- color[2] = sw_f16_to_f32(pixel[2]);
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgb_323232(float *color, const void *pixels, uint32_t offset)
-{
- const float *pixel = (float *)pixels + 3*offset;
-
- color[0] = pixel[0];
- color[1] = pixel[1];
- color[2] = pixel[2];
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgba_5551(float *color, const void *pixels, uint32_t offset)
-{
- uint16_t pixel = ((uint16_t *)pixels)[offset];
-
- color[0] = (float)((pixel & 0xF800) >> 11)/31;
- color[1] = (float)((pixel & 0x7C0) >> 6)/31;
- color[2] = (float)((pixel & 0x3E) >> 1)/31;
- color[3] = (float)(pixel & 0x1);
-}
-
-static inline void sw_get_pixel_rgba_4444(float *color, const void *pixels, uint32_t offset)
-{
- uint16_t pixel = ((uint16_t *)pixels)[offset];
-
- color[0] = (float)((pixel & 0xF000) >> 12)/15;
- color[1] = (float)((pixel & 0xF00) >> 8)/15;
- color[2] = (float)((pixel & 0xF0) >> 4)/15;
- color[3] = (float)(pixel & 0xF)/15;
-}
-
-static inline void sw_get_pixel_rgba_8888(float *color, const void *pixels, uint32_t offset)
-{
- const uint8_t *pixel = (uint8_t *)pixels + 4*offset;
-
- color[0] = (float)pixel[0]*(1.0f/255);
- color[1] = (float)pixel[1]*(1.0f/255);
- color[2] = (float)pixel[2]*(1.0f/255);
- color[3] = (float)pixel[3]*(1.0f/255);
-}
-
-static inline void sw_get_pixel_rgba_16161616(float *color, const void *pixels, uint32_t offset)
-{
- const sw_half_t *pixel = (sw_half_t *)pixels + 4*offset;
-
- color[0] = sw_f16_to_f32(pixel[0]);
- color[1] = sw_f16_to_f32(pixel[1]);
- color[2] = sw_f16_to_f32(pixel[2]);
- color[3] = sw_f16_to_f32(pixel[3]);
-}
-
-static inline void sw_get_pixel_rgba_32323232(float *color, const void *pixels, uint32_t offset)
-{
- const float *pixel = (float *)pixels + 4*offset;
-
- color[0] = pixel[0];
- color[1] = pixel[1];
- color[2] = pixel[2];
- color[3] = pixel[3];
-}
-
-static inline void sw_get_pixel(float *color, const void *pixels, uint32_t offset, sw_pixelformat_t format)
-{
- switch (format)
- {
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_get_pixel_grayscale(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_get_pixel_grayscale_alpha(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_get_pixel_rgb_565(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_get_pixel_rgb_888(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_get_pixel_rgba_5551(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_get_pixel_rgba_4444(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_get_pixel_rgba_8888(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_get_pixel_red_32(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_get_pixel_rgb_323232(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_get_pixel_rgba_32323232(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_get_pixel_red_16(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_get_pixel_rgb_161616(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_get_pixel_rgba_16161616(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNKNOWN: break;
- default: break;
+ {
+ uint16_t pixel = ((const uint16_t*)pixels)[offset];
+ color[0] = ((pixel >> 11) & 0x1F)*255/31; // R (5 bits)
+ color[1] = ((pixel >> 6) & 0x1F)*255/31; // G (5 bits)
+ color[2] = ((pixel >> 1) & 0x1F)*255/31; // B (5 bits)
+ color[3] = (pixel & 0x01)*255; // A (1 bit)
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+ {
+ uint16_t pixel = ((const uint16_t*)pixels)[offset];
+ color[0] = ((pixel >> 12) & 0x0F)*255/15; // R (4 bits)
+ color[1] = ((pixel >> 8) & 0x0F)*255/15; // G (4 bits)
+ color[2] = ((pixel >> 4) & 0x0F)*255/15; // B (4 bits)
+ color[3] = (pixel & 0x0F)*255/15; // A (4 bits)
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+ {
+ const uint8_t *src = &((const uint8_t*)pixels)[offset*4];
+ color[0] = src[0];
+ color[1] = src[1];
+ color[2] = src[2];
+ color[3] = src[3];
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32:
+ {
+ float val = ((const float*)pixels)[offset];
+ uint8_t gray = (uint8_t)(val*255.0f);
+ color[0] = gray;
+ color[1] = gray;
+ color[2] = gray;
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+ {
+ const float *src = &((const float*)pixels)[offset*3];
+ color[0] = (uint8_t)(src[0]*255.0f);
+ color[1] = (uint8_t)(src[1]*255.0f);
+ color[2] = (uint8_t)(src[2]*255.0f);
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+ {
+ const float *src = &((const float*)pixels)[offset*4];
+ color[0] = (uint8_t)(src[0]*255.0f);
+ color[1] = (uint8_t)(src[1]*255.0f);
+ color[2] = (uint8_t)(src[2]*255.0f);
+ color[3] = (uint8_t)(src[3]*255.0f);
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16:
+ {
+ uint16_t val = ((const uint16_t*)pixels)[offset];
+ uint8_t gray = sw_half_to_float(val)*SW_INV_255;
+ color[0] = gray;
+ color[1] = gray;
+ color[2] = gray;
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+ {
+ const uint16_t *src = &((const uint16_t*)pixels)[offset*3];
+ color[0] = sw_half_to_float(src[0])*SW_INV_255;
+ color[1] = sw_half_to_float(src[1])*SW_INV_255;
+ color[2] = sw_half_to_float(src[2])*SW_INV_255;
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+ {
+ const uint16_t *src = &((const uint16_t*)pixels)[offset*4];
+ color[0] = sw_half_to_float(src[0])*SW_INV_255;
+ color[1] = sw_half_to_float(src[1])*SW_INV_255;
+ color[2] = sw_half_to_float(src[2])*SW_INV_255;
+ color[3] = sw_half_to_float(src[3])*SW_INV_255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNKNOWN:
+ default:
+ {
+ color[0] = 0;
+ color[1] = 0;
+ color[2] = 0;
+ color[3] = 0;
+ break;
+ }
}
}
+//-------------------------------------------------------------------------------------------
// Texture sampling functionality
+//-------------------------------------------------------------------------------------------
+static inline void sw_texture_fetch(float* color, const sw_texture_t* tex, int x, int y)
+{
+ sw_float_from_unorm8_simd(color, &tex->pixels[4*(y*tex->width + x)]);
+}
static inline void sw_texture_sample_nearest(float *color, const sw_texture_t *tex, float u, float v)
{
u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u);
v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v);
- int x = u*tex->width, y = v*tex->height;
+ int x = u*tex->width;
+ int y = v*tex->height;
- sw_get_pixel(color, tex->pixels.cptr, y*tex->width + x, tex->format);
+ sw_texture_fetch(color, tex, x, y);
}
static inline void sw_texture_sample_linear(float *color, const sw_texture_t *tex, float u, float v)
{
- // TODO: REVIEW: With a bit more cleverness we could clearly reduce the
- // number of operations here, but for now it works fine.
+ // TODO: With a bit more cleverness we could clearly reduce the
+ // number of operations here, but for now it works fine
- float xf = u*tex->width - 0.5f;
- float yf = v*tex->height - 0.5f;
+ float xf = (u*tex->width) - 0.5f;
+ float yf = (v*tex->height) - 0.5f;
- int x0 = (int)floorf(xf);
- int y0 = (int)floorf(yf);
+ float fx = sw_fract(xf);
+ float fy = sw_fract(yf);
- float fx = xf - x0;
- float fy = yf - y0;
+ int x0 = (int)xf;
+ int y0 = (int)yf;
int x1 = x0 + 1;
int y1 = y0 + 1;
+ // NOTE: If the textures are POT we could avoid the division for SW_REPEAT
+
if (tex->sWrap == SW_CLAMP)
{
x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0;
@@ -2206,10 +1958,10 @@ static inline void sw_texture_sample_linear(float *color, const sw_texture_t *te
}
float c00[4], c10[4], c01[4], c11[4];
- sw_get_pixel(c00, tex->pixels.cptr, y0*tex->width + x0, tex->format);
- sw_get_pixel(c10, tex->pixels.cptr, y0*tex->width + x1, tex->format);
- sw_get_pixel(c01, tex->pixels.cptr, y1*tex->width + x0, tex->format);
- sw_get_pixel(c11, tex->pixels.cptr, y1*tex->width + x1, tex->format);
+ sw_texture_fetch(c00, tex, x0, y0);
+ sw_texture_fetch(c10, tex, x1, y0);
+ sw_texture_fetch(c01, tex, x0, y1);
+ sw_texture_fetch(c11, tex, x1, y1);
for (int i = 0; i < 4; i++)
{
@@ -2219,18 +1971,18 @@ static inline void sw_texture_sample_linear(float *color, const sw_texture_t *te
}
}
-static inline void sw_texture_sample(float *color, const sw_texture_t *tex, float u, float v, float duDx, float duDy, float dvDx, float dvDy)
+static inline void sw_texture_sample(float *color, const sw_texture_t *tex, float u, float v, float dUdx, float dUdy, float dVdx, float dVdy)
{
// Previous method: There is no need to compute the square root
// because using the squared value, the comparison remains `L2 > 1.0f*1.0f`
- //float du = sqrtf(duDx*duDx + duDy*duDy);
- //float dv = sqrtf(dvDx*dvDx + dvDy*dvDy);
+ //float du = sqrtf(dUdx*dUdx + dUdy*dUdy);
+ //float dv = sqrtf(dVdx*dVdx + dVdy*dVdy);
//float L = (du > dv)? du : dv;
// Calculate the derivatives for each axis
- float du2 = duDx*duDx + duDy*duDy;
- float dv2 = dvDx*dvDx + dvDy*dvDy;
- float L2 = (du2 > dv2)? du2 : dv2;
+ float dU2 = dUdx*dUdx + dUdy*dUdy;
+ float dV2 = dVdx*dVdx + dVdy*dVdy;
+ float L2 = (dU2 > dV2)? dU2 : dV2;
SWfilter filter = (L2 > 1.0f)? tex->minFilter : tex->magFilter;
@@ -2241,9 +1993,10 @@ static inline void sw_texture_sample(float *color, const sw_texture_t *tex, floa
default: break;
}
}
+//-------------------------------------------------------------------------------------------
-// Color Blending functionality
-
+// Color blending functionality
+//-------------------------------------------------------------------------------------------
static inline void sw_factor_zero(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
{
factor[0] = factor[1] = factor[2] = factor[3] = 0.0f;
@@ -2316,17 +2069,19 @@ static inline void sw_blend_colors(float *SW_RESTRICT dst/*[4]*/, const float *S
dst[2] = srcFactor[2]*src[2] + dstFactor[2]*dst[2];
dst[3] = srcFactor[3]*src[3] + dstFactor[3]*dst[3];
}
+//-------------------------------------------------------------------------------------------
// Projection helper functions
-
+//-------------------------------------------------------------------------------------------
static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4])
{
- screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalfSize[0];
- screen[1] = RLSW.vpCenter[1] - ndc[1]*RLSW.vpHalfSize[1];
+ screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalf[0] + 0.5f;
+ screen[1] = RLSW.vpCenter[1] - ndc[1]*RLSW.vpHalf[1] + 0.5f;
}
+//-------------------------------------------------------------------------------------------
-// Polygon Clipping management
-
+// Polygon clipping management
+//-------------------------------------------------------------------------------------------
#define DEFINE_CLIP_FUNC(name, FUNC_IS_INSIDE, FUNC_COMPUTE_T) \
static inline int sw_clip_##name( \
sw_vertex_t output[SW_MAX_CLIPPED_POLYGON_VERTICES], \
@@ -2358,16 +2113,17 @@ static inline int sw_clip_##name(
\
return outputCount; \
}
+//-------------------------------------------------------------------------------------------
// Frustum cliping functions
-
+//-------------------------------------------------------------------------------------------
#define IS_INSIDE_PLANE_W(h) ((h)[3] >= SW_CLIP_EPSILON)
-#define IS_INSIDE_PLANE_X_POS(h) ((h)[0] <= (h)[3])
-#define IS_INSIDE_PLANE_X_NEG(h) (-(h)[0] <= (h)[3])
-#define IS_INSIDE_PLANE_Y_POS(h) ((h)[1] <= (h)[3])
-#define IS_INSIDE_PLANE_Y_NEG(h) (-(h)[1] <= (h)[3])
-#define IS_INSIDE_PLANE_Z_POS(h) ((h)[2] <= (h)[3])
-#define IS_INSIDE_PLANE_Z_NEG(h) (-(h)[2] <= (h)[3])
+#define IS_INSIDE_PLANE_X_POS(h) ( (h)[0] < (h)[3]) // Exclusive for +X
+#define IS_INSIDE_PLANE_X_NEG(h) (-(h)[0] < (h)[3]) // Exclusive for -X
+#define IS_INSIDE_PLANE_Y_POS(h) ( (h)[1] < (h)[3]) // Exclusive for +Y
+#define IS_INSIDE_PLANE_Y_NEG(h) (-(h)[1] < (h)[3]) // Exclusive for -Y
+#define IS_INSIDE_PLANE_Z_POS(h) ( (h)[2] <= (h)[3]) // Inclusive for +Z
+#define IS_INSIDE_PLANE_Z_NEG(h) (-(h)[2] <= (h)[3]) // Inclusive for -Z
#define COMPUTE_T_PLANE_W(hPrev, hCurr) ((SW_CLIP_EPSILON - (hPrev)[3])/((hCurr)[3] - (hPrev)[3]))
#define COMPUTE_T_PLANE_X_POS(hPrev, hCurr) (((hPrev)[3] - (hPrev)[0])/(((hPrev)[3] - (hPrev)[0]) - ((hCurr)[3] - (hCurr)[0])))
@@ -2384,9 +2140,10 @@ DEFINE_CLIP_FUNC(y_pos, IS_INSIDE_PLANE_Y_POS, COMPUTE_T_PLANE_Y_POS)
DEFINE_CLIP_FUNC(y_neg, IS_INSIDE_PLANE_Y_NEG, COMPUTE_T_PLANE_Y_NEG)
DEFINE_CLIP_FUNC(z_pos, IS_INSIDE_PLANE_Z_POS, COMPUTE_T_PLANE_Z_POS)
DEFINE_CLIP_FUNC(z_neg, IS_INSIDE_PLANE_Z_NEG, COMPUTE_T_PLANE_Z_NEG)
+//-------------------------------------------------------------------------------------------
// Scissor clip functions
-
+//-------------------------------------------------------------------------------------------
#define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMin[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0])*(hPrev)[3])))
#define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMax[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0])*(hPrev)[3])))
#define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMin[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1])*(hPrev)[3])))
@@ -2401,9 +2158,9 @@ DEFINE_CLIP_FUNC(scissor_x_min, IS_INSIDE_SCISSOR_X_MIN, COMPUTE_T_SCISSOR_X_MIN
DEFINE_CLIP_FUNC(scissor_x_max, IS_INSIDE_SCISSOR_X_MAX, COMPUTE_T_SCISSOR_X_MAX)
DEFINE_CLIP_FUNC(scissor_y_min, IS_INSIDE_SCISSOR_Y_MIN, COMPUTE_T_SCISSOR_Y_MIN)
DEFINE_CLIP_FUNC(scissor_y_max, IS_INSIDE_SCISSOR_Y_MAX, COMPUTE_T_SCISSOR_Y_MAX)
+//-------------------------------------------------------------------------------------------
-// Main clip function
-
+// Main polygon clip function
static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int *vertexCounter)
{
static sw_vertex_t tmp[SW_MAX_CLIPPED_POLYGON_VERTICES];
@@ -2443,16 +2200,16 @@ static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VE
}
// Triangle rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_triangle_face_culling(void)
{
- // NOTE: Face culling is done before clipping to avoid unnecessary computations.
+ // NOTE: Face culling is done before clipping to avoid unnecessary computations
// To handle triangles crossing the w=0 plane correctly,
// we perform the winding order test in homogeneous coordinates directly,
- // before the perspective division (division by w).
+ // before the perspective division (division by w)
// This test determines the orientation of the triangle in the (x,y,w) plane,
// which corresponds to the projected 2D winding order sign,
- // even with negative w values.
+ // even with negative w values
// Preload homogeneous coordinates into local variables
const float *h0 = RLSW.vertexBuffer[0].homogeneous;
@@ -2464,7 +2221,7 @@ static inline bool sw_triangle_face_culling(void)
// This is the determinant of the matrix formed by the (x, y, w) components
// of the vertices, which correctly captures the winding order in homogeneous
// space and its relationship to the projected 2D winding order, even with
- // negative w values.
+ // negative w values
// The determinant formula used here is:
// h0.x*(h1.y*h2.w - h2.y*h1.w) +
// h1.x*(h2.y*h0.w - h0.y*h2.w) +
@@ -2476,20 +2233,18 @@ static inline bool sw_triangle_face_culling(void)
h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]);
// Discard the triangle if its winding order (determined by the sign
- // of the homogeneous area/determinant) matches the culled direction.
+ // of the homogeneous area/determinant) matches the culled direction
// A positive hSgnArea typically corresponds to a counter-clockwise
// winding in the projected space when all w > 0.
// This test is robust for points with w > 0 or w < 0, correctly
- // capturing the change in orientation when crossing the w=0 plane.
+ // capturing the change in orientation when crossing the w=0 plane
- // The culling logic remains the same based on the signed area/determinant.
+ // The culling logic remains the same based on the signed area/determinant
// A value of 0 for hSgnArea means the points are collinear in (x, y, w)
// space, which corresponds to a degenerate triangle projection.
// Such triangles are typically not culled by this test (0 < 0 is false, 0 > 0 is false)
- // and should be handled by the clipper if necessary.
- return (RLSW.cullFace == SW_FRONT)
- ? (hSgnArea < 0) // Cull if winding is "clockwise" in the projected sense
- : (hSgnArea > 0); // Cull if winding is "counter-clockwise" in the projected sense
+ // and should be handled by the clipper if necessary
+ return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0) : (hSgnArea > 0); // Cull if winding is "clockwise" : "counter-clockwise"
}
static inline void sw_triangle_clip_and_project(void)
@@ -2506,23 +2261,23 @@ static inline void sw_triangle_clip_and_project(void)
// Calculation of the reciprocal of W for normalization
// as well as perspective-correct attributes
- const float invW = 1.0f/v->homogeneous[3];
- v->homogeneous[3] = invW;
+ const float wRcp = 1.0f/v->homogeneous[3];
+ v->homogeneous[3] = wRcp;
// Division of XYZ coordinates by weight
- v->homogeneous[0] *= invW;
- v->homogeneous[1] *= invW;
- v->homogeneous[2] *= invW;
+ v->homogeneous[0] *= wRcp;
+ v->homogeneous[1] *= wRcp;
+ v->homogeneous[2] *= wRcp;
// Division of texture coordinates (perspective-correct)
- v->texcoord[0] *= invW;
- v->texcoord[1] *= invW;
+ v->texcoord[0] *= wRcp;
+ v->texcoord[1] *= wRcp;
// Division of colors (perspective-correct)
- v->color[0] *= invW;
- v->color[1] *= invW;
- v->color[2] *= invW;
- v->color[3] *= invW;
+ v->color[0] *= wRcp;
+ v->color[1] *= wRcp;
+ v->color[2] *= wRcp;
+ v->color[3] *= wRcp;
// Transformation to screen space
sw_project_ndc_to_screen(v->screen, v->homogeneous);
@@ -2532,68 +2287,64 @@ static inline void sw_triangle_clip_and_project(void)
#define DEFINE_TRIANGLE_RASTER_SCANLINE(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \
static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start, \
- const sw_vertex_t *end, float duDy, float dvDy) \
+ const sw_vertex_t *end, float dUdy, float dVdy) \
{ \
- /* Convert and center the screen coordinates */ \
- int xStart = (int)(start->screen[0] + 0.5f); \
- int xEnd = (int)(end->screen[0] + 0.5f); \
- int y = (int)start->screen[1]; \
+ /* Gets the start and end coordinates */ \
+ int xStart = (int)start->screen[0]; \
+ int xEnd = (int)end->screen[0]; \
+ \
+ /* Avoid empty lines */ \
+ if (xStart == xEnd) return; \
+ \
+ /* Compute the subpixel distance to traverse before the first pixel */ \
+ float xSubstep = 1.0f - sw_fract(start->screen[0]); \
\
/* Compute the inverse horizontal distance along the X axis */ \
- float dx = end->screen[0] - start->screen[0]; \
- if (fabsf(dx) < 1e-6f) return; \
- float dxRcp = 1.0f/dx; \
+ float dxRcp = 1.0f/(end->screen[0] - start->screen[0]); \
\
/* Compute the interpolation steps along the X axis */ \
- float dzDx = (end->homogeneous[2] - start->homogeneous[2])*dxRcp; \
- float dwDx = (end->homogeneous[3] - start->homogeneous[3])*dxRcp; \
+ float dZdx = (end->homogeneous[2] - start->homogeneous[2])*dxRcp; \
+ float dWdx = (end->homogeneous[3] - start->homogeneous[3])*dxRcp; \
\
- float dcDx[4] = { 0 }; \
- dcDx[0] = (end->color[0] - start->color[0])*dxRcp; \
- dcDx[1] = (end->color[1] - start->color[1])*dxRcp; \
- dcDx[2] = (end->color[2] - start->color[2])*dxRcp; \
- dcDx[3] = (end->color[3] - start->color[3])*dxRcp; \
+ float dCdx[4] = { \
+ (end->color[0] - start->color[0])*dxRcp, \
+ (end->color[1] - start->color[1])*dxRcp, \
+ (end->color[2] - start->color[2])*dxRcp, \
+ (end->color[3] - start->color[3])*dxRcp \
+ }; \
\
- float duDx = 0.0f, dvDx = 0.0f; \
+ float dUdx = 0.0f; \
+ float dVdx = 0.0f; \
if (ENABLE_TEXTURE) { \
- duDx = (end->texcoord[0] - start->texcoord[0])*dxRcp; \
- dvDx = (end->texcoord[1] - start->texcoord[1])*dxRcp; \
+ dUdx = (end->texcoord[0] - start->texcoord[0])*dxRcp; \
+ dVdx = (end->texcoord[1] - start->texcoord[1])*dxRcp; \
} \
\
/* Initializing the interpolation starting values */ \
- float z = start->homogeneous[2]; \
- float w = start->homogeneous[3]; \
+ float z = start->homogeneous[2] + dZdx*xSubstep; \
+ float w = start->homogeneous[3] + dWdx*xSubstep; \
\
- float color[4] = { 0 }; \
- color[0] = start->color[0]; \
- color[1] = start->color[1]; \
- color[2] = start->color[2]; \
- color[3] = start->color[3]; \
+ float color[4] = { \
+ start->color[0] + dCdx[0]*xSubstep, \
+ start->color[1] + dCdx[1]*xSubstep, \
+ start->color[2] + dCdx[2]*xSubstep, \
+ start->color[3] + dCdx[3]*xSubstep \
+ }; \
\
- float u = 0.0f, v = 0.0f; \
+ float u = 0.0f; \
+ float v = 0.0f; \
if (ENABLE_TEXTURE) { \
- u = start->texcoord[0]; \
- v = start->texcoord[1]; \
+ u = start->texcoord[0] + dUdx*xSubstep; \
+ v = start->texcoord[1] + dVdx*xSubstep; \
} \
\
/* Pre-calculate the starting pointers for the framebuffer row */ \
- void *cptr = sw_framebuffer_get_color_addr(RLSW.framebuffer.color, y*RLSW.framebuffer.width + xStart); \
- void *dptr = sw_framebuffer_get_depth_addr(RLSW.framebuffer.depth, y*RLSW.framebuffer.width + xStart); \
+ int y = (int)start->screen[1]; \
+ sw_pixel_t *ptr = RLSW.framebuffer.pixels + y*RLSW.framebuffer.width + xStart; \
\
/* Scanline rasterization */ \
for (int x = xStart; x < xEnd; x++) \
{ \
- /* Test and write depth */ \
- if (ENABLE_DEPTH_TEST) \
- { \
- /* TODO: Implement different depth funcs? */ \
- float depth = sw_framebuffer_read_depth(dptr); \
- if (z > depth) goto discard; \
- } \
- \
- sw_framebuffer_write_depth(dptr, z); \
- \
- /* Pixel color computation */ \
float wRcp = 1.0f/w; \
float srcColor[4] = { \
color[0]*wRcp, \
@@ -2602,12 +2353,22 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start,
color[3]*wRcp \
}; \
\
+ if (ENABLE_DEPTH_TEST) \
+ { \
+ /* TODO: Implement different depth funcs? */ \
+ float depth = sw_framebuffer_read_depth(ptr); \
+ if (z > depth) goto discard; \
+ } \
+ \
+ /* TODO: Implement depth mask */ \
+ sw_framebuffer_write_depth(ptr, z); \
+ \
if (ENABLE_TEXTURE) \
{ \
float texColor[4]; \
float s = u*wRcp; \
float t = v*wRcp; \
- sw_texture_sample(texColor, tex, s, t, duDx, duDy, dvDx, dvDy); \
+ sw_texture_sample(texColor, tex, s, t, dUdx, dUdy, dVdx, dVdy); \
srcColor[0] *= texColor[0]; \
srcColor[1] *= texColor[1]; \
srcColor[2] *= texColor[2]; \
@@ -2617,36 +2378,29 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start,
if (ENABLE_COLOR_BLEND) \
{ \
float dstColor[4]; \
- sw_framebuffer_read_color(dstColor, cptr); \
- \
+ sw_framebuffer_read_color(dstColor, ptr); \
sw_blend_colors(dstColor, srcColor); \
- dstColor[0] = sw_saturate(dstColor[0]); \
- dstColor[1] = sw_saturate(dstColor[1]); \
- dstColor[2] = sw_saturate(dstColor[2]); \
- \
- sw_framebuffer_write_color(cptr, dstColor); \
+ sw_framebuffer_write_color(ptr, dstColor); \
} \
else \
{ \
- sw_framebuffer_write_color(cptr, srcColor); \
+ sw_framebuffer_write_color(ptr, srcColor); \
} \
\
/* Increment the interpolation parameter, UVs, and pointers */ \
discard: \
- z += dzDx; \
- w += dwDx; \
- color[0] += dcDx[0]; \
- color[1] += dcDx[1]; \
- color[2] += dcDx[2]; \
- color[3] += dcDx[3]; \
+ z += dZdx; \
+ w += dWdx; \
+ color[0] += dCdx[0]; \
+ color[1] += dCdx[1]; \
+ color[2] += dCdx[2]; \
+ color[3] += dCdx[3]; \
if (ENABLE_TEXTURE) \
{ \
- u += duDx; \
- v += dvDx; \
+ u += dUdx; \
+ v += dVdx; \
} \
- \
- sw_framebuffer_inc_color_addr(&cptr); \
- sw_framebuffer_inc_depth_addr(&dptr); \
+ ++ptr; \
} \
}
@@ -2672,60 +2426,71 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1,
if (h02 < 1e-6f) return; \
\
/* Precompute the inverse values without additional checks */ \
- float invH02 = 1.0f/h02; \
- float invH01 = (h01 > 1e-6f)? 1.0f/h01 : 0.0f; \
- float invH12 = (h12 > 1e-6f)? 1.0f/h12 : 0.0f; \
+ float h02Rcp = 1.0f/h02; \
+ float h01Rcp = (h01 > 1e-6f)? 1.0f/h01 : 0.0f; \
+ float h12Rcp = (h12 > 1e-6f)? 1.0f/h12 : 0.0f; \
\
/* Pre-calculation of slopes */ \
- float dx02 = (x2 - x0)*invH02; \
- float dx01 = (x1 - x0)*invH01; \
- float dx12 = (x2 - x1)*invH12; \
+ float dXdy02 = (x2 - x0)*h02Rcp; \
+ float dXdy01 = (x1 - x0)*h01Rcp; \
+ float dXdy12 = (x2 - x1)*h12Rcp; \
+ \
+ /* Y subpixel correction */ \
+ float y0Substep = 1.0f - sw_fract(y0); \
+ float y1Substep = 1.0f - sw_fract(y1); \
\
/* Y bounds (vertical clipping) */ \
- int yTop = (int)(y0 + 0.5f); \
- int yMiddle = (int)(y1 + 0.5f); \
- int yBottom = (int)(y2 + 0.5f); \
+ int yTop = (int)y0; \
+ int yMid = (int)y1; \
+ int yBot = (int)y2; \
\
/* Compute gradients for each side of the triangle */ \
- sw_vertex_t vDy02, vDy01, vDy12; \
- sw_get_vertex_grad_PTCH(&vDy02, v0, v2, invH02); \
- sw_get_vertex_grad_PTCH(&vDy01, v0, v1, invH01); \
- sw_get_vertex_grad_PTCH(&vDy12, v1, v2, invH12); \
+ sw_vertex_t dVXdy02, dVXdy01, dVXdy12; \
+ sw_get_vertex_grad_PTCH(&dVXdy02, v0, v2, h02Rcp); \
+ sw_get_vertex_grad_PTCH(&dVXdy01, v0, v1, h01Rcp); \
+ sw_get_vertex_grad_PTCH(&dVXdy12, v1, v2, h12Rcp); \
\
- /* Initializing scanline variables */ \
- sw_vertex_t vLeft = *v0; \
- vLeft.screen[0] = x0; \
- sw_vertex_t vRight = *v0; \
- vRight.screen[0] = x0; \
+ /* Get a copy of vertices for interpolation and apply substep correction */ \
+ sw_vertex_t vLeft = *v0, vRight = *v0; \
+ sw_add_vertex_grad_scaled_PTCH(&vLeft, &dVXdy02, y0Substep); \
+ sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy01, y0Substep); \
+ \
+ vLeft.screen[0] += dXdy02*y0Substep; \
+ vRight.screen[0] += dXdy01*y0Substep; \
\
/* Scanline for the upper part of the triangle */ \
- for (int y = yTop; y < yMiddle; y++) \
+ for (int y = yTop; y < yMid; y++) \
{ \
vLeft.screen[1] = vRight.screen[1] = y; \
\
- if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, vDy02.texcoord[0], vDy02.texcoord[1]); \
- else FUNC_SCANLINE(tex, &vRight, &vLeft, vDy02.texcoord[0], vDy02.texcoord[1]); \
+ if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
+ else FUNC_SCANLINE(tex, &vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
\
- sw_add_vertex_grad_PTCH(&vLeft, &vDy02); \
- vLeft.screen[0] += dx02; \
- sw_add_vertex_grad_PTCH(&vRight, &vDy01); \
- vRight.screen[0] += dx01; \
+ sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); \
+ vLeft.screen[0] += dXdy02; \
+ \
+ sw_add_vertex_grad_PTCH(&vRight, &dVXdy01); \
+ vRight.screen[0] += dXdy01; \
} \
\
- /* Scanline for the lower part of the triangle */ \
- vRight = *v1, vRight.screen[0] = x1; \
+ /* Get a copy of next right for interpolation and apply substep correction */ \
+ vRight = *v1; \
+ sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy12, y1Substep); \
+ vRight.screen[0] += dXdy12*y1Substep; \
\
- for (int y = yMiddle; y < yBottom; y++) \
+ /* Scanline for the lower part of the triangle */ \
+ for (int y = yMid; y < yBot; y++) \
{ \
vLeft.screen[1] = vRight.screen[1] = y; \
\
- if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, vDy02.texcoord[0], vDy02.texcoord[1]); \
- else FUNC_SCANLINE(tex, &vRight, &vLeft, vDy02.texcoord[0], vDy02.texcoord[1]); \
+ if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
+ else FUNC_SCANLINE(tex, &vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
\
- sw_add_vertex_grad_PTCH(&vLeft, &vDy02); \
- vLeft.screen[0] += dx02; \
- sw_add_vertex_grad_PTCH(&vRight, &vDy12); \
- vRight.screen[0] += dx12; \
+ sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); \
+ vLeft.screen[0] += dXdy02; \
+ \
+ sw_add_vertex_grad_PTCH(&vRight, &dVXdy12); \
+ vRight.screen[0] += dXdy12; \
} \
}
@@ -2771,30 +2536,35 @@ static inline void sw_triangle_render(void)
} \
}
- if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
+ uint32_t state = RLSW.stateFlags;
+ if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D;
+ if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND;
+
+ if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
else TRIANGLE_RASTER(sw_triangle_raster)
#undef TRIANGLE_RASTER
}
+//-------------------------------------------------------------------------------------------
// Quad rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_quad_face_culling(void)
{
- // NOTE: Face culling is done before clipping to avoid unnecessary computations.
+ // NOTE: Face culling is done before clipping to avoid unnecessary computations
// To handle quads crossing the w=0 plane correctly,
// we perform the winding order test in homogeneous coordinates directly,
- // before the perspective division (division by w).
+ // before the perspective division (division by w)
// For a convex quad with vertices P0, P1, P2, P3 in sequential order,
// the winding order of the quad is the same as the winding order
// of the triangle P0 P1 P2. We use the homogeneous triangle
- // winding test on this first triangle.
+ // winding test on this first triangle
// Preload homogeneous coordinates into local variables
const float *h0 = RLSW.vertexBuffer[0].homogeneous;
@@ -2806,11 +2576,11 @@ static inline bool sw_quad_face_culling(void)
// Compute a value proportional to the signed area of the triangle P0 P1 P2
// in the projected 2D plane, calculated directly using homogeneous coordinates
- // BEFORE division by w.
+ // BEFORE division by w
// This is the determinant of the matrix formed by the (x, y, w) components
// of the vertices P0, P1, and P2. Its sign correctly indicates the winding order
// in homogeneous space and its relationship to the projected 2D winding order,
- // even with negative w values.
+ // even with negative w values
// The determinant formula used here is:
// h0.x*(h1.y*h2.w - h2.y*h1.w) +
// h1.x*(h2.y*h0.w - h0.y*h2.w) +
@@ -2822,21 +2592,19 @@ static inline bool sw_quad_face_culling(void)
h2[0]*(h0[1]*h1[3] - h1[1]*h0[3]);
// Perform face culling based on the winding order determined by the sign
- // of the homogeneous area/determinant of triangle P0 P1 P2.
+ // of the homogeneous area/determinant of triangle P0 P1 P2
// This test is robust for points with w > 0 or w < 0 within the triangle,
- // correctly capturing the change in orientation when crossing the w=0 plane.
+ // correctly capturing the change in orientation when crossing the w=0 plane
// A positive hSgnArea typically corresponds to a counter-clockwise
- // winding in the projected space when all w > 0.
+ // winding in the projected space when all w > 0
// A value of 0 for hSgnArea means P0, P1, P2 are collinear in (x, y, w)
- // space, which corresponds to a degenerate triangle projection.
+ // space, which corresponds to a degenerate triangle projection
// Such quads might also be degenerate or non-planar. They are typically
// not culled by this test (0 < 0 is false, 0 > 0 is false)
// and should be handled by the clipper if necessary.
- return (RLSW.cullFace == SW_FRONT)
- ? (hSgnArea < 0.0f) // Cull if winding is "clockwise" in the projected sense
- : (hSgnArea > 0.0f); // Cull if winding is "counter-clockwise" in the projected sense
+ return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0.0f) : (hSgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise"
}
static inline void sw_quad_clip_and_project(void)
@@ -2853,23 +2621,23 @@ static inline void sw_quad_clip_and_project(void)
// Calculation of the reciprocal of W for normalization
// as well as perspective-correct attributes
- const float invW = 1.0f/v->homogeneous[3];
- v->homogeneous[3] = invW;
+ const float wRcp = 1.0f/v->homogeneous[3];
+ v->homogeneous[3] = wRcp;
// Division of XYZ coordinates by weight
- v->homogeneous[0] *= invW;
- v->homogeneous[1] *= invW;
- v->homogeneous[2] *= invW;
+ v->homogeneous[0] *= wRcp;
+ v->homogeneous[1] *= wRcp;
+ v->homogeneous[2] *= wRcp;
// Division of texture coordinates (perspective-correct)
- v->texcoord[0] *= invW;
- v->texcoord[1] *= invW;
+ v->texcoord[0] *= wRcp;
+ v->texcoord[1] *= wRcp;
// Division of colors (perspective-correct)
- v->color[0] *= invW;
- v->color[1] *= invW;
- v->color[2] *= invW;
- v->color[3] *= invW;
+ v->color[0] *= wRcp;
+ v->color[1] *= wRcp;
+ v->color[2] *= wRcp;
+ v->color[3] *= wRcp;
// Transformation to screen space
sw_project_ndc_to_screen(v->screen, v->homogeneous);
@@ -2879,99 +2647,76 @@ static inline void sw_quad_clip_and_project(void)
static inline bool sw_quad_is_axis_aligned(void)
{
- int horizontal = 0;
- int vertical = 0;
-
+ // Reject quads with perspective projection
+ // The fast path assumes affine (non-perspective) quads,
+ // so we require all vertices to have homogeneous w = 1.0
for (int i = 0; i < 4; i++)
{
if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) return false;
-
- const float *v0 = RLSW.vertexBuffer[i].position;
- const float *v1 = RLSW.vertexBuffer[(i + 1)%4].position;
-
- float dx = v1[0] - v0[0];
- float dy = v1[1] - v0[1];
-
- if ((fabsf(dx) > 1e-6f) && (fabsf(dy) < 1e-6f)) horizontal++;
- else if ((fabsf(dy) > 1e-6f) && (fabsf(dx) < 1e-6f)) vertical++;
- else return false; // Diagonal edge -> not axis-aligned
}
- return ((horizontal == 2) && (vertical == 2));
+ // Epsilon tolerance in screen space (pixels)
+ const float epsilon = 0.5f;
+
+ // Fetch screen-space positions for the four quad vertices
+ const float *p0 = RLSW.vertexBuffer[0].screen;
+ const float *p1 = RLSW.vertexBuffer[1].screen;
+ const float *p2 = RLSW.vertexBuffer[2].screen;
+ const float *p3 = RLSW.vertexBuffer[3].screen;
+
+ // Compute edge vectors between consecutive vertices
+ // These define the four sides of the quad in screen space
+ float dx01 = p1[0] - p0[0], dy01 = p1[1] - p0[1];
+ float dx12 = p2[0] - p1[0], dy12 = p2[1] - p1[1];
+ float dx23 = p3[0] - p2[0], dy23 = p3[1] - p2[1];
+ float dx30 = p0[0] - p3[0], dy30 = p0[1] - p3[1];
+
+ // Each edge must be either horizontal or vertical within epsilon tolerance
+ // If any edge deviates significantly from either axis, the quad is not axis-aligned
+ if (!((fabsf(dy01) < epsilon) || (fabsf(dx01) < epsilon))) return false;
+ if (!((fabsf(dy12) < epsilon) || (fabsf(dx12) < epsilon))) return false;
+ if (!((fabsf(dy23) < epsilon) || (fabsf(dx23) < epsilon))) return false;
+ if (!((fabsf(dy30) < epsilon) || (fabsf(dx30) < epsilon))) return false;
+
+ return true;
}
static inline void sw_quad_sort_cw(const sw_vertex_t* *output)
{
- // Sort 4 quad vertices into clockwise order with fixed layout:
- //
- // v0 -- v1
- // | |
- // v3 -- v2
- //
- // The goal is:
- // - v0: top-left (minimum Y, then minimum X)
- // - v1: top-right (minimum Y row, maximum X)
- // - v2: bottom-right (maximum Y, maximum X)
- // - v3: bottom-left (maximum Y, minimum X)
const sw_vertex_t *input = RLSW.vertexBuffer;
- // Separate vertices into top and bottom based on Y-coordinate
- const sw_vertex_t *top[2] = {NULL, NULL};
- const sw_vertex_t *bottom[2] = {NULL, NULL};
- int topCount = 0, bottomCount = 0;
+ // Calculate the centroid of the quad
+ float cx = (input[0].screen[0] + input[1].screen[0] +
+ input[2].screen[0] + input[3].screen[0])*0.25f;
+ float cy = (input[0].screen[1] + input[1].screen[1] +
+ input[2].screen[1] + input[3].screen[1])*0.25f;
- // Find minimum and maximum Y
- float minY = input[0].screen[1];
- float maxY = input[0].screen[1];
+ // Calculate the angle of each vertex relative to the center
+ // and assign them directly to their correct position
+ const sw_vertex_t *corners[4] = { 0 };
- for (int i = 1; i < 4; i++)
- {
- if (input[i].screen[1] < minY) minY = input[i].screen[1];
- if (input[i].screen[1] > maxY) maxY = input[i].screen[1];
- }
-
- // Separate vertices based on Y-coordinate
for (int i = 0; i < 4; i++)
{
- if ((input[i].screen[1] == minY) && (topCount < 2)) top[topCount++] = &input[i];
- else if ((input[i].screen[1] == maxY) && (bottomCount < 2)) bottom[bottomCount++] = &input[i];
+ float dx = input[i].screen[0] - cx;
+ float dy = input[i].screen[1] - cy;
+
+ // Determine the quadrant (clockwise from top-left)
+ // top-left: dx < 0, dy < 0
+ // top-right: dx >= 0, dy < 0
+ // bottom-right: dx >= 0, dy >= 0
+ // bottom-left: dx < 0, dy >= 0
+
+ int idx;
+ if (dy < 0) idx = (dx < 0)? 0 : 1; // Top row
+ else idx = (dx < 0)? 3 : 2; // Bottom row
+
+ corners[idx] = &input[i];
}
- // If we don't have enough top/bottom vertices (e.g., Y values are all different),
- // classify vertices as top or bottom based on whether they're closer to minY or maxY
- for (int i = 0; i < 4; i++)
- {
- if ((topCount < 2) && (&input[i] != top[0]) && (&input[i] != bottom[0]) && (&input[i] != bottom[1]))
- {
- if (fabsf(input[i].screen[1] - minY) <= fabsf(input[i].screen[1] - maxY)) top[topCount++] = &input[i];
- }
- if ((bottomCount < 2) && (&input[i] != top[0]) && (&input[i] != top[1]) && (&input[i] != bottom[0]))
- {
- if (fabsf(input[i].screen[1] - maxY) < fabsf(input[i].screen[1] - minY)) bottom[bottomCount++] = &input[i];
- }
- }
-
- // Sort top vertices by X (left to right)
- if ((topCount == 2) && (top[0]->screen[0] > top[1]->screen[0]))
- {
- const sw_vertex_t *temp = top[0];
- top[0] = top[1];
- top[1] = temp;
- }
-
- // Sort bottom vertices by X (left to right)
- if ((bottomCount == 2) && (bottom[0]->screen[0] > bottom[1]->screen[0]))
- {
- const sw_vertex_t *temp = bottom[0];
- bottom[0] = bottom[1];
- bottom[1] = temp;
- }
-
- // Assign vertices in clockwise order as per the required layout
- output[0] = top[0]; // v0: top-left
- output[1] = top[topCount-1]; // v1: top-right
- output[2] = bottom[bottomCount-1]; // v2: bottom-right
- output[3] = bottom[0]; // v3: bottom-left
+ output[0] = corners[0]; // top-left
+ output[1] = corners[1]; // top-right
+ output[2] = corners[2]; // bottom-right
+ output[3] = corners[3]; // bottom-left
}
// TODO: REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth,
@@ -2989,65 +2734,68 @@ static inline void FUNC_NAME(void)
const sw_vertex_t *v3 = sortedVerts[3]; \
\
/* Screen bounds (axis-aligned) */ \
- int xMin = (int)(v0->screen[0] + 0.5f); \
- int yMin = (int)(v0->screen[1] + 0.5f); \
- int xMax = (int)(v2->screen[0] + 0.5f); \
- int yMax = (int)(v2->screen[1] + 0.5f); \
+ int xMin = (int)v0->screen[0]; \
+ int yMin = (int)v0->screen[1]; \
+ int xMax = (int)v2->screen[0]; \
+ int yMax = (int)v2->screen[1]; \
\
- int width = xMax - xMin; \
- int height = yMax - yMin; \
+ float w = v2->screen[0] - v0->screen[0]; \
+ float h = v2->screen[1] - v0->screen[1]; \
\
- if ((width == 0) || (height == 0)) return; \
+ if ((w == 0) || (h == 0)) return; \
\
- float wRcp = (width > 0.0f)? 1.0f/width : 0.0f; \
- float hRcp = (height > 0.0f)? 1.0f/height : 0.0f; \
+ float wRcp = (w > 0.0f)? 1.0f/w : 0.0f; \
+ float hRcp = (h > 0.0f)? 1.0f/h : 0.0f; \
+ \
+ /* Subpixel corrections */ \
+ float xSubstep = 1.0f - sw_fract(v0->screen[0]); \
+ float ySubstep = 1.0f - sw_fract(v0->screen[1]); \
\
/* Calculation of vertex gradients in X and Y */ \
- float tcDx[2], tcDy[2]; \
+ float dUdx = 0.0f, dVdx = 0.0f; \
+ float dUdy = 0.0f, dVdy = 0.0f; \
if (ENABLE_TEXTURE) { \
- tcDx[0] = (v1->texcoord[0] - v0->texcoord[0])*wRcp; \
- tcDx[1] = (v1->texcoord[1] - v0->texcoord[1])*wRcp; \
- tcDy[0] = (v3->texcoord[0] - v0->texcoord[0])*hRcp; \
- tcDy[1] = (v3->texcoord[1] - v0->texcoord[1])*hRcp; \
+ dUdx = (v1->texcoord[0] - v0->texcoord[0])*wRcp; \
+ dVdx = (v1->texcoord[1] - v0->texcoord[1])*wRcp; \
+ dUdy = (v3->texcoord[0] - v0->texcoord[0])*hRcp; \
+ dVdy = (v3->texcoord[1] - v0->texcoord[1])*hRcp; \
} \
\
- float cDx[4], cDy[4]; \
- cDx[0] = (v1->color[0] - v0->color[0])*wRcp; \
- cDx[1] = (v1->color[1] - v0->color[1])*wRcp; \
- cDx[2] = (v1->color[2] - v0->color[2])*wRcp; \
- cDx[3] = (v1->color[3] - v0->color[3])*wRcp; \
- cDy[0] = (v3->color[0] - v0->color[0])*hRcp; \
- cDy[1] = (v3->color[1] - v0->color[1])*hRcp; \
- cDy[2] = (v3->color[2] - v0->color[2])*hRcp; \
- cDy[3] = (v3->color[3] - v0->color[3])*hRcp; \
+ float dCdx[4], dCdy[4]; \
+ dCdx[0] = (v1->color[0] - v0->color[0])*wRcp; \
+ dCdx[1] = (v1->color[1] - v0->color[1])*wRcp; \
+ dCdx[2] = (v1->color[2] - v0->color[2])*wRcp; \
+ dCdx[3] = (v1->color[3] - v0->color[3])*wRcp; \
+ dCdy[0] = (v3->color[0] - v0->color[0])*hRcp; \
+ dCdy[1] = (v3->color[1] - v0->color[1])*hRcp; \
+ dCdy[2] = (v3->color[2] - v0->color[2])*hRcp; \
+ dCdy[3] = (v3->color[3] - v0->color[3])*hRcp; \
\
- float zDx, zDy; \
- zDx = (v1->homogeneous[2] - v0->homogeneous[2])*wRcp; \
- zDy = (v3->homogeneous[2] - v0->homogeneous[2])*hRcp; \
+ float dZdx, dZdy; \
+ dZdx = (v1->homogeneous[2] - v0->homogeneous[2])*wRcp; \
+ dZdy = (v3->homogeneous[2] - v0->homogeneous[2])*hRcp; \
\
/* Start of quad rasterization */ \
const sw_texture_t *tex; \
if (ENABLE_TEXTURE) tex = &RLSW.loadedTextures[RLSW.currentTexture]; \
\
- void *cDstBase = RLSW.framebuffer.color; \
- void *dDstBase = RLSW.framebuffer.depth; \
+ sw_pixel_t *pixels = RLSW.framebuffer.pixels; \
int wDst = RLSW.framebuffer.width; \
\
- float zScanline = v0->homogeneous[2]; \
- float uScanline = v0->texcoord[0]; \
- float vScanline = v0->texcoord[1]; \
+ float zScanline = v0->homogeneous[2] + dZdx*xSubstep + dZdy*ySubstep; \
+ float uScanline = v0->texcoord[0] + dUdx*xSubstep + dUdy*ySubstep; \
+ float vScanline = v0->texcoord[1] + dVdx*xSubstep + dVdy*ySubstep; \
\
float colorScanline[4] = { \
- v0->color[0], \
- v0->color[1], \
- v0->color[2], \
- v0->color[3] \
+ v0->color[0] + dCdx[0]*xSubstep + dCdy[0]*ySubstep, \
+ v0->color[1] + dCdx[1]*xSubstep + dCdy[1]*ySubstep, \
+ v0->color[2] + dCdx[2]*xSubstep + dCdy[2]*ySubstep, \
+ v0->color[3] + dCdx[3]*xSubstep + dCdy[3]*ySubstep \
}; \
\
for (int y = yMin; y < yMax; y++) \
{ \
- void *cptr = sw_framebuffer_get_color_addr(cDstBase, y*wDst + xMin); \
- void *dptr = sw_framebuffer_get_depth_addr(dDstBase, y*wDst + xMin); \
+ sw_pixel_t *ptr = pixels + y*wDst + xMin; \
\
float z = zScanline; \
float u = uScanline; \
@@ -3063,16 +2811,6 @@ static inline void FUNC_NAME(void)
/* Scanline rasterization */ \
for (int x = xMin; x < xMax; x++) \
{ \
- /* Test and write depth */ \
- if (ENABLE_DEPTH_TEST) \
- { \
- /* TODO: Implement different depth funcs? */ \
- float depth = sw_framebuffer_read_depth(dptr); \
- if (z > depth) goto discard; \
- } \
- \
- sw_framebuffer_write_depth(dptr, z); \
- \
/* Pixel color computation */ \
float srcColor[4] = { \
color[0], \
@@ -3081,10 +2819,21 @@ static inline void FUNC_NAME(void)
color[3] \
}; \
\
+ /* Test and write depth */ \
+ if (ENABLE_DEPTH_TEST) \
+ { \
+ /* TODO: Implement different depth funcs? */ \
+ float depth = sw_framebuffer_read_depth(ptr); \
+ if (z > depth) goto discard; \
+ } \
+ \
+ /* TODO: Implement depth mask */ \
+ sw_framebuffer_write_depth(ptr, z); \
+ \
if (ENABLE_TEXTURE) \
{ \
float texColor[4]; \
- sw_texture_sample(texColor, tex, u, v, tcDx[0], tcDy[0], tcDx[1], tcDy[1]); \
+ sw_texture_sample(texColor, tex, u, v, dUdx, dUdy, dVdx, dVdy); \
srcColor[0] *= texColor[0]; \
srcColor[1] *= texColor[1]; \
srcColor[2] *= texColor[2]; \
@@ -3094,45 +2843,36 @@ static inline void FUNC_NAME(void)
if (ENABLE_COLOR_BLEND) \
{ \
float dstColor[4]; \
- sw_framebuffer_read_color(dstColor, cptr); \
- \
+ sw_framebuffer_read_color(dstColor, ptr); \
sw_blend_colors(dstColor, srcColor); \
- dstColor[0] = sw_saturate(dstColor[0]); \
- dstColor[1] = sw_saturate(dstColor[1]); \
- dstColor[2] = sw_saturate(dstColor[2]); \
- dstColor[3] = sw_saturate(dstColor[3]); \
- \
- sw_framebuffer_write_color(cptr, dstColor); \
+ sw_framebuffer_write_color(ptr, dstColor); \
} \
- else sw_framebuffer_write_color(cptr, srcColor); \
+ else sw_framebuffer_write_color(ptr, srcColor); \
\
discard: \
- z += zDx; \
- color[0] += cDx[0]; \
- color[1] += cDx[1]; \
- color[2] += cDx[2]; \
- color[3] += cDx[3]; \
- \
+ z += dZdx; \
+ color[0] += dCdx[0]; \
+ color[1] += dCdx[1]; \
+ color[2] += dCdx[2]; \
+ color[3] += dCdx[3]; \
if (ENABLE_TEXTURE) \
{ \
- u += tcDx[0]; \
- v += tcDx[1]; \
+ u += dUdx; \
+ v += dVdx; \
} \
- \
- sw_framebuffer_inc_color_addr(&cptr); \
- sw_framebuffer_inc_depth_addr(&dptr); \
+ ++ptr; \
} \
\
- zScanline += zDy; \
- colorScanline[0] += cDy[0]; \
- colorScanline[1] += cDy[1]; \
- colorScanline[2] += cDy[2]; \
- colorScanline[3] += cDy[3]; \
+ zScanline += dZdy; \
+ colorScanline[0] += dCdy[0]; \
+ colorScanline[1] += dCdy[1]; \
+ colorScanline[2] += dCdy[2]; \
+ colorScanline[3] += dCdy[3]; \
\
if (ENABLE_TEXTURE) \
{ \
- uScanline += tcDy[0]; \
- vScanline += tcDy[1]; \
+ uScanline += dUdy; \
+ vScanline += dVdy; \
} \
} \
}
@@ -3157,15 +2897,19 @@ static inline void sw_quad_render(void)
if (RLSW.vertexCounter < 3) return;
+ uint32_t state = RLSW.stateFlags;
+ if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D;
+ if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND;
+
if ((RLSW.vertexCounter == 4) && sw_quad_is_axis_aligned())
{
- if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_DEPTH_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH();
- else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH();
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX();
+ if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_DEPTH_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX();
else sw_quad_raster_axis_aligned();
return;
}
@@ -3183,20 +2927,21 @@ static inline void sw_quad_render(void)
} \
}
- if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
+ if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
else TRIANGLE_RASTER(sw_triangle_raster)
#undef TRIANGLE_RASTER
}
+//-------------------------------------------------------------------------------------------
// Line rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_line_clip_coord(float q, float p, float *t0, float *t1)
{
if (fabsf(p) < SW_CLIP_EPSILON)
@@ -3295,137 +3040,84 @@ static inline bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1)
#define DEFINE_LINE_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \
static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \
{ \
- int x1 = (int)(v0->screen[0] + 0.5f); \
- int y1 = (int)(v0->screen[1] + 0.5f); \
- int x2 = (int)(v1->screen[0] + 0.5f); \
- int y2 = (int)(v1->screen[1] + 0.5f); \
+ float x0 = v0->screen[0]; \
+ float y0 = v0->screen[1]; \
+ float x1 = v1->screen[0]; \
+ float y1 = v1->screen[1]; \
\
- int dx = x2 - x1; \
- int dy = y2 - y1; \
+ float dx = x1 - x0; \
+ float dy = y1 - y0; \
\
- /* Handling of lines that are more horizontal or vertical */ \
- if ((dx == 0) && (dy == 0)) \
+ /* Compute dominant axis and subpixel offset */ \
+ float steps, substep; \
+ if (fabsf(dx) > fabsf(dy)) \
{ \
- /* TODO: A point should be rendered here */ \
- return; \
- } \
- \
- bool yLonger = (abs(dy) > abs(dx)); \
- int longLen, shortLen; \
- \
- if (yLonger) \
- { \
- longLen = dy; \
- shortLen = dx; \
+ steps = fabsf(dx); \
+ if (steps < 1.0f) return; \
+ substep = (dx >= 0.0f)? (1.0f - sw_fract(x0)) : sw_fract(x0); \
} \
else \
{ \
- longLen = dx; \
- shortLen = dy; \
+ steps = fabsf(dy); \
+ if (steps < 1.0f) return; \
+ substep = (dy >= 0.0f)? (1.0f - sw_fract(y0)) : sw_fract(y0); \
} \
\
- /* Handling of traversal direction */ \
- int sgnInc = (longLen < 0)? -1 : 1; \
- int abslongLen = abs(longLen); \
+ /* Compute per pixel increments */ \
+ float xInc = dx/steps; \
+ float yInc = dy/steps; \
+ float stepRcp = 1.0f/steps; \
\
- /* Calculation of the increment step for the shorter coordinate */ \
- int decInc = 0; \
- if (abslongLen != 0) decInc = (shortLen << 16)/abslongLen; \
+ float zInc = (v1->homogeneous[2] - v0->homogeneous[2])*stepRcp; \
+ float rInc = (v1->color[0] - v0->color[0])*stepRcp; \
+ float gInc = (v1->color[1] - v0->color[1])*stepRcp; \
+ float bInc = (v1->color[2] - v0->color[2])*stepRcp; \
+ float aInc = (v1->color[3] - v0->color[3])*stepRcp; \
\
- float longLenRcp = (abslongLen != 0)? (1.0f/abslongLen) : 0.0f; \
- \
- /* Calculation of interpolation steps */ \
- const float zStep = (v1->homogeneous[2] - v0->homogeneous[2])*longLenRcp; \
- const float rStep = (v1->color[0] - v0->color[0])*longLenRcp; \
- const float gStep = (v1->color[1] - v0->color[1])*longLenRcp; \
- const float bStep = (v1->color[2] - v0->color[2])*longLenRcp; \
- const float aStep = (v1->color[3] - v0->color[3])*longLenRcp; \
- \
- float z = v0->homogeneous[2]; \
- \
- float color[4] = { \
- v0->color[0], \
- v0->color[1], \
- v0->color[2], \
- v0->color[3] \
- }; \
+ /* Initializing the interpolation starting values */ \
+ float x = x0 + xInc*substep; \
+ float y = y0 + yInc*substep; \
+ float z = v0->homogeneous[2] + zInc*substep; \
+ float r = v0->color[0] + rInc*substep; \
+ float g = v0->color[1] + gInc*substep; \
+ float b = v0->color[2] + bInc*substep; \
+ float a = v0->color[3] + aInc*substep; \
\
const int fbWidth = RLSW.framebuffer.width; \
- void *cBuffer = RLSW.framebuffer.color; \
- void *dBuffer = RLSW.framebuffer.depth; \
+ sw_pixel_t *pixels = RLSW.framebuffer.pixels; \
\
- int j = 0; \
- if (yLonger) \
+ int numPixels = (int)(steps - substep) + 1; \
+ \
+ for (int i = 0; i < numPixels; i++) \
{ \
- for (int i = 0; i != longLen; i += sgnInc) \
+ /* REVIEW: May require reviewing projection details */ \
+ int px = (int)(x - 0.5f); \
+ int py = (int)(y - 0.5f); \
+ \
+ sw_pixel_t *ptr = pixels + py*fbWidth + px; \
+ \
+ if (ENABLE_DEPTH_TEST) \
{ \
- int offset = (y1 + i)*fbWidth + (x1 + (j >> 16)); \
- void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \
- \
- if (ENABLE_DEPTH_TEST) \
- { \
- float depth = sw_framebuffer_read_depth(dptr); \
- if (z > depth) goto discardA; \
- } \
- \
- sw_framebuffer_write_depth(dptr, z); \
- \
- void *cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \
- \
- if (ENABLE_COLOR_BLEND) \
- { \
- float dstColor[4]; \
- sw_framebuffer_read_color(dstColor, cptr); \
- \
- sw_blend_colors(dstColor, color); \
- sw_framebuffer_write_color(cptr, dstColor); \
- } \
- else sw_framebuffer_write_color(cptr, color); \
- \
- discardA: \
- j += decInc; \
- z += zStep; \
- color[0] += rStep; \
- color[1] += gStep; \
- color[2] += bStep; \
- color[3] += aStep; \
+ float depth = sw_framebuffer_read_depth(ptr); \
+ if (z > depth) goto discard; \
} \
- } \
- else \
- { \
- for (int i = 0; i != longLen; i += sgnInc) \
+ \
+ sw_framebuffer_write_depth(ptr, z); \
+ \
+ float color[4] = {r, g, b, a}; \
+ \
+ if (ENABLE_COLOR_BLEND) \
{ \
- int offset = (y1 + (j >> 16))*fbWidth + (x1 + i); \
- void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \
- \
- if (ENABLE_DEPTH_TEST) \
- { \
- float depth = sw_framebuffer_read_depth(dptr); \
- if (z > depth) goto discardB; \
- } \
- \
- sw_framebuffer_write_depth(dptr, z); \
- \
- void *cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \
- \
- if (ENABLE_COLOR_BLEND) \
- { \
- float dstColor[4]; \
- sw_framebuffer_read_color(dstColor, cptr); \
- \
- sw_blend_colors(dstColor, color); \
- sw_framebuffer_write_color(cptr, dstColor); \
- } \
- else sw_framebuffer_write_color(cptr, color); \
- \
- discardB: \
- j += decInc; \
- z += zStep; \
- color[0] += rStep; \
- color[1] += gStep; \
- color[2] += bStep; \
- color[3] += aStep; \
+ float dstColor[4]; \
+ sw_framebuffer_read_color(dstColor, ptr); \
+ sw_blend_colors(dstColor, color); \
+ sw_framebuffer_write_color(ptr, dstColor); \
} \
+ else sw_framebuffer_write_color(ptr, color); \
+ \
+ discard: \
+ x += xInc; y += yInc; z += zInc; \
+ r += rInc; g += gInc; b += bInc; a += aInc; \
} \
}
@@ -3507,9 +3199,10 @@ static inline void sw_line_render(sw_vertex_t *vertices)
else sw_line_raster(&vertices[0], &vertices[1]);
}
}
+//-------------------------------------------------------------------------------------------
// Point rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_point_clip_and_project(sw_vertex_t *v)
{
if (v->homogeneous[3] != 1.0f)
@@ -3561,28 +3254,24 @@ static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \
} \
\
int offset = y*RLSW.framebuffer.width + x; \
- \
- void *dptr = sw_framebuffer_get_depth_addr(RLSW.framebuffer.depth, offset); \
+ sw_pixel_t *ptr = RLSW.framebuffer.pixels + offset; \
\
if (ENABLE_DEPTH_TEST) \
{ \
- float depth = sw_framebuffer_read_depth(dptr); \
+ float depth = sw_framebuffer_read_depth(ptr); \
if (z > depth) return; \
} \
\
- sw_framebuffer_write_depth(dptr, z); \
- \
- void *cptr = sw_framebuffer_get_color_addr(RLSW.framebuffer.color, offset); \
+ sw_framebuffer_write_depth(ptr, z); \
\
if (ENABLE_COLOR_BLEND) \
{ \
float dstColor[4]; \
- sw_framebuffer_read_color(dstColor, cptr); \
- \
+ sw_framebuffer_read_color(dstColor, ptr); \
sw_blend_colors(dstColor, color); \
- sw_framebuffer_write_color(cptr, dstColor); \
+ sw_framebuffer_write_color(ptr, dstColor); \
} \
- else sw_framebuffer_write_color(cptr, color); \
+ else sw_framebuffer_write_color(ptr, color); \
}
#define DEFINE_POINT_THICK_RASTER(FUNC_NAME, RASTER_FUNC) \
@@ -3674,9 +3363,10 @@ static inline void sw_point_render(sw_vertex_t *v)
else sw_point_raster(v->screen[0], v->screen[1], v->homogeneous[2], v->color);
}
}
+//-------------------------------------------------------------------------------------------
-// Polygon modes mendering logic
-
+// Polygon modes rendering logic
+//-------------------------------------------------------------------------------------------
static inline void sw_poly_point_render(void)
{
for (int i = 0; i < RLSW.vertexCounter; i++) sw_point_render(&RLSW.vertexBuffer[i]);
@@ -3687,9 +3377,14 @@ static inline void sw_poly_line_render(void)
const sw_vertex_t *vertices = RLSW.vertexBuffer;
int cm1 = RLSW.vertexCounter - 1;
- for (int i = 0; i < cm1; i++) sw_line_render((sw_vertex_t[2]){ vertices[i], vertices[i + 1] });
+ for (int i = 0; i < cm1; i++)
+ {
+ sw_vertex_t verts[2] = { vertices[i], vertices[i + 1] };
+ sw_line_render(verts);
+ }
- sw_line_render((sw_vertex_t[2]){ vertices[cm1], vertices[0] });
+ sw_vertex_t verts[2] = { vertices[cm1], vertices[0] };
+ sw_line_render(verts);
}
static inline void sw_poly_fill_render(void)
@@ -3702,16 +3397,54 @@ static inline void sw_poly_fill_render(void)
case SW_QUADS: sw_quad_render(); break;
}
}
+//-------------------------------------------------------------------------------------------
+
+// Immediate rendering logic
+//-------------------------------------------------------------------------------------------
+void sw_immediate_push_vertex(const float position[4], const float color[4], const float texcoord[2])
+{
+ // Copy the attributes in the current vertex
+ sw_vertex_t *vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++];
+ for (int i = 0; i < 4; i++)
+ {
+ vertex->position[i] = position[i];
+ if (i < 2) vertex->texcoord[i] = texcoord[i];
+ vertex->color[i] = color[i];
+ }
+
+ // Calculate homogeneous coordinates
+ const float *m = RLSW.matMVP, *v = vertex->position;
+ vertex->homogeneous[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3];
+ vertex->homogeneous[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3];
+ vertex->homogeneous[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3];
+ vertex->homogeneous[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3];
+
+ // Immediate rendering of the primitive if the required number is reached
+ if (RLSW.vertexCounter == RLSW.reqVertices)
+ {
+ switch (RLSW.polyMode)
+ {
+ case SW_FILL: sw_poly_fill_render(); break;
+ case SW_LINE: sw_poly_line_render(); break;
+ case SW_POINT: sw_poly_point_render(); break;
+ default: break;
+ }
+
+ RLSW.vertexCounter = 0;
+ }
+}
+
+//-------------------------------------------------------------------------------------------
// Validity check helper functions
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_is_texture_valid(uint32_t id)
{
bool valid = true;
if (id == 0) valid = false;
else if (id >= SW_MAX_TEXTURES) valid = false;
- else if (RLSW.loadedTextures[id].pixels.cptr == 0) valid = false;
+ else if (RLSW.loadedTextures[id].pixels == NULL) valid = false;
return true;
}
@@ -3806,6 +3539,7 @@ static inline bool sw_is_blend_dst_factor_valid(int blend)
return result;
}
+//-------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
// Module Functions Definition
@@ -3817,17 +3551,15 @@ bool swInit(int w, int h)
swViewport(0, 0, w, h);
swScissor(0, 0, w, h);
- RLSW.loadedTextures = SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t));
+ RLSW.loadedTextures = (sw_texture_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t));
if (RLSW.loadedTextures == NULL) { swClose(); return false; }
- RLSW.freeTextureIds = SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t));
+ RLSW.freeTextureIds = (uint32_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t));
if (RLSW.loadedTextures == NULL) { swClose(); return false; }
- RLSW.clearColor[0] = 0.0f;
- RLSW.clearColor[1] = 0.0f;
- RLSW.clearColor[2] = 0.0f;
- RLSW.clearColor[3] = 1.0f;
- RLSW.clearDepth = 1.0f;
+ const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
+ sw_framebuffer_write_color(&RLSW.clearValue, clearColor);
+ sw_framebuffer_write_depth(&RLSW.clearValue, 1.0f);
RLSW.currentMatrixMode = SW_MODELVIEW;
RLSW.currentMatrix = &RLSW.stackModelview[0];
@@ -3859,46 +3591,63 @@ bool swInit(int w, int h)
RLSW.polyMode = SW_FILL;
RLSW.cullFace = SW_BACK;
- static const float defTex[3*2*2] = {
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f,
+ static uint32_t defaultTex[3*2*2] = {
+ 0xFFFFFFFF,
+ 0xFFFFFFFF,
+ 0xFFFFFFFF,
+ 0xFFFFFFFF
};
- RLSW.loadedTextures[0].pixels.cptr = defTex;
+ RLSW.loadedTextures[0].pixels = (uint8_t*)defaultTex;
RLSW.loadedTextures[0].width = 2;
RLSW.loadedTextures[0].height = 2;
RLSW.loadedTextures[0].wMinus1 = 1;
RLSW.loadedTextures[0].hMinus1 = 1;
- RLSW.loadedTextures[0].format = SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32;
RLSW.loadedTextures[0].minFilter = SW_NEAREST;
RLSW.loadedTextures[0].magFilter = SW_NEAREST;
RLSW.loadedTextures[0].sWrap = SW_REPEAT;
RLSW.loadedTextures[0].tWrap = SW_REPEAT;
RLSW.loadedTextures[0].tx = 0.5f;
RLSW.loadedTextures[0].ty = 0.5f;
- RLSW.loadedTextures[0].copy = false;
RLSW.loadedTextureCount = 1;
+ SW_LOG("INFO: RLSW: Software renderer initialized successfully\n");
+#if defined(SW_HAS_FMA_AVX) && defined(SW_HAS_FMA_AVX2)
+ SW_LOG("INFO: RLSW: Using SIMD instructions: FMA AVX\n");
+#endif
+#if defined(SW_HAS_AVX) || defined(SW_HAS_AVX2)
+ SW_LOG("INFO: RLSW: Using SIMD instructions: AVX\n");
+#endif
+#if defined(SW_HAS_SSE) || defined(SW_HAS_SSE2) || defined(SW_HAS_SSE3) || defined(SW_HAS_SSSE3) || defined(SW_HAS_SSE41) || defined(SW_HAS_SSE42)
+ SW_LOG("INFO: RLSW: Using SIMD instructions: SSE\n");
+#endif
+#if defined(SW_HAS_NEON_FMA) || defined(SW_HAS_NEON)
+ SW_LOG("INFO: RLSW: Using SIMD instructions: NEON\n");
+#endif
+#if defined(SW_HAS_RVV)
+ SW_LOG("INFO: RLSW: Using SIMD instructions: RVV\n");
+#endif
+
return true;
}
void swClose(void)
{
+ // NOTE: Starts at texture 1, texture 0 does not have to be freed
for (int i = 1; i < RLSW.loadedTextureCount; i++)
{
- sw_texture_t *texture = &RLSW.loadedTextures[i];
- if (sw_is_texture_valid(i) && texture->copy) SW_FREE(texture->pixels.ptr);
+ if (sw_is_texture_valid(i))
+ {
+ SW_FREE(RLSW.loadedTextures[i].pixels);
+ }
}
- SW_FREE(RLSW.framebuffer.color);
- SW_FREE(RLSW.framebuffer.depth);
+ SW_FREE(RLSW.framebuffer.pixels);
SW_FREE(RLSW.loadedTextures);
SW_FREE(RLSW.freeTextureIds);
- RLSW = (sw_context_t) { 0 };
+ RLSW = SW_CURLY_INIT(sw_context_t) { 0 };
}
bool swResizeFramebuffer(int w, int h)
@@ -3908,19 +3657,10 @@ bool swResizeFramebuffer(int w, int h)
void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels)
{
- sw_pixelformat_t pFormat = sw_get_pixel_format(format, type);
+ sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type);
- if (w <= 0)
- {
- RLSW.errCode = SW_INVALID_VALUE;
- return;
- }
-
- if (h <= 0)
- {
- RLSW.errCode = SW_INVALID_VALUE;
- return;
- }
+ if (w <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
+ if (h <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
if (w > RLSW.framebuffer.width) w = RLSW.framebuffer.width;
if (h > RLSW.framebuffer.height) h = RLSW.framebuffer.height;
@@ -3928,40 +3668,51 @@ void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type,
x = sw_clampi(x, 0, w);
y = sw_clampi(y, 0, h);
+ if ((x >= w) || (y >= h)) return;
+
+ if ((x == 0) && (y == 0) && (w == RLSW.framebuffer.width) && (h == RLSW.framebuffer.height))
+ {
+ #if SW_COLOR_BUFFER_BITS == 32
+ if (pFormat == SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
+ {
+ sw_framebuffer_copy_fast(pixels);
+ return;
+ }
+ #elif SW_COLOR_BUFFER_BITS == 16
+ if (pFormat == SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5)
+ {
+ sw_framebuffer_copy_fast(pixels);
+ return;
+ }
+ #endif
+ }
+
switch (pFormat)
{
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_copy_to_R32(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_copy_to_R32G32B32(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_copy_to_R32G32B32A32(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_copy_to_R16(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_copy_to_R16G16B16(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_copy_to_R16G16B16A16(x, y, w, h, pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, (uint16_t *)pixels); break;
+ //case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, (uint8_t *)pixels); break;
+ // Below: not implemented
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
default: RLSW.errCode = SW_INVALID_ENUM; break;
}
}
void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels)
{
- sw_pixelformat_t pFormat = sw_get_pixel_format(format, type);
+ sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type);
- if (wSrc <= 0)
- {
- RLSW.errCode = SW_INVALID_VALUE;
- return;
- }
-
- if (hSrc <= 0)
- {
- RLSW.errCode = SW_INVALID_VALUE;
- return;
- }
+ if (wSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
+ if (hSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
if (wSrc > RLSW.framebuffer.width) wSrc = RLSW.framebuffer.width;
if (hSrc > RLSW.framebuffer.height) hSrc = RLSW.framebuffer.height;
@@ -3969,33 +3720,35 @@ void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySr
xSrc = sw_clampi(xSrc, 0, wSrc);
ySrc = sw_clampi(ySrc, 0, hSrc);
+ // Check if the sizes are identical after clamping the source to avoid unexpected issues
+ // REVIEW: This repeats the operations if true, so we could make a copy function without these checks
+ if (xDst == xSrc && yDst == ySrc && wDst == wSrc && hDst == hSrc)
+ {
+ swCopyFramebuffer(xSrc, ySrc, wSrc, hSrc, format, type, pixels);
+ }
+
switch (pFormat)
{
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_blit_to_R32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_blit_to_R32G32B32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_blit_to_R32G32B32A32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_blit_to_R16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_blit_to_R16G16B16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_blit_to_R16G16B16A16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- default: RLSW.errCode = SW_INVALID_ENUM; break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ // Below: not implemented
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+ default:
+ RLSW.errCode = SW_INVALID_ENUM;
+ break;
}
}
-void *swGetColorBuffer(int *w, int *h)
-{
- if (w) *w = RLSW.framebuffer.width;
- if (h) *h = RLSW.framebuffer.height;
-
- return RLSW.framebuffer.color;
-}
-
void swEnable(SWstate state)
{
switch (state)
@@ -4039,10 +3792,11 @@ void swGetFloatv(SWget name, float *v)
{
case SW_COLOR_CLEAR_VALUE:
{
- v[0] = RLSW.clearColor[0];
- v[1] = RLSW.clearColor[1];
- v[2] = RLSW.clearColor[2];
- v[3] = RLSW.clearColor[3];
+ sw_framebuffer_read_color(v, &RLSW.clearValue);
+ } break;
+ case SW_DEPTH_CLEAR_VALUE:
+ {
+ v[0] = sw_framebuffer_read_depth(&RLSW.clearValue);
} break;
case SW_CURRENT_COLOR:
{
@@ -4117,11 +3871,11 @@ void swViewport(int x, int y, int width, int height)
RLSW.vpSize[0] = width;
RLSW.vpSize[1] = height;
- RLSW.vpHalfSize[0] = (int)(width/2.0f + 0.5f);
- RLSW.vpHalfSize[1] = (int)(height/2.0f + 0.5f);
+ RLSW.vpHalf[0] = width/2.0f;
+ RLSW.vpHalf[1] = height/2.0f;
- RLSW.vpCenter[0] = x + RLSW.vpHalfSize[0];
- RLSW.vpCenter[1] = y + RLSW.vpHalfSize[1];
+ RLSW.vpCenter[0] = (float)x + RLSW.vpHalf[0];
+ RLSW.vpCenter[1] = (float)y + RLSW.vpHalf[1];
RLSW.vpMin[0] = sw_clampi(x, 0, RLSW.framebuffer.width - 1);
RLSW.vpMin[1] = sw_clampi(y, 0, RLSW.framebuffer.height - 1);
@@ -4150,10 +3904,13 @@ void swScissor(int x, int y, int width, int height)
void swClearColor(float r, float g, float b, float a)
{
- RLSW.clearColor[0] = r;
- RLSW.clearColor[1] = g;
- RLSW.clearColor[2] = b;
- RLSW.clearColor[3] = a;
+ float v[4] = { r, g, b, a };
+ sw_framebuffer_write_color(&RLSW.clearValue, v);
+}
+
+void swClearDepth(float depth)
+{
+ sw_framebuffer_write_depth(&RLSW.clearValue, depth);
}
void swClear(uint32_t bitmask)
@@ -4162,15 +3919,15 @@ void swClear(uint32_t bitmask)
if ((bitmask & (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) == (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT))
{
- sw_framebuffer_fill(RLSW.framebuffer.color, RLSW.framebuffer.depth,size, RLSW.clearColor, RLSW.clearDepth);
+ sw_framebuffer_fill(RLSW.framebuffer.pixels, size, RLSW.clearValue);
}
else if (bitmask & (SW_COLOR_BUFFER_BIT))
{
- sw_framebuffer_fill_color(RLSW.framebuffer.color, size, RLSW.clearColor);
+ sw_framebuffer_fill_color(RLSW.framebuffer.pixels, size, RLSW.clearValue.color);
}
else if (bitmask & SW_DEPTH_BUFFER_BIT)
{
- sw_framebuffer_fill_depth(RLSW.framebuffer.depth, size, RLSW.clearDepth);
+ sw_framebuffer_fill_depth(RLSW.framebuffer.pixels, size, RLSW.clearValue.depth);
}
}
@@ -4553,95 +4310,68 @@ void swBegin(SWdraw mode)
void swEnd(void)
{
- RLSW.drawMode = 0;
+ RLSW.drawMode = (SWdraw)0;
}
void swVertex2i(int x, int y)
{
const float v[4] = { (float)x, (float)y, 0.0f, 1.0f };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex2f(float x, float y)
{
const float v[4] = { x, y, 0.0f, 1.0f };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex2fv(const float *v)
{
const float v4[4] = { v[0], v[1], 0.0f, 1.0f };
- swVertex4fv(v4);
+ sw_immediate_push_vertex(v4, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex3i(int x, int y, int z)
{
const float v[4] = { (float)x, (float)y, (float)z, 1.0f };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex3f(float x, float y, float z)
{
const float v[4] = { x, y, z, 1.0f };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex3fv(const float *v)
{
const float v4[4] = { v[0], v[1], v[2], 1.0f };
- swVertex4fv(v4);
+ sw_immediate_push_vertex(v4, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex4i(int x, int y, int z, int w)
{
const float v[4] = { (float)x, (float)y, (float)z, (float)w };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex4f(float x, float y, float z, float w)
{
const float v[4] = { x, y, z, w };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex4fv(const float *v)
{
- // Copy the position in the current vertex
- sw_vertex_t *vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++];
- for (int i = 0; i < 4; i++) vertex->position[i] = v[i];
-
- // Copy additonal vertex data
- for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.current.texcoord[i];
- for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.current.color[i];
-
- // Calculation of homogeneous coordinates
- const float *m = RLSW.matMVP;
- vertex->homogeneous[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3];
- vertex->homogeneous[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3];
- vertex->homogeneous[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3];
- vertex->homogeneous[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3];
-
- // Immediate rendering of the primitive if the required number is reached
- if (RLSW.vertexCounter == RLSW.reqVertices)
- {
- switch (RLSW.polyMode)
- {
- case SW_FILL: sw_poly_fill_render(); break;
- case SW_LINE: sw_poly_line_render(); break;
- case SW_POINT: sw_poly_point_render(); break;
- default: break;
- }
-
- RLSW.vertexCounter = 0;
- }
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swColor3ub(uint8_t r, uint8_t g, uint8_t b)
{
float cv[4];
- cv[0] = (float)r/255;
- cv[1] = (float)g/255;
- cv[2] = (float)b/255;
+ cv[0] = (float)r*SW_INV_255;
+ cv[1] = (float)g*SW_INV_255;
+ cv[2] = (float)b*SW_INV_255;
cv[3] = 1.0f;
swColor4fv(cv);
@@ -4650,9 +4380,9 @@ void swColor3ub(uint8_t r, uint8_t g, uint8_t b)
void swColor3ubv(const uint8_t *v)
{
float cv[4];
- cv[0] = (float)v[0]/255;
- cv[1] = (float)v[1]/255;
- cv[2] = (float)v[2]/255;
+ cv[0] = (float)v[0]*SW_INV_255;
+ cv[1] = (float)v[1]*SW_INV_255;
+ cv[2] = (float)v[2]*SW_INV_255;
cv[3] = 1.0f;
swColor4fv(cv);
@@ -4683,10 +4413,10 @@ void swColor3fv(const float *v)
void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
float cv[4];
- cv[0] = (float)r/255;
- cv[1] = (float)g/255;
- cv[2] = (float)b/255;
- cv[3] = (float)a/255;
+ cv[0] = (float)r*SW_INV_255;
+ cv[1] = (float)g*SW_INV_255;
+ cv[2] = (float)b*SW_INV_255;
+ cv[3] = (float)a*SW_INV_255;
swColor4fv(cv);
}
@@ -4694,10 +4424,10 @@ void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
void swColor4ubv(const uint8_t *v)
{
float cv[4];
- cv[0] = (float)v[0]/255;
- cv[1] = (float)v[1]/255;
- cv[2] = (float)v[2]/255;
- cv[3] = (float)v[3]/255;
+ cv[0] = (float)v[0]*SW_INV_255;
+ cv[1] = (float)v[1]*SW_INV_255;
+ cv[2] = (float)v[2]*SW_INV_255;
+ cv[3] = (float)v[3]*SW_INV_255;
swColor4fv(cv);
}
@@ -4738,9 +4468,9 @@ void swBindArray(SWarray type, void *buffer)
{
switch (type)
{
- case SW_VERTEX_ARRAY: RLSW.array.positions = buffer; break;
- case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = buffer; break;
- case SW_COLOR_ARRAY: RLSW.array.colors = buffer; break;
+ case SW_VERTEX_ARRAY: RLSW.array.positions = (float *)buffer; break;
+ case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = (float *)buffer; break;
+ case SW_COLOR_ARRAY: RLSW.array.colors = (uint8_t *)buffer; break;
default: break;
}
}
@@ -4755,14 +4485,156 @@ void swDrawArrays(SWdraw mode, int offset, int count)
swBegin(mode);
{
- swTexCoord2f(0.0f, 0.0f);
- swColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ const float *texMatrix = RLSW.stackTexture[RLSW.stackTextureCounter - 1];
+ const float *defaultTexcoord = RLSW.current.texcoord;
+ const float *defaultColor = RLSW.current.color;
- for (int i = offset; i < count; i++)
+ const float *positions = RLSW.array.positions;
+ const float *texcoords = RLSW.array.texcoords;
+ const uint8_t *colors = RLSW.array.colors;
+
+ int end = offset + count;
+
+ for (int i = offset; i < end; i++)
{
- if (RLSW.array.texcoords) swTexCoord2fv(RLSW.array.texcoords + 2*i);
- if (RLSW.array.colors) swColor4ubv(RLSW.array.colors + 4*i);
- swVertex3fv(RLSW.array.positions + 3*i);
+ float u, v;
+ if (texcoords)
+ {
+ int idx = 2*i;
+ u = texcoords[idx];
+ v = texcoords[idx + 1];
+ }
+ else
+ {
+ u = defaultTexcoord[0];
+ v = defaultTexcoord[1];
+ }
+
+ float texcoord[2];
+ texcoord[0] = texMatrix[0]*u + texMatrix[4]*v + texMatrix[12];
+ texcoord[1] = texMatrix[1]*u + texMatrix[5]*v + texMatrix[13];
+
+ float color[4] = {
+ defaultColor[0],
+ defaultColor[1],
+ defaultColor[2],
+ defaultColor[3]
+ };
+
+ if (colors)
+ {
+ int idx = 4*i;
+ color[0] *= (float)colors[idx]*SW_INV_255;
+ color[1] *= (float)colors[idx + 1]*SW_INV_255;
+ color[2] *= (float)colors[idx + 2]*SW_INV_255;
+ color[3] *= (float)colors[idx + 3]*SW_INV_255;
+ }
+
+ int idx = 3*i;
+ float position[4] = {
+ positions[idx],
+ positions[idx + 1],
+ positions[idx + 2],
+ 1.0f
+ };
+
+ sw_immediate_push_vertex(position, color, texcoord);
+ }
+ }
+ swEnd();
+}
+
+void swDrawElements(SWdraw mode, int count, int type, const void *indices)
+{
+ if (RLSW.array.positions == 0)
+ {
+ RLSW.errCode = SW_INVALID_OPERATION;
+ return;
+ }
+
+ if (count < 0)
+ {
+ RLSW.errCode = SW_INVALID_VALUE;
+ return;
+ }
+
+ const uint8_t *indicesUb = NULL;
+ const uint16_t *indicesUs = NULL;
+ const uint32_t *indicesUi = NULL;
+
+ switch (type)
+ {
+ case SW_UNSIGNED_BYTE:
+ indicesUb = (const uint8_t *)indices;
+ break;
+ case SW_UNSIGNED_SHORT:
+ indicesUs = (const uint16_t *)indices;
+ break;
+ case SW_UNSIGNED_INT:
+ indicesUi = (const uint32_t *)indices;
+ break;
+ default:
+ RLSW.errCode = SW_INVALID_ENUM;
+ return;
+ }
+
+ swBegin(mode);
+ {
+ const float *texMatrix = RLSW.stackTexture[RLSW.stackTextureCounter - 1];
+ const float *defaultTexcoord = RLSW.current.texcoord;
+ const float *defaultColor = RLSW.current.color;
+
+ const float *positions = RLSW.array.positions;
+ const float *texcoords = RLSW.array.texcoords;
+ const uint8_t *colors = RLSW.array.colors;
+
+ for (int i = 0; i < count; i++)
+ {
+ int index = indicesUb? indicesUb[i] :
+ (indicesUs? indicesUs[i] : indicesUi[i]);
+
+ float u, v;
+ if (texcoords)
+ {
+ int idx = 2*index;
+ u = texcoords[idx];
+ v = texcoords[idx + 1];
+ }
+ else
+ {
+ u = defaultTexcoord[0];
+ v = defaultTexcoord[1];
+ }
+
+ float texcoord[2];
+ texcoord[0] = texMatrix[0]*u + texMatrix[4]*v + texMatrix[12];
+ texcoord[1] = texMatrix[1]*u + texMatrix[5]*v + texMatrix[13];
+
+ float color[4] = {
+ defaultColor[0],
+ defaultColor[1],
+ defaultColor[2],
+ defaultColor[3]
+ };
+
+ if (colors)
+ {
+ int idx = 4*index;
+ color[0] *= (float)colors[idx]*SW_INV_255;
+ color[1] *= (float)colors[idx + 1]*SW_INV_255;
+ color[2] *= (float)colors[idx + 2]*SW_INV_255;
+ color[3] *= (float)colors[idx + 3]*SW_INV_255;
+ }
+
+ int idx = 3*index;
+ float position[4] = {
+ positions[idx],
+ positions[idx + 1],
+ positions[idx + 2],
+ 1.0f
+ };
+
+ sw_immediate_push_vertex(position, color, texcoord);
}
}
swEnd();
@@ -4801,17 +4673,14 @@ void swDeleteTextures(int count, uint32_t *textures)
continue;
}
- if (RLSW.loadedTextures[textures[i]].copy)
- {
- SW_FREE(RLSW.loadedTextures[textures[i]].pixels.ptr);
- }
+ SW_FREE(RLSW.loadedTextures[textures[i]].pixels);
- RLSW.loadedTextures[textures[i]].pixels.cptr = NULL;
+ RLSW.loadedTextures[textures[i]].pixels = NULL;
RLSW.freeTextureIds[RLSW.freeTextureIdCount++] = textures[i];
}
}
-void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void *data)
+void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data)
{
uint32_t id = RLSW.currentTexture;
@@ -4831,33 +4700,27 @@ void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy
sw_texture_t *texture = &RLSW.loadedTextures[id];
- if (copy)
+ int size = width*height;
+ texture->pixels = SW_MALLOC(4*size);
+
+ if (texture->pixels == NULL)
{
- int bytes = sw_get_pixel_bytes(pixelFormat);
- int size = bytes*width*height;
- texture->pixels.ptr = SW_MALLOC(size);
-
- if (texture->pixels.ptr == NULL)
- {
- RLSW.errCode = SW_STACK_OVERFLOW; // WARING: Out of memory...
- return;
- }
-
- for (int i = 0; i < size; i++)
- {
- ((uint8_t *)texture->pixels.ptr)[i] = ((uint8_t *)data)[i];
- }
+ RLSW.errCode = SW_STACK_OVERFLOW; // WARNING: Out of memory...
+ return;
+ }
+
+ for (int i = 0; i < size; i++)
+ {
+ uint32_t *dst = &((uint32_t*)texture->pixels)[i];
+ sw_get_pixel((uint8_t*)dst, data, i, pixelFormat);
}
- else texture->pixels.cptr = data;
texture->width = width;
texture->height = height;
texture->wMinus1 = width - 1;
texture->hMinus1 = height - 1;
- texture->format = pixelFormat;
texture->tx = 1.0f/width;
texture->ty = 1.0f/height;
- texture->copy = copy;
}
void swTexParameteri(int param, int value)
@@ -4882,7 +4745,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->minFilter = value;
+ texture->minFilter = (SWfilter)value;
} break;
case SW_TEXTURE_MAG_FILTER:
{
@@ -4892,7 +4755,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->magFilter = value;
+ texture->magFilter = (SWfilter)value;
} break;
case SW_TEXTURE_WRAP_S:
{
@@ -4902,7 +4765,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->sWrap = value;
+ texture->sWrap = (SWwrap)value;
} break;
case SW_TEXTURE_WRAP_T:
{
@@ -4912,7 +4775,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->tWrap = value;
+ texture->tWrap = (SWwrap)value;
} break;
default: RLSW.errCode = SW_INVALID_ENUM; break;
}
@@ -4926,7 +4789,7 @@ void swBindTexture(uint32_t id)
return;
}
- if (RLSW.loadedTextures[id].pixels.cptr == NULL)
+ if (RLSW.loadedTextures[id].pixels == NULL)
{
RLSW.errCode = SW_INVALID_OPERATION;
return;
diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c
index 47dcce32b..88b3b4bba 100644
--- a/src/platforms/rcore_android.c
+++ b/src/platforms/rcore_android.c
@@ -623,10 +623,9 @@ double GetTime(void)
}
// 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.
-// Ref: https://github.com/raysan5/raylib/issues/686
+// 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
@@ -687,7 +686,7 @@ void SetMouseCursor(int cursor)
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
}
-// Get physical key name.
+// Get physical key name
const char *GetKeyName(int key)
{
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
@@ -748,9 +747,9 @@ void PollInputEvents(void)
// Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
- // NOTE: Allow closing the window in case a configuration change happened.
+ // NOTE: Allow closing the window in case a configuration change happened
// The android_main function should be allowed to return to its caller in order for the
- // Android OS to relaunch the activity.
+ // Android OS to relaunch the activity
if (platform.app->destroyRequested != 0)
{
CORE.Window.shouldClose = true;
@@ -796,10 +795,10 @@ int InitPlatform(void)
//AConfiguration_getScreenLong(platform.app->config);
// Set some default window flags
- CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false
- CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // false
- CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true
- CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN); // false
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // false
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // true
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // false
//----------------------------------------------------------------------------
// Initialize App command system
@@ -829,13 +828,13 @@ int InitPlatform(void)
// Wait for window to be initialized (display and context)
while (!CORE.Window.ready)
{
- // Process events until we reach TIMEOUT, which indicates no more events queued.
+ // Process events until we reach TIMEOUT, which indicates no more events queued
while ((pollResult = ALooper_pollOnce(0, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT))
{
// Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
- // NOTE: It's highly likely destroyRequested will never be non-zero at the start of the activity lifecycle.
+ // NOTE: It's highly likely destroyRequested will never be non-zero at the start of the activity lifecycle
//if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true;
}
}
@@ -869,8 +868,9 @@ void ClosePlatform(void)
platform.device = EGL_NO_DISPLAY;
}
- // NOTE: Reset global state in case the activity is being relaunched.
- if (platform.app->destroyRequested != 0) {
+ // NOTE: Reset global state in case the activity is being relaunched
+ if (platform.app->destroyRequested != 0)
+ {
CORE = (CoreData){0};
platform = (PlatformData){0};
}
@@ -883,11 +883,11 @@ void ClosePlatform(void)
static int InitGraphicsDevice(void)
{
CORE.Window.fullscreen = true;
- CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
EGLint samples = 0;
EGLint sampleBuffer = 0;
- if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
{
samples = 4;
sampleBuffer = 1;
@@ -925,7 +925,7 @@ static int InitGraphicsDevice(void)
// 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.
+ // 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 -1;
}
@@ -992,7 +992,7 @@ static int InitGraphicsDevice(void)
CORE.Window.ready = true;
- if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) MinimizeWindow();
return 0;
}
@@ -1059,7 +1059,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
// Set font white rectangle for shapes drawing, so shapes and text can be batched together
// WARNING: rshapes module is required, if not available, default internal white rectangle is used
Rectangle rec = GetFontDefault().recs[95];
- if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
{
// NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
@@ -1081,41 +1081,26 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
-
- // TODO: GPU assets reload in case of lost focus (lost context)
- // NOTE: This problem has been solved just unbinding and rebinding context from display
- /*
- if (assetsReloadRequired)
- {
- for (int i = 0; i < assetCount; i++)
- {
- // TODO: Unload old asset if required
-
- // Load texture again to pointed texture
- (*textureAsset + i) = LoadTexture(assetPath[i]);
- }
- }
- */
}
}
} break;
case APP_CMD_GAINED_FOCUS:
{
platform.appEnabled = true;
- CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
//ResumeMusicStream();
} break;
case APP_CMD_PAUSE: break;
case APP_CMD_LOST_FOCUS:
{
platform.appEnabled = false;
- CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
//PauseMusicStream();
} break;
case APP_CMD_TERM_WINDOW:
{
// Detach OpenGL context and destroy display surface
- // NOTE 1: This case is used when the user exits the app without closing it. We detach the context to ensure everything is recoverable upon resuming.
+ // NOTE 1: This case is used when the user exits the app without closing it, context is detached to ensure everything is recoverable upon resuming
// NOTE 2: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...)
// NOTE 3: In some cases (too many context loaded), OS could unload context automatically... :(
if (platform.device != EGL_NO_DISPLAY)
@@ -1179,16 +1164,16 @@ static GamepadButton AndroidTranslateGamepadButton(int button)
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
{
// If additional inputs are required check:
- // https://developer.android.com/ndk/reference/group/input
- // https://developer.android.com/training/game-controllers/controller-input
+ // Ref: https://developer.android.com/ndk/reference/group/input
+ // Ref: https://developer.android.com/training/game-controllers/controller-input
int type = AInputEvent_getType(event);
int source = AInputEvent_getSource(event);
if (type == AINPUT_EVENT_TYPE_MOTION)
{
- if (((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK) ||
- ((source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD))
+ if (FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
+ FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD))
{
// For now we'll assume a single gamepad which we "detect" on its input event
CORE.Input.Gamepad.ready[0] = true;
@@ -1251,8 +1236,8 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
//int32_t AKeyEvent_getMetaState(event);
// Handle gamepad button presses and releases
- if (((source & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK) ||
- ((source & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD))
+ if (FLAG_IS_SET(source, AINPUT_SOURCE_JOYSTICK) ||
+ FLAG_IS_SET(source, AINPUT_SOURCE_GAMEPAD))
{
// For now we'll assume a single gamepad which we "detect" on its input event
CORE.Input.Gamepad.ready[0] = true;
@@ -1290,7 +1275,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
{
// Let the OS handle input to avoid app stuck. Behaviour: CMD_PAUSE -> CMD_SAVE_STATE -> CMD_STOP -> CMD_CONFIG_CHANGED -> CMD_LOST_FOCUS
// Resuming Behaviour: CMD_START -> CMD_RESUME -> CMD_CONFIG_CHANGED -> CMD_CONFIG_CHANGED -> CMD_GAINED_FOCUS
- // It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected.
+ // It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected
// NOTE: AndroidManifest.xml must have
// Before that change, activity was calling CMD_TERM_WINDOW and CMD_DESTROY when locking mobile, so that was not a normal behaviour
return 0;
@@ -1419,15 +1404,9 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
if (CORE.Input.Touch.pointCount > 0) CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 1;
else CORE.Input.Touch.currentTouchState[MOUSE_BUTTON_LEFT] = 0;
- // Stores the previous position of touch[0] only while it's active to calculate the delta.
- if (flags == AMOTION_EVENT_ACTION_MOVE)
- {
- CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
- }
- else
- {
- CORE.Input.Mouse.previousPosition = CORE.Input.Touch.position[0];
- }
+ // Stores the previous position of touch[0] only while it's active to calculate the delta
+ if (flags == AMOTION_EVENT_ACTION_MOVE) CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
+ else CORE.Input.Mouse.previousPosition = CORE.Input.Touch.position[0];
// Map touch[0] as mouse input for convenience
CORE.Input.Mouse.currentPosition = CORE.Input.Touch.position[0];
diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c
index 5dde1df67..a56e1c683 100644
--- a/src/platforms/rcore_desktop_glfw.c
+++ b/src/platforms/rcore_desktop_glfw.c
@@ -78,28 +78,27 @@
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include // Required for: timespec, nanosleep(), select() - POSIX
-#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
+ #if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
// Set appropriate expose macros based on available backends
- #if defined(_GLFW_X11)
- #define GLFW_EXPOSE_NATIVE_X11
- #define Font X11Font // Hack to fix 'Font' name collision
+ #if defined(_GLFW_X11)
+ #define GLFW_EXPOSE_NATIVE_X11
+ #define Font X11Font // Hack to fix 'Font' name collision
// The definition and references to the X11 Font type will be replaced by 'X11Font'
// Works as long as the current file consistently references any X11 Font as X11Font
// Since it is never referenced (as of writing), this does not pose an issue
- #endif
+ #endif
- #if defined(_GLFW_WAYLAND)
- #define GLFW_EXPOSE_NATIVE_WAYLAND
- #endif
+ #if defined(_GLFW_WAYLAND)
+ #define GLFW_EXPOSE_NATIVE_WAYLAND
+ #endif
- #include "GLFW/glfw3native.h" // Include native header only once, regardless of how many backends are defined
+ #include "GLFW/glfw3native.h" // Include native header only once, regardless of how many backends are defined
// Required for: glfwGetX11Window() and glfwGetWaylandWindow()
-
- #if defined(_GLFW_X11) // Clean up X11-specific hacks
- #undef Font // Revert hack and allow normal raylib Font usage
+ #if defined(_GLFW_X11) // Clean up X11-specific hacks
+ #undef Font // Revert hack and allow normal raylib Font usage
+ #endif
#endif
#endif
-#endif
#if defined(__APPLE__)
#include // Required for: usleep()
@@ -195,14 +194,14 @@ void ToggleFullscreen(void)
TRACELOG(LOG_WARNING, "GLFW: Failed to get monitor");
CORE.Window.fullscreen = false;
- CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
glfwSetWindowMonitor(platform.handle, NULL, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
}
else
{
CORE.Window.fullscreen = true;
- CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
glfwSetWindowMonitor(platform.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
}
@@ -211,7 +210,7 @@ void ToggleFullscreen(void)
else
{
CORE.Window.fullscreen = false;
- CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
+ 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);
@@ -222,7 +221,7 @@ void ToggleFullscreen(void)
// 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
- if (CORE.Window.flags & FLAG_VSYNC_HINT) glfwSwapInterval(1);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) glfwSwapInterval(1);
}
// Toggle borderless windowed mode
@@ -256,7 +255,7 @@ void ToggleBorderlessWindowed(void)
// Set undecorated flag
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE);
- CORE.Window.flags |= FLAG_WINDOW_UNDECORATED;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
// Get monitor position and size
int monitorPosX = 0;
@@ -272,13 +271,13 @@ void ToggleBorderlessWindowed(void)
// Refocus window
glfwFocusWindow(platform.handle);
- CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
else
{
// Remove undecorated flag
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
- CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED;
+ 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
@@ -288,7 +287,7 @@ void ToggleBorderlessWindowed(void)
// Refocus window
glfwFocusWindow(platform.handle);
- CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
+ 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;
@@ -305,7 +304,7 @@ void MaximizeWindow(void)
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
{
glfwMaximizeWindow(platform.handle);
- CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
}
}
@@ -323,8 +322,8 @@ void RestoreWindow(void)
{
// Restores the specified window if it was previously iconified (minimized) or maximized
glfwRestoreWindow(platform.handle);
- CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED;
- CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
}
}
@@ -337,109 +336,109 @@ void SetWindowState(unsigned int flags)
// NOTE: In most cases the functions already change the flags internally
// State change: FLAG_VSYNC_HINT
- if (((CORE.Window.flags & FLAG_VSYNC_HINT) != (flags & FLAG_VSYNC_HINT)) && ((flags & FLAG_VSYNC_HINT) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT) != FLAG_IS_SET(flags, FLAG_VSYNC_HINT)) && FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
{
glfwSwapInterval(1);
- CORE.Window.flags |= FLAG_VSYNC_HINT;
+ FLAG_SET(CORE.Window.flags, FLAG_VSYNC_HINT);
}
// State change: FLAG_BORDERLESS_WINDOWED_MODE
// NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running
- if (((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) != (flags & FLAG_BORDERLESS_WINDOWED_MODE)) && ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE) != FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE)) && FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function
}
// State change: FLAG_FULLSCREEN_MODE
- if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) != (flags & FLAG_FULLSCREEN_MODE) && ((flags & FLAG_FULLSCREEN_MODE) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE) != FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE)) && FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
{
ToggleFullscreen(); // NOTE: Window state flag updated inside function
}
// State change: FLAG_WINDOW_RESIZABLE
- if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != (flags & FLAG_WINDOW_RESIZABLE)) && ((flags & FLAG_WINDOW_RESIZABLE) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)) && FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
{
glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_TRUE);
- CORE.Window.flags |= FLAG_WINDOW_RESIZABLE;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE);
}
// State change: FLAG_WINDOW_UNDECORATED
- if (((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) != (flags & FLAG_WINDOW_UNDECORATED)) && (flags & FLAG_WINDOW_UNDECORATED))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED) != FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED)) && FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
{
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE);
- CORE.Window.flags |= FLAG_WINDOW_UNDECORATED;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
}
// State change: FLAG_WINDOW_HIDDEN
- if (((CORE.Window.flags & FLAG_WINDOW_HIDDEN) != (flags & FLAG_WINDOW_HIDDEN)) && ((flags & FLAG_WINDOW_HIDDEN) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN) != FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN)) && FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
{
glfwHideWindow(platform.handle);
- CORE.Window.flags |= FLAG_WINDOW_HIDDEN;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
}
// State change: FLAG_WINDOW_MINIMIZED
- if (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) != (flags & FLAG_WINDOW_MINIMIZED)) && ((flags & FLAG_WINDOW_MINIMIZED) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) != FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)) && FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
{
//GLFW_ICONIFIED
MinimizeWindow(); // NOTE: Window state flag updated inside function
}
// State change: FLAG_WINDOW_MAXIMIZED
- if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) != (flags & FLAG_WINDOW_MAXIMIZED)) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED) != FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)) && FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
{
//GLFW_MAXIMIZED
MaximizeWindow(); // NOTE: Window state flag updated inside function
}
// State change: FLAG_WINDOW_UNFOCUSED
- if (((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) != (flags & FLAG_WINDOW_UNFOCUSED)) && ((flags & FLAG_WINDOW_UNFOCUSED) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED) != FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED)) && FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
{
glfwSetWindowAttrib(platform.handle, GLFW_FOCUS_ON_SHOW, GLFW_FALSE);
- CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
}
// State change: FLAG_WINDOW_TOPMOST
- if (((CORE.Window.flags & FLAG_WINDOW_TOPMOST) != (flags & FLAG_WINDOW_TOPMOST)) && ((flags & FLAG_WINDOW_TOPMOST) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST) != FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST)) && FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
{
glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_TRUE);
- CORE.Window.flags |= FLAG_WINDOW_TOPMOST;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST);
}
// State change: FLAG_WINDOW_ALWAYS_RUN
- if (((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) != (flags & FLAG_WINDOW_ALWAYS_RUN)) && ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN) != FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) && FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
{
- CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
}
// The following states can not be changed after window creation
// State change: FLAG_WINDOW_TRANSPARENT
- if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) != (flags & FLAG_WINDOW_TRANSPARENT)) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT) != FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT)) && FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
{
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
}
// State change: FLAG_WINDOW_HIGHDPI
- if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) != (flags & FLAG_WINDOW_HIGHDPI)) && ((flags & FLAG_WINDOW_HIGHDPI) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI) != FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI)) && FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
{
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
}
// State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
- if (((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) != (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)) && ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH) != FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) && FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
{
glfwSetWindowAttrib(platform.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
- CORE.Window.flags |= FLAG_WINDOW_MOUSE_PASSTHROUGH;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH);
}
// State change: FLAG_MSAA_4X_HINT
- if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) != (flags & FLAG_MSAA_4X_HINT)) && ((flags & FLAG_MSAA_4X_HINT) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT) != FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT)) && FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
{
TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
}
// State change: FLAG_INTERLACED_HINT
- if (((CORE.Window.flags & FLAG_INTERLACED_HINT) != (flags & FLAG_INTERLACED_HINT)) && ((flags & FLAG_INTERLACED_HINT) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_INTERLACED_HINT) != FLAG_IS_SET(flags, FLAG_INTERLACED_HINT)) && FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
{
TRACELOG(LOG_WARNING, "WINDOW: Interlaced mode can only be configured before window initialization");
}
@@ -452,107 +451,107 @@ void ClearWindowState(unsigned int flags)
// NOTE: In most cases the functions already change the flags internally
// State change: FLAG_VSYNC_HINT
- if (((CORE.Window.flags & FLAG_VSYNC_HINT) > 0) && ((flags & FLAG_VSYNC_HINT) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) && (FLAG_IS_SET(flags, FLAG_VSYNC_HINT)))
{
glfwSwapInterval(0);
- CORE.Window.flags &= ~FLAG_VSYNC_HINT;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_VSYNC_HINT);
}
// State change: FLAG_BORDERLESS_WINDOWED_MODE
// NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running
- if (((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0) && ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0))
+ 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
}
// State change: FLAG_FULLSCREEN_MODE
- if (((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) && ((flags & FLAG_FULLSCREEN_MODE) > 0))
+ 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
}
// State change: FLAG_WINDOW_RESIZABLE
- if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) && ((flags & FLAG_WINDOW_RESIZABLE) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) && (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)))
{
glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_FALSE);
- CORE.Window.flags &= ~FLAG_WINDOW_RESIZABLE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_RESIZABLE);
}
// State change: FLAG_WINDOW_HIDDEN
- if (((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) && ((flags & FLAG_WINDOW_HIDDEN) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) && (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN)))
{
glfwShowWindow(platform.handle);
- CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
}
// State change: FLAG_WINDOW_MINIMIZED
- if (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((flags & FLAG_WINDOW_MINIMIZED) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)))
{
RestoreWindow(); // NOTE: Window state flag updated inside function
}
// State change: FLAG_WINDOW_MAXIMIZED
- if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)))
{
RestoreWindow(); // NOTE: Window state flag updated inside function
}
// State change: FLAG_WINDOW_UNDECORATED
- if (((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) && ((flags & FLAG_WINDOW_UNDECORATED) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED)))
{
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
- CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
}
// State change: FLAG_WINDOW_UNFOCUSED
- if (((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) && ((flags & FLAG_WINDOW_UNFOCUSED) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED)))
{
glfwSetWindowAttrib(platform.handle, GLFW_FOCUS_ON_SHOW, GLFW_TRUE);
- CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
}
// State change: FLAG_WINDOW_TOPMOST
- if (((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) && ((flags & FLAG_WINDOW_TOPMOST) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST)) && (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST)))
{
glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_FALSE);
- CORE.Window.flags &= ~FLAG_WINDOW_TOPMOST;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_TOPMOST);
}
// State change: FLAG_WINDOW_ALWAYS_RUN
- if (((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) > 0) && ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN)) && (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)))
{
- CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
}
// The following states can not be changed after window creation
// State change: FLAG_WINDOW_TRANSPARENT
- if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) && (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT)))
{
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
}
// State change: FLAG_WINDOW_HIGHDPI
- if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) && ((flags & FLAG_WINDOW_HIGHDPI) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) && (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI)))
{
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
}
// State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
- if (((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) && ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) && (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)))
{
glfwSetWindowAttrib(platform.handle, GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE);
- CORE.Window.flags &= ~FLAG_WINDOW_MOUSE_PASSTHROUGH;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH);
}
// State change: FLAG_MSAA_4X_HINT
- if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) > 0) && ((flags & FLAG_MSAA_4X_HINT) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) && (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT)))
{
TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
}
// State change: FLAG_INTERLACED_HINT
- if (((CORE.Window.flags & FLAG_INTERLACED_HINT) > 0) && ((flags & FLAG_INTERLACED_HINT) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_INTERLACED_HINT)) && (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT)))
{
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
}
@@ -1070,6 +1069,7 @@ void EnableCursor(void)
if (glfwRawMouseMotionSupported()) glfwSetInputMode(platform.handle, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE);
+ CORE.Input.Mouse.cursorHidden = false;
CORE.Input.Mouse.cursorLocked = false;
}
@@ -1083,6 +1083,7 @@ void DisableCursor(void)
if (glfwRawMouseMotionSupported()) glfwSetInputMode(platform.handle, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
+ CORE.Input.Mouse.cursorHidden = true;
CORE.Input.Mouse.cursorLocked = true;
}
@@ -1218,9 +1219,9 @@ void PollInputEvents(void)
// Map touch position to mouse position for convenience
// WARNING: If the target desktop device supports touch screen, this behaviour should be reviewed!
- // TODO: GLFW does not support multi-touch input just yet
- // https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch
- // https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages
+ // TODO: GLFW does not support multi-touch input yet
+ // Ref: https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch
+ // Ref: https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
// Check if gamepads are ready
@@ -1332,7 +1333,7 @@ void PollInputEvents(void)
// Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform()
// We need to provide these because GLFWallocator expects function pointers with specific signatures
// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch
-// https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
+// Ref: https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
static void *AllocateWrapper(size_t size, void *user)
{
(void)user;
@@ -1391,31 +1392,31 @@ int InitPlatform(void)
unsigned int requestedWindowFlags = CORE.Window.flags;
// Check window creation flags
- if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true;
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) CORE.Window.fullscreen = true;
- if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Visible window
+ 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
- if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window
else glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); // Decorated window
- if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // Resizable window
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // Resizable window
else glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // Avoid window being resizable
// Disable FLAG_WINDOW_MINIMIZED, not supported on initialization
- if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED;
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
// Disable FLAG_WINDOW_MAXIMIZED, not supported on initialization
- if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
- if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE);
else glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
- if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST)) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
else glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
// NOTE: Some GLFW flags are not supported on HTML5
- if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer
+ 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
@@ -1428,7 +1429,7 @@ int InitPlatform(void)
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
#endif
- if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
+ 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__)
@@ -1445,10 +1446,10 @@ int InitPlatform(void)
else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
// Mouse passthrough
- if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
else glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_FALSE);
- if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
{
// NOTE: MSAA is only enabled for main framebuffer, not user-created FBOs
TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4");
@@ -1590,8 +1591,8 @@ int InitPlatform(void)
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;
+ int creationWidth = (CORE.Window.screen.width != 0)? CORE.Window.screen.width : 1;
+ int creationHeight = (CORE.Window.screen.height != 0)? CORE.Window.screen.height : 1;
platform.handle = glfwCreateWindow(creationWidth, creationHeight, (CORE.Window.title != 0)? CORE.Window.title : " ", NULL, NULL);
if (!platform.handle)
@@ -1640,7 +1641,7 @@ int InitPlatform(void)
// 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
// to be activated on web platforms since VSync is enforced there
- if (CORE.Window.flags & FLAG_VSYNC_HINT)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT))
{
// WARNING: It seems to hit a critical render path in Intel HD Graphics
glfwSwapInterval(1);
@@ -1650,7 +1651,7 @@ int InitPlatform(void)
int fbWidth = CORE.Window.screen.width;
int fbHeight = CORE.Window.screen.height;
- if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
+ 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);
@@ -1682,7 +1683,7 @@ int InitPlatform(void)
return -1;
}
- if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
+ 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; }
@@ -1726,7 +1727,7 @@ int InitPlatform(void)
glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);
glfwSetDropCallback(platform.handle, WindowDropCallback);
- if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
}
@@ -1747,7 +1748,12 @@ int InitPlatform(void)
{
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
// we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1)
- if (glfwJoystickPresent(i)) strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
+ if (glfwJoystickPresent(i))
+ {
+ CORE.Input.Gamepad.ready[i] = true;
+ CORE.Input.Gamepad.axisCount[i] = GLFW_GAMEPAD_AXIS_LAST + 1;
+ strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
+ }
}
//----------------------------------------------------------------------------
@@ -1847,22 +1853,22 @@ static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float s
// GLFW3 WindowIconify Callback, runs when window is minimized/restored
static void WindowIconifyCallback(GLFWwindow *window, int iconified)
{
- if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified
- else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored
+ if (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
static void WindowMaximizeCallback(GLFWwindow *window, int maximized)
{
- if (maximized) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // The window was maximized
- else CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; // The window was restored
+ 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
static void WindowFocusCallback(GLFWwindow *window, int focused)
{
- if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused
- else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus
+ 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
@@ -1905,8 +1911,8 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
else if (action == GLFW_REPEAT) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
// WARNING: Check if CAPS/NUM key modifiers are enabled and force down state for those keys
- if (((key == KEY_CAPS_LOCK) && ((mods & GLFW_MOD_CAPS_LOCK) > 0)) ||
- ((key == KEY_NUM_LOCK) && ((mods & GLFW_MOD_NUM_LOCK) > 0))) CORE.Input.Keyboard.currentKeyState[key] = 1;
+ if (((key == KEY_CAPS_LOCK) && (FLAG_IS_SET(mods, GLFW_MOD_CAPS_LOCK))) ||
+ ((key == KEY_NUM_LOCK) && (FLAG_IS_SET(mods, GLFW_MOD_NUM_LOCK)))) CORE.Input.Keyboard.currentKeyState[key] = 1;
// Check if there is space available in the key queue
if ((CORE.Input.Keyboard.keyPressedQueueCount < MAX_KEY_PRESSED_QUEUE) && (action == GLFW_PRESS))
diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c
index 86842140d..a1b13856b 100644
--- a/src/platforms/rcore_desktop_rgfw.c
+++ b/src/platforms/rcore_desktop_rgfw.c
@@ -303,7 +303,7 @@ void ToggleFullscreen(void)
platform.mon = RGFW_window_getMonitor(platform.window);
CORE.Window.fullscreen = true;
- CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
RGFW_monitor_scaleToWindow(platform.mon, platform.window);
RGFW_window_setFullscreen(platform.window, 1);
@@ -311,7 +311,7 @@ void ToggleFullscreen(void)
else
{
CORE.Window.fullscreen = false;
- CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
if (platform.mon.mode.area.w)
{
@@ -330,7 +330,7 @@ void ToggleFullscreen(void)
// 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
- if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) RGFW_window_swapInterval(platform.window, 1);
}
// Toggle borderless windowed mode
@@ -372,7 +372,7 @@ void MinimizeWindow(void)
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
- if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
RGFW_window_restore(platform.window);
}
@@ -382,72 +382,72 @@ void SetWindowState(unsigned int flags)
{
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
- CORE.Window.flags |= flags;
+ FLAG_SET(CORE.Window.flags, flags);
- if (flags & FLAG_VSYNC_HINT)
+ if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
{
RGFW_window_swapInterval(platform.window, 1);
}
- if (flags & FLAG_FULLSCREEN_MODE)
+ if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
{
if (!CORE.Window.fullscreen) ToggleFullscreen();
}
- if (flags & FLAG_WINDOW_RESIZABLE)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
{
RGFW_window_setMaxSize(platform.window, RGFW_AREA(0, 0));
RGFW_window_setMinSize(platform.window, RGFW_AREA(0, 0));
}
- if (flags & FLAG_WINDOW_UNDECORATED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
{
RGFW_window_setBorder(platform.window, 0);
}
- if (flags & FLAG_WINDOW_HIDDEN)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
{
RGFW_window_hide(platform.window);
}
- if (flags & FLAG_WINDOW_MINIMIZED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
{
RGFW_window_minimize(platform.window);
}
- if (flags & FLAG_WINDOW_MAXIMIZED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
{
RGFW_window_maximize(platform.window);
}
- if (flags & FLAG_WINDOW_UNFOCUSED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
{
- CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
- platform.window->_flags &= ~RGFW_windowFocusOnShow;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
+ FLAG_CLEAR(platform.window->_flags, RGFW_windowFocusOnShow);
RGFW_window_setFlags(platform.window, platform.window->_flags);
}
- if (flags & FLAG_WINDOW_TOPMOST)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
{
RGFW_window_setFloating(platform.window, RGFW_TRUE);
}
- if (flags & FLAG_WINDOW_ALWAYS_RUN)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
{
- CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
}
- if (flags & FLAG_WINDOW_TRANSPARENT)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
{
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
}
- if (flags & FLAG_WINDOW_HIGHDPI)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
{
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
}
- if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
{
RGFW_window_setMousePassthrough(platform.window, 1);
}
- if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
+ if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
ToggleBorderlessWindowed();
}
- if (flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
{
RGFW_setGLHint(RGFW_glSamples, 4);
}
- if (flags & FLAG_INTERLACED_HINT)
+ if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
{
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
}
@@ -456,77 +456,72 @@ void SetWindowState(unsigned int flags)
// Clear window configuration state flags
void ClearWindowState(unsigned int flags)
{
- CORE.Window.flags &= ~flags;
+ FLAG_CLEAR(CORE.Window.flags, flags);
- if (flags & FLAG_VSYNC_HINT)
+ if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
{
RGFW_window_swapInterval(platform.window, 0);
}
- if (flags & FLAG_FULLSCREEN_MODE)
+ if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
{
if (CORE.Window.fullscreen) ToggleFullscreen();
}
- if (flags & FLAG_WINDOW_RESIZABLE)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
{
RGFW_window_setMaxSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h));
RGFW_window_setMinSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h));
}
- if (flags & FLAG_WINDOW_UNDECORATED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
{
RGFW_window_setBorder(platform.window, 1);
}
- if (flags & FLAG_WINDOW_HIDDEN)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
{
- if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
RGFW_window_show(platform.window);
}
- if (flags & FLAG_WINDOW_MINIMIZED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
{
- if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
RGFW_window_restore(platform.window);
}
- if (flags & FLAG_WINDOW_MAXIMIZED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
{
- if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) RGFW_window_focus(platform.window);
RGFW_window_restore(platform.window);
}
- if (flags & FLAG_WINDOW_UNFOCUSED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
{
RGFW_window_setFlags(platform.window, platform.window->_flags | RGFW_windowFocusOnShow);
- CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
}
- if (flags & FLAG_WINDOW_TOPMOST)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
{
RGFW_window_setFloating(platform.window, RGFW_FALSE);
}
- if (flags & FLAG_WINDOW_ALWAYS_RUN)
- {
- CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN;
- }
- if (flags & FLAG_WINDOW_TRANSPARENT)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
{
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
}
- if (flags & FLAG_WINDOW_HIGHDPI)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
{
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
}
- if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
{
RGFW_window_setMousePassthrough(platform.window, 0);
}
- if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
+ if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
if (CORE.Window.fullscreen) ToggleBorderlessWindowed();
}
- if (flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
{
RGFW_setGLHint(RGFW_glSamples, 0);
}
- if (flags & FLAG_INTERLACED_HINT)
+ if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
{
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
}
@@ -843,8 +838,9 @@ void EnableCursor(void)
// Set cursor position in the middle
SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
- RGFW_window_showMouse(platform.window, true);
- CORE.Input.Mouse.cursorHidden = false;
+ ShowCursor();
+
+ CORE.Input.Mouse.cursorLocked = true;
}
// Disables cursor (lock cursor)
@@ -853,6 +849,8 @@ void DisableCursor(void)
RGFW_disableCursor = true;
RGFW_window_mouseHold(platform.window, RGFW_AREA(0, 0));
HideCursor();
+
+ CORE.Input.Mouse.cursorLocked = true;
}
// Swap back buffer with front buffer (screen drawing)
@@ -872,17 +870,27 @@ double GetTime(void)
}
// 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.
-// Ref: https://github.com/raysan5/raylib/issues/686
+// NOTE: This function is only safe to use if you control the URL given
+// A user could craft a malicious string performing another action
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
{
- // TODO: Open URL implementation
+ char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
+#if defined(_WIN32)
+ sprintf(cmd, "explorer \"%s\"", url);
+#endif
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser
+#endif
+#if defined(__APPLE__)
+ sprintf(cmd, "open '%s'", url);
+#endif
+ int result = system(cmd);
+ if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
+ RL_FREE(cmd);
}
}
@@ -917,7 +925,7 @@ void SetMouseCursor(int cursor)
RGFW_window_setMouseStandard(platform.window, cursor);
}
-// Get physical key name.
+// Get physical key name
const char *GetKeyName(int key)
{
TRACELOG(LOG_WARNING, "GetKeyName() unsupported on target platform");
@@ -983,7 +991,7 @@ void PollInputEvents(void)
CORE.Window.resizedLastFrame = false;
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
- if (platform.window->_flags & RGFW_HOLD_MOUSE)
+ if (FLAG_IS_SET(platform.window->_flags, RGFW_HOLD_MOUSE))
{
CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
@@ -1062,18 +1070,18 @@ void PollInputEvents(void)
} break;
case RGFW_windowMaximized:
{
- CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // The window was maximized
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was maximized
} break;
case RGFW_windowMinimized:
{
- CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was iconified
} break;
case RGFW_windowRestored:
{
if (RGFW_window_isMaximized(platform.window))
- CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED; // The window was restored
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was restored
if (RGFW_window_isMinimized(platform.window))
- CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was restored
} break;
case RGFW_windowMoved:
{
@@ -1097,11 +1105,7 @@ void PollInputEvents(void)
CORE.Input.Keyboard.currentKeyState[key] = 1;
}
- // TODO: Put exitKey verification outside the switch?
- if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey])
- {
- CORE.Window.shouldClose = true;
- }
+ if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey]) CORE.Window.shouldClose = true;
// NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int)
// Check if there is space available in the queue
@@ -1159,7 +1163,7 @@ void PollInputEvents(void)
} break;
case RGFW_mousePosChanged:
{
- if (platform.window->_flags & RGFW_HOLD_MOUSE)
+ if (FLAG_IS_SET(platform.window->_flags, RGFW_HOLD_MOUSE))
{
CORE.Input.Mouse.currentPosition.x += (float)event->vector.x;
CORE.Input.Mouse.currentPosition.y += (float)event->vector.y;
@@ -1283,24 +1287,24 @@ int InitPlatform(void)
unsigned int flags = RGFW_windowCenter | RGFW_windowAllowDND;
// Check window creation flags
- if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{
CORE.Window.fullscreen = true;
- flags |= RGFW_windowFullscreen;
+ FLAG_SET(flags, RGFW_windowFullscreen);
}
- if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
CORE.Window.fullscreen = true;
- flags |= RGFW_windowedFullscreen;
+ FLAG_SET(flags, RGFW_windowedFullscreen);
}
- if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) flags |= RGFW_windowNoBorder;
- if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) flags |= RGFW_windowNoResize;
- if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) flags |= RGFW_windowTransparent;
- if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) flags |= RGFW_windowFullscreen;
- if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) flags |= RGFW_windowHide;
- if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= RGFW_windowMaximize;
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) FLAG_SET(flags, RGFW_windowNoBorder);
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) FLAG_SET(flags, RGFW_windowNoResize);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) FLAG_SET(flags, RGFW_windowTransparent);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) FLAG_SET(flags, RGFW_windowFullscreen);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(flags, RGFW_windowHide);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(flags, RGFW_windowMaximize);
// NOTE: Some OpenGL context attributes must be set before window creation
// Check selection OpenGL version
@@ -1320,9 +1324,9 @@ int InitPlatform(void)
RGFW_setGLHint(RGFW_glMinor, 3);
}
- if (CORE.Window.flags & FLAG_MSAA_4X_HINT) RGFW_setGLHint(RGFW_glSamples, 4);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT)) RGFW_setGLHint(RGFW_glSamples, 4);
- if (!(CORE.Window.flags & FLAG_WINDOW_UNFOCUSED)) flags |= RGFW_windowFocusOnShow | RGFW_windowFocus;
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_SET(flags, RGFW_windowFocusOnShow | RGFW_windowFocus);
platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags);
platform.mon.mode.area.w = 0;
@@ -1346,7 +1350,7 @@ int InitPlatform(void)
// If so, rcore_desktop_sdl should be updated too
//SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
- if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT)) RGFW_window_swapInterval(platform.window, 1);
RGFW_window_makeCurrent(platform.window);
// Check surface and context activation
diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c
index e135cd848..36235a6c8 100644
--- a/src/platforms/rcore_desktop_sdl.c
+++ b/src/platforms/rcore_desktop_sdl.c
@@ -463,21 +463,21 @@ void ToggleFullscreen(void)
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
{
- if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{
SDL_SetWindowFullscreen(platform.window, 0);
- CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
CORE.Window.fullscreen = false;
}
else
{
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN);
- CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
CORE.Window.fullscreen = true;
}
}
@@ -491,20 +491,20 @@ void ToggleBorderlessWindowed(void)
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
{
- if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
SDL_SetWindowFullscreen(platform.window, 0);
- CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
else
{
SDL_SetWindowFullscreen(platform.window, SDL_WINDOW_FULLSCREEN_DESKTOP);
- CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
@@ -514,14 +514,14 @@ void ToggleBorderlessWindowed(void)
void MaximizeWindow(void)
{
SDL_MaximizeWindow(platform.window);
- if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
}
// Set window state: minimized
void MinimizeWindow(void)
{
SDL_MinimizeWindow(platform.window);
- if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
}
// Restore window from being minimized/maximized
@@ -536,19 +536,19 @@ void SetWindowState(unsigned int flags)
{
if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
- CORE.Window.flags |= flags;
+ FLAG_SET(CORE.Window.flags, flags);
- if (flags & FLAG_VSYNC_HINT)
+ if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
{
SDL_GL_SetSwapInterval(1);
}
- if (flags & FLAG_FULLSCREEN_MODE)
+ if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
{
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
@@ -558,61 +558,61 @@ void SetWindowState(unsigned int flags)
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
}
- if (flags & FLAG_WINDOW_RESIZABLE)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
{
SDL_SetWindowResizable(platform.window, SDL_TRUE);
}
- if (flags & FLAG_WINDOW_UNDECORATED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
{
SDL_SetWindowBordered(platform.window, SDL_FALSE);
}
- if (flags & FLAG_WINDOW_HIDDEN)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
{
SDL_HideWindow(platform.window);
}
- if (flags & FLAG_WINDOW_MINIMIZED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
{
SDL_MinimizeWindow(platform.window);
}
- if (flags & FLAG_WINDOW_MAXIMIZED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
{
SDL_MaximizeWindow(platform.window);
}
- if (flags & FLAG_WINDOW_UNFOCUSED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
{
// NOTE: To be able to implement this part it seems that we should
// do it ourselves, via 'windows.h', 'X11/Xlib.h' or even 'Cocoa.h'
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
}
- if (flags & FLAG_WINDOW_TOPMOST)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
{
SDL_SetWindowAlwaysOnTop(platform.window, SDL_FALSE);
}
- if (flags & FLAG_WINDOW_ALWAYS_RUN)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
{
- CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
}
- if (flags & FLAG_WINDOW_TRANSPARENT)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
{
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL");
}
- if (flags & FLAG_WINDOW_HIGHDPI)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
{
// NOTE: Such a function does not seem to exist
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL");
}
- if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
{
//SDL_SetWindowGrab(platform.window, SDL_FALSE);
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_SDL");
}
- if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
+ if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
const int monitor = SDL_GetWindowDisplayIndex(platform.window);
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
@@ -621,12 +621,12 @@ void SetWindowState(unsigned int flags)
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
}
- if (flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
{
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); // Enable multisampling buffers
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); // Enable multisampling
}
- if (flags & FLAG_INTERLACED_HINT)
+ if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
{
TRACELOG(LOG_WARNING, "SetWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_SDL");
}
@@ -635,74 +635,69 @@ void SetWindowState(unsigned int flags)
// Clear window configuration state flags
void ClearWindowState(unsigned int flags)
{
- CORE.Window.flags &= ~flags;
+ FLAG_CLEAR(CORE.Window.flags, flags);
- if (flags & FLAG_VSYNC_HINT)
+ if (FLAG_IS_SET(flags, FLAG_VSYNC_HINT))
{
SDL_GL_SetSwapInterval(0);
}
- if (flags & FLAG_FULLSCREEN_MODE)
+ if (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE))
{
SDL_SetWindowFullscreen(platform.window, 0);
CORE.Window.fullscreen = false;
}
- if (flags & FLAG_WINDOW_RESIZABLE)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE))
{
SDL_SetWindowResizable(platform.window, SDL_FALSE);
}
- if (flags & FLAG_WINDOW_UNDECORATED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNDECORATED))
{
SDL_SetWindowBordered(platform.window, SDL_TRUE);
}
- if (flags & FLAG_WINDOW_HIDDEN)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIDDEN))
{
SDL_ShowWindow(platform.window);
}
- if (flags & FLAG_WINDOW_MINIMIZED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED))
{
SDL_RestoreWindow(platform.window);
}
- if (flags & FLAG_WINDOW_MAXIMIZED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED))
{
SDL_RestoreWindow(platform.window);
}
- if (flags & FLAG_WINDOW_UNFOCUSED)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_UNFOCUSED))
{
//SDL_RaiseWindow(platform.window);
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_UNFOCUSED is not supported on PLATFORM_DESKTOP_SDL");
}
- if (flags & FLAG_WINDOW_TOPMOST)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TOPMOST))
{
SDL_SetWindowAlwaysOnTop(platform.window, SDL_FALSE);
}
- if (flags & FLAG_WINDOW_ALWAYS_RUN)
- {
- CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN;
- }
- if (flags & FLAG_WINDOW_TRANSPARENT)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_TRANSPARENT))
{
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL");
}
- if (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");
}
- if (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MOUSE_PASSTHROUGH))
{
//SDL_SetWindowGrab(platform.window, SDL_TRUE);
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_MOUSE_PASSTHROUGH is not supported on PLATFORM_DESKTOP_SDL");
}
- if (flags & FLAG_BORDERLESS_WINDOWED_MODE)
+ if (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
SDL_SetWindowFullscreen(platform.window, 0);
}
- if (flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT))
{
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); // Disable multisampling buffers
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); // Disable multisampling
}
- if (flags & FLAG_INTERLACED_HINT)
+ if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
{
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_INTERLACED_HINT is not supported on PLATFORM_DESKTOP_SDL");
}
@@ -838,7 +833,7 @@ void SetWindowMonitor(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
@@ -847,7 +842,7 @@ void SetWindowMonitor(int monitor)
// 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
// see commit https://github.com/libsdl-org/SDL/commit/3f5ef7dd422057edbcf3e736107e34be4b75d9ba
// 2. A workaround for SDL2 is leaving fullscreen, moving the window, then entering full screen again
- const bool wasFullscreen = ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)? true : false;
+ const bool wasFullscreen = (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))? true : false;
const int screenWidth = CORE.Window.screen.width;
const int screenHeight = CORE.Window.screen.height;
@@ -966,7 +961,7 @@ Vector2 GetMonitorPosition(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
@@ -994,7 +989,7 @@ int GetMonitorWidth(int monitor)
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
@@ -1015,7 +1010,7 @@ int GetMonitorHeight(int monitor)
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
@@ -1036,7 +1031,7 @@ int GetMonitorPhysicalWidth(int monitor)
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
@@ -1060,7 +1055,7 @@ int GetMonitorPhysicalHeight(int monitor)
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
@@ -1084,7 +1079,7 @@ int GetMonitorRefreshRate(int monitor)
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
@@ -1104,7 +1099,7 @@ const char *GetMonitorName(int monitor)
const int monitorCount = SDL_GetNumVideoDisplays();
#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
- if ((monitor > 0) && (monitor <= monitorCount))
+ if (SDL_GetDisplayProperties(monitor) != 0) // Returns 0 on failure, so a value other than zero indicates that the monitor id is valid
#else
if ((monitor >= 0) && (monitor < monitorCount))
#endif
@@ -1134,7 +1129,7 @@ Vector2 GetWindowScaleDPI(void)
#ifndef USING_VERSION_SDL3
// NOTE: SDL_GetWindowDisplayScale was only added on SDL3
- // see https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
+ // Ref: https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
// TODO: Implement the window scale factor calculation manually
TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
#else
@@ -1193,7 +1188,7 @@ Image GetClipboardImage(void)
size_t dataSize = 0;
void *fileData = NULL;
- for (int i = 0; i < SDL_arraysize(imageFormats); ++i)
+ for (int i = 0; i < SDL_arraysize(imageFormats); i++)
{
// NOTE: This pointer should be free with SDL_free() at some point
fileData = SDL_GetClipboardData(imageFormats[i], &dataSize);
@@ -1242,14 +1237,7 @@ void EnableCursor(void)
{
SDL_SetRelativeMouseMode(SDL_FALSE);
-#if defined(USING_VERSION_SDL3)
- // NOTE: SDL_ShowCursor() has been split into three functions:
- // SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()
- SDL_ShowCursor();
-#else
- SDL_ShowCursor(SDL_ENABLE);
-#endif
-
+ ShowCursor();
CORE.Input.Mouse.cursorLocked = false;
}
@@ -1258,6 +1246,7 @@ void DisableCursor(void)
{
SDL_SetRelativeMouseMode(SDL_TRUE);
+ HideCursor();
CORE.Input.Mouse.cursorLocked = true;
}
@@ -1406,11 +1395,11 @@ void PollInputEvents(void)
//-----------------------------------------------------------------------------
// WARNING: Indexes into this array are obtained by using SDL_Scancode values, not SDL_Keycode values
//const Uint8 *keys = SDL_GetKeyboardState(NULL);
- //for (int i = 0; i < 256; ++i) CORE.Input.Keyboard.currentKeyState[i] = keys[i];
+ //for (int i = 0; i < 256; i++) CORE.Input.Keyboard.currentKeyState[i] = keys[i];
CORE.Window.resizedLastFrame = false;
- if ((CORE.Window.eventWaiting) || (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) == 0)))
+ if ((CORE.Window.eventWaiting) || (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) && !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN)))
{
SDL_WaitEvent(NULL);
CORE.Time.previous = GetTime();
@@ -1436,8 +1425,10 @@ void PollInputEvents(void)
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
#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, you should make a copy of it. SDL_TEXTINPUTEVENT_TEXT_SIZE is no longer necessary and has been removed.
+ // 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,
+ // 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);
#else
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file);
@@ -1469,7 +1460,7 @@ void PollInputEvents(void)
// SDL3 states:
// The SDL_WINDOWEVENT_* events have been moved to top level events, and SDL_WINDOWEVENT has been removed
// In general, handling this change just means checking for the individual events instead of first checking for SDL_WINDOWEVENT
- // and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event.
+ // and then checking for window events. You can compare the event >= SDL_EVENT_WINDOW_FIRST and <= SDL_EVENT_WINDOW_LAST if you need to see whether it's a window event
case SDL_WINDOWEVENT:
{
switch (event.window.event)
@@ -1498,7 +1489,7 @@ void PollInputEvents(void)
#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
- if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED))
{
int borderTop = 0;
int borderLeft = 0;
@@ -1508,7 +1499,7 @@ void PollInputEvents(void)
SDL_Rect usableBounds;
SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(platform.window), &usableBounds);
- if ((width + borderLeft + borderRight != usableBounds.w) && (height + borderTop + borderBottom != usableBounds.h)) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
+ if ((width + borderLeft + borderRight != usableBounds.w) && (height + borderTop + borderBottom != usableBounds.h)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
}
#endif
} break;
@@ -1524,43 +1515,43 @@ void PollInputEvents(void)
case SDL_WINDOWEVENT_MINIMIZED:
{
- if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED;
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
} break;
case SDL_WINDOWEVENT_MAXIMIZED:
{
- if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) == 0) CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
} break;
case SDL_WINDOWEVENT_RESTORED:
{
- if ((SDL_GetWindowFlags(platform.window) & SDL_WINDOW_MINIMIZED) == 0)
+ if (!FLAG_IS_SET(SDL_GetWindowFlags(platform.window), SDL_WINDOW_MINIMIZED))
{
- if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED;
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
}
#ifdef USING_VERSION_SDL3
- if ((SDL_GetWindowFlags(platform.window) & SDL_WINDOW_MAXIMIZED) == 0)
+ if (!FLAG_IS_SET(SDL_GetWindowFlags(platform.window), SDL_WINDOW_MAXIMIZED))
{
- if ((CORE.Window.flags & SDL_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~SDL_WINDOW_MAXIMIZED;
+ if (FLAG_IS_SET(CORE.Window.flags, SDL_WINDOW_MAXIMIZED)) FLAG_CLEAR(CORE.Window.flags, SDL_WINDOW_MAXIMIZED);
}
#endif
} break;
case SDL_WINDOWEVENT_HIDDEN:
{
- if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) == 0) CORE.Window.flags |= FLAG_WINDOW_HIDDEN;
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
} break;
case SDL_WINDOWEVENT_SHOWN:
{
- if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN;
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN);
} break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
{
- if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
} break;
case SDL_WINDOWEVENT_FOCUS_LOST:
{
- if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0) CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED);
} break;
#ifndef USING_VERSION_SDL3
@@ -1573,7 +1564,7 @@ void PollInputEvents(void)
case SDL_KEYDOWN:
{
#if defined(USING_VERSION_SDL3)
- // SDL3 Migration: The following structures have been removed: * SDL_Keysym
+ // SDL3 Migration: The following structures have been removed: SDL_Keysym
KeyboardKey key = ConvertScancodeToKey(event.key.scancode);
#else
KeyboardKey key = ConvertScancodeToKey(event.key.keysym.scancode);
@@ -1593,11 +1584,9 @@ void PollInputEvents(void)
if (event.key.repeat) CORE.Input.Keyboard.keyRepeatInFrame[key] = 1;
- // TODO: Put exitKey verification outside the switch?
- if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey])
- {
- CORE.Window.shouldClose = true;
- }
+ // Check for registered exit key to request exit game loop on next iteration
+ if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey]) CORE.Window.shouldClose = true;
+
} break;
case SDL_KEYUP:
@@ -1708,7 +1697,7 @@ void PollInputEvents(void)
int jid = event.jdevice.which; // Joystick device index
// check if already added at InitPlatform
- for (int i = 0; i < MAX_GAMEPADS; ++i)
+ for (int i = 0; i < MAX_GAMEPADS; i++)
{
if (jid == platform.gamepadId[i])
{
@@ -1734,12 +1723,11 @@ void PollInputEvents(void)
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
memset(CORE.Input.Gamepad.name[nextAvailableSlot], 0, MAX_GAMEPAD_NAME_LENGTH);
- strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], SDL_GameControllerNameForIndex(nextAvailableSlot), MAX_GAMEPAD_NAME_LENGTH - 1);
- }
- else
- {
- TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
+ const char *controllerName = SDL_GameControllerNameForIndex(nextAvailableSlot);
+ if (controllerName != NULL) strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], controllerName, MAX_GAMEPAD_NAME_LENGTH - 1);
+ else strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], "noname", 6);
}
+ else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
}
} break;
case SDL_JOYDEVICEREMOVED:
@@ -1930,38 +1918,34 @@ int InitPlatform(void)
// Initialize graphic device: display/window and graphic context
//----------------------------------------------------------------------------
unsigned int flags = 0;
- flags |= SDL_WINDOW_SHOWN;
- flags |= SDL_WINDOW_INPUT_FOCUS;
- flags |= SDL_WINDOW_MOUSE_FOCUS;
- flags |= SDL_WINDOW_MOUSE_CAPTURE; // Window has mouse captured
+ FLAG_SET(flags, SDL_WINDOW_SHOWN);
+ FLAG_SET(flags, SDL_WINDOW_INPUT_FOCUS);
+ FLAG_SET(flags, SDL_WINDOW_MOUSE_FOCUS);
+ FLAG_SET(flags, SDL_WINDOW_MOUSE_CAPTURE); // Window has mouse captured
// Check window creation flags
- if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE))
{
CORE.Window.fullscreen = true;
- flags |= SDL_WINDOW_FULLSCREEN;
+ FLAG_SET(flags, SDL_WINDOW_FULLSCREEN);
}
- //if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) == 0) flags |= SDL_WINDOW_HIDDEN;
- if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) flags |= SDL_WINDOW_BORDERLESS;
- if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) flags |= SDL_WINDOW_RESIZABLE;
- if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) flags |= SDL_WINDOW_MINIMIZED;
- if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) flags |= SDL_WINDOW_MAXIMIZED;
-
- if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0)
+ //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);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) FLAG_SET(flags, SDL_WINDOW_RESIZABLE);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_SET(flags, SDL_WINDOW_MINIMIZED);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_SET(flags, SDL_WINDOW_MAXIMIZED);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED))
{
- flags &= ~SDL_WINDOW_INPUT_FOCUS;
- flags &= ~SDL_WINDOW_MOUSE_FOCUS;
+ FLAG_CLEAR(flags, SDL_WINDOW_INPUT_FOCUS);
+ FLAG_CLEAR(flags, SDL_WINDOW_MOUSE_FOCUS);
}
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST)) FLAG_SET(flags, SDL_WINDOW_ALWAYS_ON_TOP);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) FLAG_CLEAR(flags, SDL_WINDOW_MOUSE_CAPTURE);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) FLAG_SET(flags, SDL_WINDOW_ALLOW_HIGHDPI);
- if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) flags |= SDL_WINDOW_ALWAYS_ON_TOP;
- if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
-
- if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) flags |= SDL_WINDOW_ALLOW_HIGHDPI;
-
- //if ((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) flags |= SDL_WINDOW_TRANSPARENT; // Alternative: SDL_GL_ALPHA_SIZE = 8
-
- //if ((CORE.Window.flags & FLAG_FULLSCREEN_DESKTOP) > 0) flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
+ //if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) FLAG_SET(flags, SDL_WINDOW_TRANSPARENT); // Alternative: SDL_GL_ALPHA_SIZE = 8
+ //if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_DESKTOP)) FLAG_SET(flags, SDL_WINDOW_FULLSCREEN_DESKTOP);
// NOTE: Some OpenGL context attributes must be set before window creation
@@ -2004,7 +1988,7 @@ int InitPlatform(void)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
- if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
{
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
@@ -2047,7 +2031,7 @@ int InitPlatform(void)
if (platform.glContext != NULL)
{
- SDL_GL_SetSwapInterval((CORE.Window.flags & FLAG_VSYNC_HINT)? 1 : 0);
+ SDL_GL_SetSwapInterval((FLAG_IS_SET(CORE.Window.flags, FLAG_VSYNC_HINT))? 1: 0);
// Load OpenGL extensions
// NOTE: GL procedures address loader is required to load extensions
@@ -2096,7 +2080,7 @@ int InitPlatform(void)
// Disable mouse events being interpreted as touch events
// NOTE: This is wanted because there are SDL_FINGER* events available which provide unique data
- // Due to the way PollInputEvents() and rgestures.h are currently implemented, setting this won't break SUPPORT_MOUSE_GESTURES
+ // Due to the way PollInputEvents() and rgestures.h are currently implemented, setting this won't break SUPPORT_MOUSE_GESTURES
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c
index 9b66f8c4b..8a4050332 100644
--- a/src/platforms/rcore_desktop_win32.c
+++ b/src/platforms/rcore_desktop_win32.c
@@ -49,8 +49,6 @@
#define CloseWindow CloseWindowWin32
#define Rectangle RectangleWin32
#define ShowCursor ShowCursorWin32
-#define LoadImageA LoadImageAWin32
-#define LoadImageW LoadImageWin32
#define DrawTextA DrawTextAWin32
#define DrawTextW DrawTextWin32
#define DrawTextExA DrawTextExAWin32
@@ -63,8 +61,6 @@
#undef Rectangle // raylib symbol collision
#undef ShowCursor // raylib symbol collision
#undef LoadImage // raylib symbol collision
-#undef LoadImageA
-#undef LoadImageW
#undef DrawText // raylib symbol collision
#undef DrawTextA
#undef DrawTextW
@@ -76,6 +72,8 @@
#include
#include
+#include // Required for alloca()
+
#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
#include
#endif
@@ -199,8 +197,8 @@ static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL;
#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_ES_PROFILE_BIT_EXT 0x00000004
-#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
+#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
+#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -264,9 +262,9 @@ static bool DecoratedFromStyle(DWORD style)
// Get window style from required flags
static DWORD MakeWindowStyle(unsigned flags)
{
- // We don't need this since we don't have any child windows, but I guess
- // it improves efficiency, plus, windows adds this flag automatically anyway
- // so it keeps our flags in sync with the OS
+ // Flag is not needed because there are no child windows,
+ // 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;
style |= (flags & FLAG_WINDOW_HIDDEN)? 0 : WS_VISIBLE;
@@ -275,7 +273,7 @@ static DWORD MakeWindowStyle(unsigned flags)
// Minimized takes precedence over maximized
int mized = MIZED_NONE;
- if (FLAG_CHECK(flags, FLAG_WINDOW_MINIMIZED)) mized = MIZED_MIN;
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_MINIMIZED)) mized = MIZED_MIN;
if (flags & FLAG_WINDOW_MAXIMIZED) mized = MIZED_MAX;
switch (mized)
@@ -941,7 +939,7 @@ void SetWindowIcon(Image image)
// Set icon for window
void SetWindowIcons(Image *images, int count)
{
- // TODO.
+ // TODO: Implement SetWindowIcons()
}
void SetWindowTitle(const char *title)
@@ -1143,7 +1141,7 @@ void ShowCursor(void)
// Hides mouse cursor
void HideCursor(void)
{
- // NOTE: We use SetCursor() instead of ShowCursor() because
+ // NOTE: We use SetCursor() instead of ShowCursor() because
// it makes it easy to only hide the cursor while it's inside the client area
SetCursor(NULL);
CORE.Input.Mouse.cursorHidden = true;
@@ -1232,7 +1230,7 @@ void SwapScreenBuffer(void)
// Get elapsed time measure in seconds
double GetTime(void)
{
- LARGE_INTEGER now;
+ LARGE_INTEGER now = 0;
QueryPerformanceCounter(&now);
return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
}
@@ -1248,7 +1246,11 @@ void OpenURL(const char *url)
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
else
{
- TRACELOG(LOG_WARNING, "OpenURL not implemented");
+ char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
+ sprintf(cmd, "explorer \"%s\"", url);
+ int result = system(cmd);
+ if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
+ RL_FREE(cmd);
}
}
@@ -1529,7 +1531,7 @@ int InitPlatform(void)
// Load user-provided icon if available
// NOTE: raylib resource file defaults to GLFW_ICON id, so looking for same identifier
windowClass.hIcon = LoadImageW(hInstance, L"GLFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
- if (!windowClass.hIcon) windowClass.hIcon = LoadImageW(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+ if (!windowClass.hIcon) windowClass.hIcon = LoadImageW(NULL, (LPCWSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
// Register window class
result = (int)RegisterClassExW(&windowClass);
@@ -1985,7 +1987,7 @@ static void HandleKey(WPARAM wparam, LPARAM lparam, char state)
{
CORE.Input.Keyboard.currentKeyState[key] = state;
- if ((key == KEY_ESCAPE) && (state == 1)) CORE.Window.shouldClose = 1;
+ if ((key == KEY_ESCAPE) && (state == 1)) CORE.Window.shouldClose = true;
}
else TRACELOG(LOG_WARNING, "INPUT: Unknown (or currently unhandled) virtual keycode %d (0x%x)", wparam, wparam);
diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c
index a08a76bce..881f96034 100644
--- a/src/platforms/rcore_drm.c
+++ b/src/platforms/rcore_drm.c
@@ -220,7 +220,7 @@ static const short linuxToRaylibMap[KEYMAP_SIZE] = {
248, 0, 0, 0, 0, 0, 0, 0,
// Gamepads are mapped according to:
- // https://www.kernel.org/doc/html/next/input/gamepad.html
+ // Ref: https://www.kernel.org/doc/html/next/input/gamepad.html
// Those mappings are standardized, but that doesn't mean people follow
// the standards, so this is more of an approximation
[BTN_DPAD_UP] = GAMEPAD_BUTTON_LEFT_FACE_UP,
@@ -637,7 +637,7 @@ static uint32_t GetOrCreateFbForBo(struct gbm_bo *bo)
}
// Renders a blank frame to allocate initial buffers
-// TODO: WARNING: Platform layers do not include OpenGL code!
+// TODO: WARNING: Platform backend should not include OpenGL code
void RenderBlankFrame()
{
glClearColor(0, 0, 0, 1);
@@ -824,15 +824,6 @@ void SwapScreenBuffer(void)
return;
}
- // Get the software rendered color buffer
- int bufferWidth = 0, bufferHeight = 0;
- void *colorBuffer = swGetColorBuffer(&bufferWidth, &bufferHeight);
- if (!colorBuffer)
- {
- TRACELOG(LOG_ERROR, "DISPLAY: Failed to get software color buffer");
- return;
- }
-
// Retrieving the dimensions of the display mode used
drmModeModeInfo *mode = &platform.connector->modes[platform.modeIndex];
uint32_t width = mode->hdisplay;
@@ -900,16 +891,8 @@ void SwapScreenBuffer(void)
}
// Copy the software rendered buffer to the dumb buffer with scaling if needed
- if (bufferWidth == width && bufferHeight == height)
- {
- // Direct copy if sizes match
- swCopyFramebuffer(0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
- }
- else
- {
- // Scale the software buffer to match the display mode
- swBlitFramebuffer(0, 0, width, height, 0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
- }
+ // NOTE: RLSW will make a simple copy if the dimensions match
+ swBlitFramebuffer(0, 0, width, height, 0, 0, width, height, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
// Unmap the buffer
munmap(dumbBuffer, creq.size);
@@ -1165,7 +1148,7 @@ int InitPlatform(void)
// Initialize graphic device: display/window and graphic context
//----------------------------------------------------------------------------
CORE.Window.fullscreen = true;
- CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
#if defined(DEFAULT_GRAPHIC_DEVICE_DRM)
platform.fd = open(DEFAULT_GRAPHIC_DEVICE_DRM, O_RDWR);
@@ -1230,9 +1213,9 @@ int InitPlatform(void)
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i modes detected: %i", i, con->count_modes);
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i,
- (con->connection == DRM_MODE_CONNECTED) ? "CONNECTED" :
- (con->connection == DRM_MODE_DISCONNECTED) ? "DISCONNECTED" :
- (con->connection == DRM_MODE_UNKNOWNCONNECTION) ? "UNKNOWN" : "OTHER");
+ (con->connection == DRM_MODE_CONNECTED)? "CONNECTED" :
+ (con->connection == DRM_MODE_DISCONNECTED)? "DISCONNECTED" :
+ (con->connection == DRM_MODE_UNKNOWNCONNECTION)? "UNKNOWN" : "OTHER");
// In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected
// This might be a hardware or software limitation like on Raspberry Pi Zero with composite output
@@ -1314,8 +1297,8 @@ int InitPlatform(void)
CORE.Window.screen.height = CORE.Window.display.height;
}
- const bool allowInterlaced = CORE.Window.flags & FLAG_INTERLACED_HINT;
- const int fps = (CORE.Time.target > 0) ? (1.0/CORE.Time.target) : 60;
+ const bool allowInterlaced = FLAG_IS_SET(CORE.Window.flags, FLAG_INTERLACED_HINT);
+ const int fps = (CORE.Time.target > 0)? (1.0/CORE.Time.target) : 60;
// Try to find an exact matching mode
platform.modeIndex = FindExactConnectorMode(platform.connector, CORE.Window.screen.width, CORE.Window.screen.height, fps, allowInterlaced);
@@ -1345,7 +1328,7 @@ int InitPlatform(void)
TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u)", platform.connector->modes[platform.modeIndex].name,
platform.connector->modes[platform.modeIndex].hdisplay, platform.connector->modes[platform.modeIndex].vdisplay,
- (platform.connector->modes[platform.modeIndex].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
+ FLAG_IS_SET(platform.connector->modes[platform.modeIndex].flags, DRM_MODE_FLAG_INTERLACE)? 'i' : 'p',
platform.connector->modes[platform.modeIndex].vrefresh);
drmModeFreeEncoder(enc);
@@ -1362,7 +1345,7 @@ int InitPlatform(void)
platform.connector->modes[0].name,
platform.connector->modes[0].hdisplay,
platform.connector->modes[0].vdisplay,
- (platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
+ (platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE)? 'i' : 'p',
platform.connector->modes[0].vrefresh);
}
else
@@ -1401,7 +1384,7 @@ int InitPlatform(void)
EGLint samples = 0;
EGLint sampleBuffer = 0;
- if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
{
samples = 4;
sampleBuffer = 1;
@@ -1473,7 +1456,7 @@ int InitPlatform(void)
// find the EGL config that matches the previously setup GBM format
int found = 0;
- for (EGLint i = 0; i < matchingNumConfigs; ++i)
+ for (EGLint i = 0; i < matchingNumConfigs; i++)
{
EGLint id = 0;
if (!eglGetConfigAttrib(platform.device, configs[i], EGL_NATIVE_VISUAL_ID, &id))
@@ -1578,17 +1561,17 @@ int InitPlatform(void)
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
#endif
- if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
+ 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 SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
// Set some default window flags
- CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // false
- CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // false
- CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED; // true
- CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // false
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_HIDDEN); // false
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // false
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // true
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // false
//----------------------------------------------------------------------------
// Initialize timing system
@@ -1737,8 +1720,8 @@ static void InitKeyboard(void)
// New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
// NOTE: ISIG controls if ^C and ^Z generate break signals or not
- keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG);
- //keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
+ FLAG_CLEAR(keyboardNewSettings.c_lflag, ICANON | ECHO | ISIG);
+ //FLAG_CLEAR(keyboardNewSettings.c_iflag, ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
keyboardNewSettings.c_cc[VMIN] = 1;
keyboardNewSettings.c_cc[VTIME] = 0;
@@ -1757,10 +1740,10 @@ static void InitKeyboard(void)
else
{
// Reconfigure keyboard mode to get:
- // - scancodes (K_RAW)
- // - keycodes (K_MEDIUMRAW)
- // - ASCII chars (K_XLATE)
- // - UNICODE chars (K_UNICODE)
+ // - scancodes (K_RAW)
+ // - keycodes (K_MEDIUMRAW)
+ // - ASCII chars (K_XLATE)
+ // - UNICODE chars (K_UNICODE)
ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE); // ASCII chars
}
@@ -1895,7 +1878,7 @@ static void InitEvdevInput(void)
platform.mouseFd = -1;
// Reset variables
- for (int i = 0; i < MAX_TOUCH_POINTS; ++i)
+ for (int i = 0; i < MAX_TOUCH_POINTS; i++)
{
CORE.Input.Touch.position[i].x = -1;
CORE.Input.Touch.position[i].y = -1;
@@ -2419,7 +2402,7 @@ static int FindMatchingConnectorMode(const drmModeConnector *connector, const dr
for (size_t i = 0; i < connector->count_modes; i++)
{
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, connector->modes[i].hdisplay, connector->modes[i].vdisplay,
- connector->modes[i].vrefresh, (connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
+ connector->modes[i].vrefresh, (FLAG_IS_SET(connector->modes[i].flags, DRM_MODE_FLAG_INTERLACE) > 0)? "interlaced" : "progressive");
if (0 == BINCMP(&platform.crtc->mode, &platform.connector->modes[i])) return i;
}
@@ -2440,9 +2423,9 @@ static int FindExactConnectorMode(const drmModeConnector *connector, uint width,
{
const drmModeModeInfo *const mode = &platform.connector->modes[i];
- TRACELOG(LOG_TRACE, "DISPLAY: DRM Mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
+ TRACELOG(LOG_TRACE, "DISPLAY: DRM Mode %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh, (FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0)? "interlaced" : "progressive");
- if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !allowInterlaced) continue;
+ if ((FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0) && !allowInterlaced) continue;
if ((mode->hdisplay == width) && (mode->vdisplay == height) && (mode->vrefresh == fps)) return i;
}
@@ -2466,7 +2449,7 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
const drmModeModeInfo *const mode = &platform.connector->modes[i];
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode: %d %ux%u@%u %s", i, mode->hdisplay, mode->vdisplay, mode->vrefresh,
- (mode->flags & DRM_MODE_FLAG_INTERLACE)? "interlaced" : "progressive");
+ (FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0)? "interlaced" : "progressive");
if ((mode->hdisplay < width) || (mode->vdisplay < height))
{
@@ -2474,13 +2457,13 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
continue;
}
- if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !allowInterlaced)
+ if ((FLAG_IS_SET(mode->flags, DRM_MODE_FLAG_INTERLACE) > 0) && !allowInterlaced)
{
TRACELOG(LOG_TRACE, "DISPLAY: DRM shouldn't choose an interlaced mode");
continue;
}
- const int unusedPixels = (mode->hdisplay - width) * (mode->vdisplay - height);
+ const int unusedPixels = (mode->hdisplay - width)*(mode->vdisplay - height);
const int fpsDiff = mode->vrefresh - fps;
if ((unusedPixels < minUnusedPixels) ||
diff --git a/src/platforms/rcore_memory.c b/src/platforms/rcore_memory.c
new file mode 100644
index 000000000..e49159a85
--- /dev/null
+++ b/src/platforms/rcore_memory.c
@@ -0,0 +1,595 @@
+/**********************************************************************************************
+*
+* rcore_memory - Functions to manage window, graphics device and inputs
+*
+* PLATFORM: MEMORY (No OS)
+* - Memory framebuffer output (no os)
+*
+* LIMITATIONS:
+* - Software renderer (rlsw)
+* - No input system
+*
+* POSSIBLE IMPROVEMENTS:
+* - 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-
+*
+* DEPENDENCIES:
+* - rlsw: Software renderer
+* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs)
+*
+*
+* LICENSE: zlib/libpng
+*
+* Copyright (c) 2025 Ramon Santamaria (@raysan5) and contributors
+*
+* This software is provided "as-is", without any express or implied warranty. In no event
+* will the authors be held liable for any damages arising from the use of this software.
+*
+* 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.
+*
+**********************************************************************************************/
+
+#if defined(_WIN32)
+ #include // Required for: kbhit()
+#else
+ // Provide kbhit() function in non-Windows platforms
+ #include
+ #include
+ #include
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Platform-specific required data for timming (Win32)
+#if defined(_WIN32)
+typedef struct _LARGE_INTEGER { int64_t QuadPart; } LARGE_INTEGER;
+__declspec(dllimport) int __stdcall QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
+__declspec(dllimport) int __stdcall QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
+#endif
+
+typedef struct {
+ unsigned int *pixels; // Pointer to pixel data buffer (RGBA8888 format)
+#if defined(_WIN32)
+ LARGE_INTEGER timerFrequency;
+#endif
+} PlatformData;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+extern CoreData CORE; // Global CORE state context
+
+static PlatformData platform = { 0 }; // Platform specific data
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+int InitPlatform(void); // Initialize platform (graphics, inputs and more)
+bool InitGraphicsDevice(void); // Initialize graphics device
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+// NOTE: Functions declaration is provided by raylib.h
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+#if !defined(_WIN32)
+static int kbhit(void); // Check if a key has been pressed
+static char getch(void) { return getchar(); } // Get pressed character
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Window and Graphics Device
+//----------------------------------------------------------------------------------
+
+// Check if application should close
+bool WindowShouldClose(void)
+{
+ if (CORE.Window.ready) return CORE.Window.shouldClose;
+ else return true;
+}
+
+// Toggle fullscreen mode
+void ToggleFullscreen(void)
+{
+ TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform");
+}
+
+// Toggle borderless windowed mode
+void ToggleBorderlessWindowed(void)
+{
+ TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform");
+}
+
+// Set window state: maximized, if resizable
+void MaximizeWindow(void)
+{
+ TRACELOG(LOG_WARNING, "MaximizeWindow() not available on target platform");
+}
+
+// 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)
+{
+ TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
+}
+
+// Set window configuration state using flags
+void SetWindowState(unsigned int flags)
+{
+ TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform");
+}
+
+// Clear window configuration state flags
+void ClearWindowState(unsigned int flags)
+{
+ TRACELOG(LOG_WARNING, "ClearWindowState() 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
+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;
+}
+
+// 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;
+}
+
+// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
+void SetWindowMaxSize(int width, int height)
+{
+ CORE.Window.screenMax.width = width;
+ CORE.Window.screenMax.height = height;
+}
+
+// Set window dimensions
+void SetWindowSize(int width, int height)
+{
+ TRACELOG(LOG_WARNING, "SetWindowSize() not available on target platform");
+}
+
+// Set window opacity, value opacity is between 0.0 and 1.0
+void SetWindowOpacity(float opacity)
+{
+ TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform");
+}
+
+// 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)
+{
+ TRACELOG(LOG_WARNING, "GetMonitorWidth() not implemented on target platform");
+ return 0;
+}
+
+// Get selected monitor height (currently used by monitor)
+int GetMonitorHeight(int monitor)
+{
+ TRACELOG(LOG_WARNING, "GetMonitorHeight() not implemented on target platform");
+ return 0;
+}
+
+// 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)
+{
+ TRACELOG(LOG_WARNING, "GetWindowPosition() not implemented on target platform");
+ return (Vector2){ 0, 0 };
+}
+
+// Get window scale DPI factor for current monitor
+Vector2 GetWindowScaleDPI(void)
+{
+ TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
+ return (Vector2){ 1.0f, 1.0f };
+}
+
+// Set clipboard text content
+void SetClipboardText(const char *text)
+{
+ TRACELOG(LOG_WARNING, "SetClipboardText() not implemented on target platform");
+}
+
+// Get clipboard text content
+// NOTE: returned string is allocated and freed by GLFW
+const char *GetClipboardText(void)
+{
+ TRACELOG(LOG_WARNING, "GetClipboardText() not implemented on target platform");
+ return NULL;
+}
+
+// Get clipboard image
+Image GetClipboardImage(void)
+{
+ Image image = { 0 };
+
+ TRACELOG(LOG_WARNING, "GetClipboardImage() not implemented on target platform");
+
+ return image;
+}
+
+// Show mouse cursor
+void ShowCursor(void)
+{
+ CORE.Input.Mouse.cursorHidden = false;
+}
+
+// Hides mouse cursor
+void HideCursor(void)
+{
+ CORE.Input.Mouse.cursorHidden = true;
+}
+
+// Enables cursor (unlock cursor)
+void EnableCursor(void)
+{
+ // Set cursor position in the middle
+ SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
+
+ CORE.Input.Mouse.cursorHidden = false;
+}
+
+// Disables cursor (lock cursor)
+void DisableCursor(void)
+{
+ // Set cursor position in the middle
+ SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
+
+ CORE.Input.Mouse.cursorHidden = true;
+}
+
+// Swap back buffer with front buffer (screen drawing)
+void SwapScreenBuffer(void)
+{
+ // Update framebuffer
+ rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels);
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Misc
+//----------------------------------------------------------------------------------
+
+// Get elapsed time measure in seconds since InitTimer()
+double GetTime(void)
+{
+ double time = 0.0;
+#if defined(_WIN32)
+ LARGE_INTEGER now = { 0 };
+ QueryPerformanceCounter(&now);
+ return (double)(now.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart;
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
+ 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()
+#endif
+ 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.
+// Ref: https://github.com/raysan5/raylib/issues/686
+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
+ {
+ char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
+ sprintf(cmd, "explorer \"%s\"", url);
+ int result = system(cmd);
+ if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created");
+ RL_FREE(cmd);
+ }
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition: Inputs
+//----------------------------------------------------------------------------------
+
+// Set internal gamepad mappings
+int SetGamepadMappings(const char *mappings)
+{
+ TRACELOG(LOG_WARNING, "SetGamepadMappings() not implemented on target platform");
+ return 0;
+}
+
+// Set gamepad vibration
+void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration)
+{
+ TRACELOG(LOG_WARNING, "SetGamepadVibration() not implemented on target platform");
+}
+
+// Set mouse position XY
+void SetMousePosition(int x, int y)
+{
+ CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
+ CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
+}
+
+// Set mouse cursor
+void SetMouseCursor(int cursor)
+{
+ TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
+}
+
+// Get physical key name.
+const char *GetKeyName(int 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 key repeats
+ for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
+
+ // Reset last gamepad button/axis registered state
+ CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
+ //CORE.Input.Gamepad.axisCount = 0;
+
+ // 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 };
+
+ // Register previous keys states
+ // NOTE: Android supports up to 260 keys
+ for (int i = 0; i < 260; i++)
+ {
+ CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i];
+ CORE.Input.Keyboard.keyRepeatInFrame[i] = 0;
+ }
+
+ // TODO: Poll input events for current platform
+
+ // Check for key pressed to exit
+ if (kbhit())
+ {
+ int key = getch();
+ if (key == 27) CORE.Window.shouldClose = true; // KEY_SCAPE
+ }
+}
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+
+// Initialize platform: graphics, inputs and more
+int InitPlatform(void)
+{
+ // Memory framebuffer can only work with software renderer
+ if (rlGetVersion() != RL_OPENGL_11_SOFTWARE)
+ {
+ TRACELOG(LOG_WARNING, "DISPLAY: Memory platform requires software renderer (GRAPHICS_API_OPENGL_11_SOFTWARE)");
+ TRACELOG(LOG_FATAL, "PLATFORM: Failed to initialize graphics device");
+ return -1;
+ }
+ else
+ {
+ // Load memory framebuffer with desired screen size
+ platform.pixels = (unsigned int *)RL_CALLOC(CORE.Window.screen.width*CORE.Window.screen.height, sizeof(int));
+ }
+ //----------------------------------------------------------------------------
+
+ // If everything work as expected, we can continue
+ CORE.Window.render.width = CORE.Window.screen.width;
+ CORE.Window.render.height = CORE.Window.screen.height;
+ CORE.Window.currentFbo.width = CORE.Window.render.width;
+ CORE.Window.currentFbo.height = CORE.Window.render.height;
+
+ 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);
+
+ CORE.Window.ready = true;
+
+ // TODO: Load OpenGL extensions
+ // NOTE: GL procedures address loader is required to load extensions
+ //----------------------------------------------------------------------------
+ // ...
+ //----------------------------------------------------------------------------
+
+ // TODO: Initialize input events system
+ // It could imply keyboard, mouse, gamepad, touch...
+ // Depending on the platform libraries/SDK it could use a callback mechanism
+ // For system events and inputs evens polling on a per-frame basis, use PollInputEvents()
+ //----------------------------------------------------------------------------
+ // ...
+ //----------------------------------------------------------------------------
+
+ // Initialize timing system
+ //----------------------------------------------------------------------------
+#if defined(_WIN32)
+ LARGE_INTEGER time = { 0 };
+ QueryPerformanceCounter(&time);
+ QueryPerformanceFrequency(&platform.timerFrequency);
+ CORE.Time.base = time.QuadPart;
+#endif
+ InitTimer();
+ //----------------------------------------------------------------------------
+
+ // Initialize storage system
+ //----------------------------------------------------------------------------
+ CORE.Storage.basePath = GetWorkingDirectory();
+ //----------------------------------------------------------------------------
+
+ TRACELOG(LOG_INFO, "PLATFORM: MEMORY: Initialized successfully");
+
+ return 0;
+}
+
+// Close platform
+void ClosePlatform(void)
+{
+ RL_FREE(platform.pixels);
+}
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+#if !defined(_WIN32)
+// Check if a key has been pressed
+static int kbhit(void)
+{
+ struct termios oldt = { 0 };
+ struct termios newt = { 0 };
+ int ch = 0;
+ int oldf = 0;
+
+ tcgetattr(STDIN_FILENO, &oldt);
+ newt = oldt;
+ newt.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(STDIN_FILENO, TCSANOW, &newt);
+ oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
+ fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
+
+ ch = getchar();
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
+ fcntl(STDIN_FILENO, F_SETFL, oldf);
+
+ if (ch != EOF)
+ {
+ ungetc(ch, stdin);
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+// EOF
diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c
index 36629fc69..bc03a3cdb 100644
--- a/src/platforms/rcore_template.c
+++ b/src/platforms/rcore_template.c
@@ -460,11 +460,11 @@ int InitPlatform(void)
// Below example illustrates that process using EGL library
//----------------------------------------------------------------------------
CORE.Window.fullscreen = true;
- CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
EGLint samples = 0;
EGLint sampleBuffer = 0;
- if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
{
samples = 4;
sampleBuffer = 1;
diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c
index c8fe0cfe7..2d2f8d1c0 100644
--- a/src/platforms/rcore_web.c
+++ b/src/platforms/rcore_web.c
@@ -159,7 +159,7 @@ static const char *GetCanvasId(void);
bool WindowShouldClose(void)
{
// Emscripten Asyncify is required to run synchronous code in asynchronous JS
- // REF: https://emscripten.org/docs/porting/asyncify.html
+ // Ref: https://emscripten.org/docs/porting/asyncify.html
// WindowShouldClose() is not called on a web-ready raylib application if using emscripten_set_main_loop()
// and encapsulating one frame execution on a UpdateDrawFrame() function,
@@ -181,8 +181,8 @@ void ToggleFullscreen(void)
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
if (wasFullscreen)
{
- if (CORE.Window.flags & FLAG_FULLSCREEN_MODE) enterFullscreen = false;
- else if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) enterFullscreen = true;
+ 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);
@@ -194,8 +194,8 @@ void ToggleFullscreen(void)
EM_ASM(document.exitFullscreen(););
CORE.Window.fullscreen = false;
- CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
- CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
else enterFullscreen = true;
@@ -210,7 +210,7 @@ void ToggleFullscreen(void)
}, 100);
);
CORE.Window.fullscreen = true;
- CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
// NOTE: Old notes below:
@@ -263,7 +263,7 @@ void ToggleFullscreen(void)
TRACELOG(LOG_WARNING, "Emscripten: Enter fullscreen: Canvas size: %i x %i", width, height);
CORE.Window.fullscreen = true; // Toggle fullscreen flag
- CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
else
{
@@ -275,7 +275,7 @@ void ToggleFullscreen(void)
TRACELOG(LOG_WARNING, "Emscripten: Exit fullscreen: Canvas size: %i x %i", width, height);
CORE.Window.fullscreen = false; // Toggle fullscreen flag
- CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
*/
}
@@ -289,8 +289,8 @@ void ToggleBorderlessWindowed(void)
const bool wasFullscreen = EM_ASM_INT( { if (document.fullscreenElement) return 1; }, 0);
if (wasFullscreen)
{
- if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) enterBorderless = false;
- else if (CORE.Window.flags & FLAG_FULLSCREEN_MODE) enterBorderless = true;
+ 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);
@@ -302,15 +302,15 @@ void ToggleBorderlessWindowed(void)
EM_ASM(document.exitFullscreen(););
CORE.Window.fullscreen = false;
- CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
- CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
else enterBorderless = true;
if (enterBorderless)
{
- // NOTE: 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
+ // 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()
@@ -322,14 +322,14 @@ void ToggleBorderlessWindowed(void)
}, 100);
}, 100);
);
- CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE;
+ FLAG_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
}
// Set window state: maximized, if resizable
void MaximizeWindow(void)
{
- if ((glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) && !(CORE.Window.flags & FLAG_WINDOW_MAXIMIZED))
+ if ((glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) && !(FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)))
{
platform.unmaximizedWidth = CORE.Window.screen.width;
platform.unmaximizedHeight = CORE.Window.screen.height;
@@ -339,7 +339,7 @@ void MaximizeWindow(void)
if (tabWidth && tabHeight) glfwSetWindowSize(platform.handle, tabWidth, tabHeight);
- CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
}
}
@@ -352,11 +352,11 @@ void MinimizeWindow(void)
// Restore window from being minimized/maximized
void RestoreWindow(void)
{
- if ((glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) && (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED))
+ if ((glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE) && (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)))
{
if (platform.unmaximizedWidth && platform.unmaximizedHeight) glfwSetWindowSize(platform.handle, platform.unmaximizedWidth, platform.unmaximizedHeight);
- CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
}
}
@@ -369,13 +369,13 @@ void SetWindowState(unsigned int flags)
// NOTE: In most cases the functions already change the flags internally
// State change: FLAG_VSYNC_HINT
- if ((flags & FLAG_VSYNC_HINT) > 0)
+ 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 ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
+ 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);
@@ -383,13 +383,13 @@ void SetWindowState(unsigned int flags)
{
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 ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) || canvasStyleWidth > canvasWidth) ToggleBorderlessWindowed();
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) || canvasStyleWidth > canvasWidth) ToggleBorderlessWindowed();
}
else ToggleBorderlessWindowed();
}
// State change: FLAG_FULLSCREEN_MODE
- if ((flags & FLAG_FULLSCREEN_MODE) > 0)
+ 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);
@@ -397,38 +397,38 @@ void SetWindowState(unsigned int flags)
{
const int canvasWidth = EM_ASM_INT( { return Module.canvas.width; }, 0);
const int screenWidth = EM_ASM_INT( { return screen.width; }, 0);
- if ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) || screenWidth == canvasWidth ) ToggleFullscreen();
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) || screenWidth == canvasWidth ) ToggleFullscreen();
}
else ToggleFullscreen();
}
// State change: FLAG_WINDOW_RESIZABLE
- if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != (flags & FLAG_WINDOW_RESIZABLE)) && ((flags & FLAG_WINDOW_RESIZABLE) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)) && (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)))
{
glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_TRUE);
- CORE.Window.flags |= FLAG_WINDOW_RESIZABLE;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE);
}
// State change: FLAG_WINDOW_UNDECORATED
- if ((flags & FLAG_WINDOW_UNDECORATED) > 0)
+ 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 ((flags & FLAG_WINDOW_HIDDEN) > 0)
+ 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 ((flags & FLAG_WINDOW_MINIMIZED) > 0)
+ 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 (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) != (flags & FLAG_WINDOW_MAXIMIZED)) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0))
+ 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 (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
{
@@ -440,24 +440,24 @@ void SetWindowState(unsigned int flags)
if (tabWidth && tabHeight) glfwSetWindowSize(platform.handle, tabWidth, tabHeight);
- CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
+ FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
}
}
// State change: FLAG_WINDOW_UNFOCUSED
- if ((flags & FLAG_WINDOW_UNFOCUSED) > 0)
+ 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 ((flags & FLAG_WINDOW_TOPMOST) > 0)
+ 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 ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
{
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_ALWAYS_RUN) not available on target platform");
}
@@ -466,31 +466,31 @@ void SetWindowState(unsigned int flags)
// NOTE: Review for PLATFORM_WEB
// State change: FLAG_WINDOW_TRANSPARENT
- if ((flags & FLAG_WINDOW_TRANSPARENT) > 0)
+ 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 ((flags & FLAG_WINDOW_HIGHDPI) > 0)
+ 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 ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0)
+ 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 ((flags & FLAG_MSAA_4X_HINT) > 0)
+ 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 ((flags & FLAG_INTERLACED_HINT) > 0)
+ if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
{
TRACELOG(LOG_WARNING, "SetWindowState(FLAG_INTERLACED_HINT) not available on target platform");
}
@@ -503,90 +503,90 @@ void ClearWindowState(unsigned int flags)
// NOTE: In most cases the functions already change the flags internally
// State change: FLAG_VSYNC_HINT
- if ((flags & FLAG_VSYNC_HINT) > 0)
+ 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 ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0)
+ 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 ((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) || (screenWidth == canvasWidth)) EM_ASM(document.exitFullscreen(););
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE) || (screenWidth == canvasWidth)) EM_ASM(document.exitFullscreen(););
}
- CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
// State change: FLAG_FULLSCREEN_MODE
- if ((flags & FLAG_FULLSCREEN_MODE) > 0)
+ 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 ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) || (canvasStyleWidth > canvasWidth)) EM_ASM(document.exitFullscreen(););
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE) || (canvasStyleWidth > canvasWidth)) EM_ASM(document.exitFullscreen(););
}
CORE.Window.fullscreen = false;
- CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
}
// State change: FLAG_WINDOW_RESIZABLE
- if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) && ((flags & FLAG_WINDOW_RESIZABLE) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) && (FLAG_IS_SET(flags, FLAG_WINDOW_RESIZABLE)))
{
glfwSetWindowAttrib(platform.handle, GLFW_RESIZABLE, GLFW_FALSE);
- CORE.Window.flags &= ~FLAG_WINDOW_RESIZABLE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_RESIZABLE);
}
// State change: FLAG_WINDOW_HIDDEN
- if ((flags & FLAG_WINDOW_HIDDEN) > 0)
+ 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 ((flags & FLAG_WINDOW_MINIMIZED) > 0)
+ 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 (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0))
+ if ((FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) && (FLAG_IS_SET(flags, FLAG_WINDOW_MAXIMIZED)))
{
if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
{
if (platform.unmaximizedWidth && platform.unmaximizedHeight) glfwSetWindowSize(platform.handle, platform.unmaximizedWidth, platform.unmaximizedHeight);
- CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
}
}
// State change: FLAG_WINDOW_UNDECORATED
- if ((flags & FLAG_WINDOW_UNDECORATED) > 0)
+ 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 ((flags & FLAG_WINDOW_UNFOCUSED) > 0)
+ 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 ((flags & FLAG_WINDOW_TOPMOST) > 0)
+ 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 ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0)
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN))
{
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_ALWAYS_RUN) not available on target platform");
}
@@ -595,31 +595,31 @@ void ClearWindowState(unsigned int flags)
// NOTE: Review for PLATFORM_WEB
// State change: FLAG_WINDOW_TRANSPARENT
- if ((flags & FLAG_WINDOW_TRANSPARENT) > 0)
+ 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 ((flags & FLAG_WINDOW_HIGHDPI) > 0)
+ 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 ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0)
+ 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 ((flags & FLAG_MSAA_4X_HINT) > 0)
+ 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 ((flags & FLAG_INTERLACED_HINT) > 0)
+ if (FLAG_IS_SET(flags, FLAG_INTERLACED_HINT))
{
TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_INTERLACED_HINT) not available on target platform");
}
@@ -663,7 +663,7 @@ void SetWindowMinSize(int width, int height)
CORE.Window.screenMin.height = height;
// Trigger the resize event once to update the window minimum width and height
- if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != 0) EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != 0) EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
}
// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
@@ -673,7 +673,7 @@ void SetWindowMaxSize(int width, int height)
CORE.Window.screenMax.height = height;
// Trigger the resize event once to update the window maximum width and height
- if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != 0) EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE) != 0) EmscriptenResizeCallback(EMSCRIPTEN_EVENT_RESIZE, NULL, NULL);
}
// Set window dimensions
@@ -866,7 +866,6 @@ void EnableCursor(void)
// Disables cursor (lock cursor)
void DisableCursor(void)
{
- // TODO: figure out how not to hard code the canvas ID here.
emscripten_request_pointerlock(GetCanvasId(), 1);
// Set cursor position in the middle
@@ -893,10 +892,9 @@ double GetTime(void)
}
// 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.
-// Ref: https://github.com/raysan5/raylib/issues/686
+// 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
@@ -1090,10 +1088,6 @@ void PollInputEvents(void)
}
CORE.Window.resizedLastFrame = false;
-
- // TODO: This code does not seem to do anything??
- //if (CORE.Window.eventWaiting) glfwWaitEvents(); // Wait for in input events before continue (drawing is paused)
- //else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) --> WARNING: Where is key input reset?
}
//----------------------------------------------------------------------------------
@@ -1122,27 +1116,27 @@ int InitPlatform(void)
// glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers
// Check window creation flags
- if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true;
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) CORE.Window.fullscreen = true;
- if ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // Visible window
+ 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
- if ((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNDECORATED)) glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // Border and buttons on Window
else glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); // Decorated window
- if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // Resizable window
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // Resizable window
else glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // Avoid window being resizable
// Disable FLAG_WINDOW_MINIMIZED, not supported on initialization
- if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED;
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED);
// Disable FLAG_WINDOW_MAXIMIZED, not supported on initialization
- if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED);
- if ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED)) glfwWindowHint(GLFW_FOCUSED, GLFW_FALSE);
else glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
- if ((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TOPMOST)) glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
else glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
// NOTE: Some GLFW flags are not supported on HTML5
@@ -1150,10 +1144,10 @@ int InitPlatform(void)
// Scale content area based on the monitor content scale where window is placed on
// NOTE: This feature requires emscripten 3.1.51
- //if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
+ //if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
//else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
- if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
{
// NOTE: MSAA is only enabled for main framebuffer, not user-created FBOs
TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4");
@@ -1161,8 +1155,8 @@ int InitPlatform(void)
}
// NOTE: When asking for an OpenGL context version, most drivers provide the highest supported version
- // with backward compatibility to older OpenGL versions.
- // For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context.
+ // with backward compatibility to older OpenGL versions
+ // For example, if using OpenGL 1.1, driver can provide a 4.3 backwards compatible context
// Check selection OpenGL version
if (rlGetVersion() == RL_OPENGL_21)
@@ -1172,10 +1166,12 @@ int InitPlatform(void)
}
else if (rlGetVersion() == RL_OPENGL_33)
{
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint)
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Choose OpenGL minor version (just hint)
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above!
- // Values: GLFW_OPENGL_CORE_PROFILE, GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Choose OpenGL major version (just hint)
+ 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_FORWARD_COMPAT, GLFW_FALSE); // Forward Compatibility Hint: Only 3.3 and above!
// glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); // Request OpenGL DEBUG context
}
@@ -1198,7 +1194,6 @@ int InitPlatform(void)
}
else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context
{
- // TODO: It seems WebGL 2.0 context is not set despite being requested
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
@@ -1217,8 +1212,8 @@ int InitPlatform(void)
// 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))
{
- // 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.
+ // 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;
}
@@ -1296,7 +1291,7 @@ int InitPlatform(void)
glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);
glfwSetDropCallback(platform.handle, WindowDropCallback);
- if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
// Window content (framebuffer) scale callback
glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
@@ -1338,7 +1333,7 @@ int InitPlatform(void)
return -1;
}
- if ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) MinimizeWindow();
+ 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; }
@@ -1423,7 +1418,7 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
if (IsWindowFullscreen()) return;
// Set current screen size
- if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
Vector2 windowScaleDPI = GetWindowScaleDPI();
@@ -1448,15 +1443,15 @@ static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float s
// GLFW3: Called on windows minimized/restored
static void WindowIconifyCallback(GLFWwindow *window, int iconified)
{
- if (iconified) CORE.Window.flags |= FLAG_WINDOW_MINIMIZED; // The window was iconified
- else CORE.Window.flags &= ~FLAG_WINDOW_MINIMIZED; // The window was restored
+ if (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: Called on windows get/lose focus
static void WindowFocusCallback(GLFWwindow *window, int focused)
{
- if (focused) CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED; // The window was focused
- else CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED; // The window lost focus
+ if (focused) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // The window was focused
+ else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // The window lost focus
}
// GLFW3: Called on file-drop over the window
@@ -1671,8 +1666,8 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
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++) 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]);
*/
if (gamepadEvent->connected && (gamepadEvent->index < MAX_GAMEPADS))
@@ -1714,7 +1709,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0;
}
- // Update mouse position if we detect a single touch.
+ // 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;
@@ -1782,8 +1777,8 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
if (!wasFullscreen)
{
CORE.Window.fullscreen = false;
- CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
- CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
+ FLAG_CLEAR(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
+ FLAG_CLEAR(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE);
}
}
@@ -1794,7 +1789,7 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData)
{
// Don't resize non-resizeable windows
- if ((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) == 0) return 1;
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_RESIZABLE)) return 1;
// This event is called whenever the window changes sizes,
// so the size of the canvas object is explicitly retrieved below
@@ -1844,8 +1839,8 @@ static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent
// Emscripten: Called on visibility change events
static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData)
{
- if (visibilityChangeEvent->hidden) CORE.Window.flags |= FLAG_WINDOW_HIDDEN; // The window was hidden
- else CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN; // The window was restored
+ 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
}
//-------------------------------------------------------------------------------------------------------
diff --git a/src/raudio.c b/src/raudio.c
index de2bf81b2..2416f0849 100644
--- a/src/raudio.c
+++ b/src/raudio.c
@@ -593,7 +593,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
// Init audio buffer values
audioBuffer->volume = 1.0f;
audioBuffer->pitch = 1.0f;
- audioBuffer->pan = 0.5f;
+ audioBuffer->pan = 0.0f; // Center
audioBuffer->callback = NULL;
audioBuffer->processor = NULL;
@@ -720,7 +720,7 @@ void SetAudioBufferPitch(AudioBuffer *buffer, float pitch)
// Set pan for an audio buffer
void SetAudioBufferPan(AudioBuffer *buffer, float pan)
{
- if (pan < 0.0f) pan = 0.0f;
+ if (pan < -1.0f) pan = -1.0f;
else if (pan > 1.0f) pan = 1.0f;
if (buffer != NULL)
@@ -985,10 +985,10 @@ Sound LoadSoundAlias(Sound source)
audioBuffer->sizeInFrames = source.stream.buffer->sizeInFrames;
audioBuffer->data = source.stream.buffer->data;
- // initalize the buffer as if it was new
+ // Initalize the buffer as if it was new
audioBuffer->volume = 1.0f;
audioBuffer->pitch = 1.0f;
- audioBuffer->pan = 0.5f;
+ audioBuffer->pan = 0.0f; // Center
sound.frameCount = source.frameCount;
sound.stream.sampleRate = AUDIO.System.device.sampleRate;
@@ -2092,9 +2092,7 @@ float GetMusicTimePlayed(Music music)
int framesInFirstBuffer = music.stream.buffer->isSubBufferProcessed[0]? 0 : subBufferSize;
int framesInSecondBuffer = music.stream.buffer->isSubBufferProcessed[1]? 0 : subBufferSize;
int framesInBuffers = framesInFirstBuffer + framesInSecondBuffer;
- if ((unsigned int)framesInBuffers > music.frameCount) {
- if (!music.looping) framesInBuffers = music.frameCount;
- }
+ if (((unsigned int)framesInBuffers > music.frameCount) && !music.looping) framesInBuffers = music.frameCount;
int framesSentToMix = music.stream.buffer->frameCursorPos%subBufferSize;
int framesPlayed = (framesProcessed - framesInBuffers + framesSentToMix)%(int)music.frameCount;
if (framesPlayed < 0) framesPlayed += music.frameCount;
@@ -2125,7 +2123,7 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
if (deviceBitsPerSample > 4) deviceBitsPerSample = 4;
deviceBitsPerSample *= AUDIO.System.device.playback.channels;
- unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0) ? (AUDIO.System.device.sampleRate/30*deviceBitsPerSample) : AUDIO.Buffer.defaultSize;
+ unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0)? (AUDIO.System.device.sampleRate/30*deviceBitsPerSample) : AUDIO.Buffer.defaultSize;
if (subBufferSize < periodSize) subBufferSize = periodSize;
@@ -2605,8 +2603,8 @@ static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 fr
if (channels == 2) // We consider panning
{
- const float left = buffer->pan;
- const float right = 1.0f - left;
+ const float right = (buffer->pan + 1.0f)/2.0f; // Normalize: [-1..1] -> [0..1]
+ const float left = 1.0f - right;
// Fast sine approximation in [0..1] for pan law: y = 0.5f*x*(3 - x*x);
const float levels[2] = { localVolume*0.5f*left*(3.0f - left*left), localVolume*0.5f*right*(3.0f - right*right) };
diff --git a/src/raylib.h b/src/raylib.h
index e4be11084..ece2e6aab 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -33,7 +33,6 @@
* [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management
*
* OPTIONAL DEPENDENCIES (included):
-* [rcore] msf_gif (Miles Fogle) for GIF recording
* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm
* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm
* [rcore] rprand (Ramon Santamaria) for pseudo-random numbers generation
@@ -100,13 +99,13 @@
#define __declspec(x) __attribute__((x))
#endif
#if defined(BUILD_LIBTYPE_SHARED)
- #define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
+ #define RLAPI __declspec(dllexport) // 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)
+ #define RLAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll)
#endif
#else
#if defined(BUILD_LIBTYPE_SHARED)
- #define RLAPI __attribute__((visibility("default"))) // We are building as a Unix shared library (.so/.dylib)
+ #define RLAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib)
#endif
#endif
@@ -158,7 +157,7 @@
#error "C++11 or later is required. Add -std=c++11"
#endif
-// NOTE: We set some defines with some data types declared by raylib
+// NOTE: Set some defines with some data types declared by raylib
// Other modules (raymath, rlgl) also require some of those types, so,
// to be able to use those other modules as standalone (not depending on raylib)
// this defines are very useful for internal check and avoid type (re)definitions
@@ -1673,7 +1672,7 @@ RLAPI void ResumeSound(Sound sound); // Resume
RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing
RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
-RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (0.5 is center)
+RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)
RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave
RLAPI void WaveCrop(Wave *wave, int initFrame, int finalFrame); // Crop a wave to defined frames range
RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format
@@ -1694,7 +1693,7 @@ RLAPI void ResumeMusicStream(Music music); // Resume
RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds)
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
-RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (0.5 is center)
+RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (-1.0 left, 0.0 center, 1.0 right)
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
diff --git a/src/raymath.h b/src/raymath.h
index 65a20de59..32dfd2b0a 100644
--- a/src/raymath.h
+++ b/src/raymath.h
@@ -2552,7 +2552,38 @@ RMAPI int QuaternionEquals(Quaternion p, Quaternion q)
return result;
}
+// Compose a transformation matrix from rotational, translational and scaling components
+// TODO: This function is not following raymath conventions defined in header: NOT self-contained
+RMAPI Matrix MatrixCompose(Vector3 translation, Quaternion rotation, Vector3 scale)
+{
+ // Initialize vectors
+ Vector3 right = { 1.0f, 0.0f, 0.0f };
+ Vector3 up = { 0.0f, 1.0f, 0.0f };
+ Vector3 forward = { 0.0f, 0.0f, 1.0f };
+
+ // Scale vectors
+ right = Vector3Scale(right, scale.x);
+ up = Vector3Scale(up, scale.y);
+ forward = Vector3Scale(forward , scale.z);
+
+ // Rotate vectors
+ right = Vector3RotateByQuaternion(right, rotation);
+ up = Vector3RotateByQuaternion(up, rotation);
+ forward = Vector3RotateByQuaternion(forward, rotation);
+
+ // Set result matrix output
+ Matrix result = {
+ right.x, up.x, forward.x, translation.x,
+ right.y, up.y, forward.y, translation.y,
+ right.z, up.z, forward.z, translation.z,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+
+ return result;
+}
+
// Decompose a transformation matrix into its rotational, translational and scaling components and remove shear
+// TODO: This function is not following raymath conventions defined in header: NOT self-contained
RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale)
{
float eps = (float)1e-9;
@@ -2587,10 +2618,7 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio
// X Scale
scl.x = Vector3Length(matColumns[0]);
- if (scl.x > eps)
- {
- matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x);
- }
+ if (scl.x > eps) matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x);
// Compute XY shear and make col2 orthogonal
shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]);
diff --git a/src/rcore.c b/src/rcore.c
index 350490ad1..88448bdfe 100644
--- a/src/rcore.c
+++ b/src/rcore.c
@@ -26,10 +26,13 @@
* - Linux DRM subsystem (KMS mode)
* > PLATFORM_ANDROID:
* - Android (ARM, ARM64)
-*
+* > PLATFORM_DESKTOP_WIN32 (Native Win32):
+* - Windows (Win32, Win64)
+* > PLATFORM_MEMORY
+* - Memory framebuffer output, using software renderer, no OS required
* CONFIGURATION:
* #define SUPPORT_DEFAULT_FONT (default)
-* Default font is loaded on window initialization to be available for the user to render simple text.
+* 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 (module: text)
*
* #define SUPPORT_CAMERA_SYSTEM
@@ -40,7 +43,7 @@
* Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
*
* #define SUPPORT_MOUSE_GESTURES
-* Mouse gestures are directly mapped like touches and processed by gestures system.
+* Mouse gestures are directly mapped like touches and processed by gestures system
*
* #define SUPPORT_BUSY_WAIT_LOOP
* Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
@@ -51,9 +54,6 @@
* #define SUPPORT_SCREEN_CAPTURE
* Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
*
-* #define SUPPORT_GIF_RECORDING
-* Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
-*
* #define SUPPORT_COMPRESSION_API
* Support CompressData() and DecompressData() functions, those functions use zlib implementation
* provided by stb_image and stb_image_write libraries, so, those libraries must be enabled on textures module
@@ -94,12 +94,12 @@
//----------------------------------------------------------------------------------
#if (defined(__linux__) || defined(PLATFORM_WEB) || defined(PLATFORM_WEB_RGFW)) && (_XOPEN_SOURCE < 500)
#undef _XOPEN_SOURCE
- #define _XOPEN_SOURCE 500 // Required for: readlink if compiled with c99 without gnu ext.
+ #define _XOPEN_SOURCE 500 // Required for: readlink if compiled with c99 without GNU extensions
#endif
#if (defined(__linux__) || defined(PLATFORM_WEB) || defined(PLATFORM_WEB_RGFW)) && (_POSIX_C_SOURCE < 199309L)
#undef _POSIX_C_SOURCE
- #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext.
+ #define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without GNU extensions
#endif
#include "raylib.h" // Declares module functions
@@ -117,6 +117,9 @@
#include // Required for: time() [Used in InitTimer()]
#include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
+#if defined(PLATFORM_MEMORY)
+ #define SW_GL_FRAMEBUFFER_COPY_BGRA false
+#endif
#define RLGL_IMPLEMENTATION
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
@@ -133,15 +136,6 @@
#include "rcamera.h" // Camera system functionality
#endif
-#if defined(SUPPORT_GIF_RECORDING)
- #define MSF_GIF_MALLOC(contextPointer, newSize) RL_MALLOC(newSize)
- #define MSF_GIF_REALLOC(contextPointer, oldMemory, oldSize, newSize) RL_REALLOC(oldMemory, newSize)
- #define MSF_GIF_FREE(contextPointer, oldMemory, oldSize) RL_FREE(oldMemory)
-
- #define MSF_GIF_IMPL
- #include "external/msf_gif.h" // GIF recording functionality
-#endif
-
#if defined(SUPPORT_COMPRESSION_API)
#define SINFL_IMPLEMENTATION
#define SINFL_NO_SIMD
@@ -161,20 +155,23 @@
#endif
// Platform specific defines to handle GetApplicationDirectory()
-#if (defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)) || (defined(_MSC_VER) && defined(PLATFORM_DESKTOP_RGFW))
+#if defined(_WIN32)
+ #if !defined(MAX_PATH)
+ #define MAX_PATH 260
+ #endif
-struct HINSTANCE__;
-#if defined(__cplusplus)
-extern "C" {
-#endif
-__declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(struct HINSTANCE__ *hModule, char *lpFilename, unsigned long nSize);
-__declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(struct HINSTANCE__ *hModule, wchar_t *lpFilename, unsigned long nSize);
-__declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
-__declspec(dllimport) unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod);
-__declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
-#if defined(__cplusplus)
-}
-#endif
+ struct HINSTANCE__;
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+ __declspec(dllimport) unsigned long __stdcall GetModuleFileNameA(struct HINSTANCE__ *hModule, char *lpFilename, unsigned long nSize);
+ __declspec(dllimport) unsigned long __stdcall GetModuleFileNameW(struct HINSTANCE__ *hModule, wchar_t *lpFilename, unsigned long nSize);
+ __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
+ __declspec(dllimport) unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod);
+ __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
+ #if defined(__cplusplus)
+ }
+ #endif
#elif defined(__linux__)
#include
#elif defined(__FreeBSD__)
@@ -276,7 +273,7 @@ __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod)
#define FLAG_SET(n, f) ((n) |= (f))
#define FLAG_CLEAR(n, f) ((n) &= ~(f))
#define FLAG_TOGGLE(n, f) ((n) ^= (f))
-#define FLAG_CHECK(n, f) ((n) & (f))
+#define FLAG_IS_SET(n, f) (((n) & (f)) > 0)
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -322,7 +319,8 @@ typedef struct CoreData {
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 prev vs cur key state, we need to handle key repeats specially
+ // 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
int keyPressedQueue[MAX_KEY_PRESSED_QUEUE]; // Input keys queue
@@ -398,12 +396,6 @@ bool isGpuReady = false;
static int screenshotCounter = 0; // Screenshots counter
#endif
-#if defined(SUPPORT_GIF_RECORDING)
-static unsigned int gifFrameCounter = 0; // GIF frames counter
-static bool gifRecording = false; // GIF recording state
-static MsfGifState gifState = { 0 }; // MSGIF context state
-#endif
-
#if defined(SUPPORT_AUTOMATION_EVENTS)
// Automation events type
typedef enum AutomationEventType {
@@ -437,7 +429,7 @@ typedef enum AutomationEventType {
} AutomationEventType;
// Event type to config events flags
-// TODO: Not used at the moment
+// WARNING: Not used at the moment
typedef enum {
EVENT_INPUT_KEYBOARD = 0,
EVENT_INPUT_MOUSE = 1,
@@ -544,12 +536,6 @@ const char *TextFormat(const char *text, ...); // Formatting of text with variab
#if (!defined(SUPPORT_FILEFORMAT_PNG) || !defined(SUPPORT_FILEFORMAT_JPG)) && !defined(_WIN32)
#pragma message ("WARNING: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
#endif
-
- // Not needed because 'rtexture.c' will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined
- // #if !defined(STBI_REQUIRED)
- // #pragma message ("WARNING: "STBI_REQUIRED is not defined, that means we can't load images from clipbard"
- // #endif
-
#endif // SUPPORT_CLIPBOARD_IMAGE
// Include platform-specific submodules
@@ -567,6 +553,8 @@ const char *TextFormat(const char *text, ...); // Formatting of text with variab
#include "platforms/rcore_drm.c"
#elif defined(PLATFORM_ANDROID)
#include "platforms/rcore_android.c"
+#elif defined(PLATFORM_MEMORY)
+ #include "platforms/rcore_memory.c"
#else
// TODO: Include your custom platform backend!
// i.e software rendering backend or console backend!
@@ -641,6 +629,8 @@ void InitWindow(int width, int height, const char *title)
TRACELOG(LOG_INFO, "Platform backend: NATIVE DRM");
#elif defined(PLATFORM_ANDROID)
TRACELOG(LOG_INFO, "Platform backend: ANDROID");
+#elif defined(PLATFORM_MEMORY)
+ TRACELOG(LOG_INFO, "Platform backend: MEMORY (No OS)");
#else
// TODO: Include your custom platform backend!
// i.e software rendering backend or console backend!
@@ -705,7 +695,7 @@ void InitWindow(int width, int height, const char *title)
//--------------------------------------------------------------
// Initialize rlgl default data (buffers and shaders)
- // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
+ // NOTE: Current fbo size stored as globals in rlgl for convenience
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
isGpuReady = true; // Flag to note GPU has been initialized successfully
@@ -721,7 +711,7 @@ void InitWindow(int width, int height, const char *title)
// Set font white rectangle for shapes drawing, so shapes and text can be batched together
// WARNING: rshapes module is required, if not available, default internal white rectangle is used
Rectangle rec = GetFontDefault().recs[95];
- if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
{
// NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
@@ -754,15 +744,6 @@ void InitWindow(int width, int height, const char *title)
// Close window and unload OpenGL context
void CloseWindow(void)
{
-#if defined(SUPPORT_GIF_RECORDING)
- if (gifRecording)
- {
- MsfGifResult result = msf_gif_end(&gifState);
- msf_gif_free(result);
- gifRecording = false;
- }
-#endif
-
#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
UnloadFontDefault(); // WARNING: Module required: rtext
#endif
@@ -793,25 +774,25 @@ bool IsWindowFullscreen(void)
// Check if window is currently hidden
bool IsWindowHidden(void)
{
- return ((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0);
+ return (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIDDEN));
}
// Check if window has been minimized
bool IsWindowMinimized(void)
{
- return ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0);
+ return (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED));
}
// Check if window has been maximized
bool IsWindowMaximized(void)
{
- return ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0);
+ return (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED));
}
// Check if window has the focus
bool IsWindowFocused(void)
{
- return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0);
+ return (!FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED));
}
// Check if window has been resizedLastFrame
@@ -823,7 +804,7 @@ bool IsWindowResized(void)
// Check if one specific window flag is enabled
bool IsWindowState(unsigned int flag)
{
- return ((CORE.Window.flags & flag) > 0);
+ return (FLAG_IS_SET(CORE.Window.flags, flag));
}
// Get current screen width
@@ -925,47 +906,6 @@ void EndDrawing(void)
{
rlDrawRenderBatchActive(); // Update and draw internal render batch
-#if defined(SUPPORT_GIF_RECORDING)
- // Draw record indicator
- if (gifRecording)
- {
- #ifndef GIF_RECORD_FRAMERATE
- #define GIF_RECORD_FRAMERATE 10
- #endif
- gifFrameCounter += (unsigned int)(GetFrameTime()*1000);
-
- // NOTE: We record one gif frame depending on the desired gif framerate
- if (gifFrameCounter > 1000/GIF_RECORD_FRAMERATE)
- {
- // Get image data for the current frame (from backbuffer)
- // NOTE: This process is quite slow... :(
- Vector2 scale = GetWindowScaleDPI();
- unsigned char *screenData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
-
- #ifndef GIF_RECORD_BITRATE
- #define GIF_RECORD_BITRATE 16
- #endif
-
- // Add the frame to the gif recording, given how many frames have passed in centiseconds
- msf_gif_frame(&gifState, screenData, gifFrameCounter/10, GIF_RECORD_BITRATE, (int)((float)CORE.Window.render.width*scale.x)*4);
- gifFrameCounter -= 1000/GIF_RECORD_FRAMERATE;
-
- RL_FREE(screenData); // Free image data
- }
-
- #if defined(SUPPORT_MODULE_RSHAPES) && defined(SUPPORT_MODULE_RTEXT)
- // Display the recording indicator every half-second
- if ((int)(GetTime()/0.5)%2 == 1)
- {
- DrawCircle(30, CORE.Window.screen.height - 20, 10, MAROON); // WARNING: Module required: rshapes
- DrawText("GIF RECORDING", 50, CORE.Window.screen.height - 25, 10, RED); // WARNING: Module required: rtext
- }
- #endif
-
- rlDrawRenderBatchActive(); // Update and draw internal render batch
- }
-#endif
-
#if defined(SUPPORT_AUTOMATION_EVENTS)
if (automationEventRecording) RecordAutomationEvent(); // Event recording
#endif
@@ -998,38 +938,8 @@ void EndDrawing(void)
#if defined(SUPPORT_SCREEN_CAPTURE)
if (IsKeyPressed(KEY_F12))
{
-#if defined(SUPPORT_GIF_RECORDING)
- if (IsKeyDown(KEY_LEFT_CONTROL))
- {
- if (gifRecording)
- {
- gifRecording = false;
-
- MsfGifResult result = msf_gif_end(&gifState);
-
- SaveFileData(TextFormat("%s/screenrec%03i.gif", CORE.Storage.basePath, screenshotCounter), result.data, (unsigned int)result.dataSize);
- msf_gif_free(result);
-
- TRACELOG(LOG_INFO, "SYSTEM: Finish animated GIF recording");
- }
- else
- {
- gifRecording = true;
- gifFrameCounter = 0;
-
- Vector2 scale = GetWindowScaleDPI();
- msf_gif_begin(&gifState, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
- screenshotCounter++;
-
- TRACELOG(LOG_INFO, "SYSTEM: Start animated GIF recording: %s", TextFormat("screenrec%03i.gif", screenshotCounter));
- }
- }
- else
-#endif // SUPPORT_GIF_RECORDING
- {
- TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
- screenshotCounter++;
- }
+ TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
+ screenshotCounter++;
}
#endif // SUPPORT_SCREEN_CAPTURE
@@ -1204,7 +1114,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 && ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0))
+ 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));
@@ -1361,14 +1271,14 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
{
// After custom shader loading, we TRY to set default location names
// Default shader attribute locations have been binded before linking:
- // vertex position location = 0
- // vertex texcoord location = 1
- // vertex normal location = 2
- // vertex color location = 3
- // vertex tangent location = 4
- // vertex texcoord2 location = 5
- // vertex boneIds location = 6
- // vertex boneWeights location = 7
+ // - vertex position location = 0
+ // - vertex texcoord location = 1
+ // - vertex normal location = 2
+ // - vertex color location = 3
+ // - vertex tangent location = 4
+ // - vertex texcoord2 location = 5
+ // - vertex boneIds location = 6
+ // - vertex boneWeights location = 7
// NOTE: If any location is not found, loc point becomes -1
@@ -1637,8 +1547,6 @@ Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int heigh
// Calculate view matrix from camera look at (and transpose it)
Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
- // TODO: Why not use Vector3Transform(Vector3 v, Matrix mat)?
-
// Convert world position vector to quaternion
Quaternion worldPos = { position.x, position.y, position.z, 1.0f };
@@ -1927,7 +1835,7 @@ void SetConfigFlags(unsigned int flags)
// Selected flags are set but not evaluated at this point,
// flag evaluation happens at InitWindow() or SetWindowState()
- CORE.Window.flags |= flags;
+ FLAG_SET(CORE.Window.flags, flags);
}
//----------------------------------------------------------------------------------
@@ -2335,13 +2243,15 @@ const char *GetApplicationDirectory(void)
#if defined(_WIN32)
int len = 0;
-#if defined(UNICODE)
+
+ #if defined(UNICODE)
unsigned short widePath[MAX_PATH];
len = GetModuleFileNameW(NULL, (wchar_t *)widePath, MAX_PATH);
len = WideCharToMultiByte(0, 0, (wchar_t *)widePath, len, appDir, MAX_PATH, NULL, NULL);
-#else
+ #else
len = GetModuleFileNameA(NULL, appDir, MAX_PATH);
-#endif
+ #endif
+
if (len > 0)
{
for (int i = len; i >= 0; --i)
@@ -2358,8 +2268,9 @@ const char *GetApplicationDirectory(void)
appDir[0] = '.';
appDir[1] = '\\';
}
-
+
#elif defined(__linux__)
+
unsigned int size = sizeof(appDir);
ssize_t len = readlink("/proc/self/exe", appDir, size);
@@ -2379,7 +2290,9 @@ const char *GetApplicationDirectory(void)
appDir[0] = '.';
appDir[1] = '/';
}
+
#elif defined(__APPLE__)
+
uint32_t size = sizeof(appDir);
if (_NSGetExecutablePath(appDir, &size) == 0)
@@ -2399,7 +2312,9 @@ const char *GetApplicationDirectory(void)
appDir[0] = '.';
appDir[1] = '/';
}
+
#elif defined(__FreeBSD__)
+
size_t size = sizeof(appDir);
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
@@ -2420,7 +2335,6 @@ const char *GetApplicationDirectory(void)
appDir[0] = '.';
appDir[1] = '/';
}
-
#endif
return appDir;
@@ -2578,8 +2492,6 @@ bool IsFileNameValid(const char *fileName)
// Check non-glyph characters
if ((unsigned char)fileName[i] < 32) { valid = false; break; }
- // TODO: Check trailing periods/spaces?
-
// Check if filename is not all periods
if (fileName[i] != '.') allPeriods = false;
}
@@ -2988,7 +2900,7 @@ unsigned int *ComputeMD5(unsigned char *data, int dataSize)
// NOTE: Returns a static int[5] array (20 bytes)
unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
{
- #define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
+ #define SHA1_ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
static unsigned int hash[5] = { 0 }; // Hash to be returned
@@ -3031,7 +2943,7 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
}
// Message schedule: extend the sixteen 32-bit words into eighty 32-bit words:
- for (int i = 16; i < 80; i++) w[i] = ROTATE_LEFT(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
+ for (int i = 16; i < 80; i++) w[i] = SHA1_ROTATE_LEFT(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
// Initialize hash value for this chunk
unsigned int a = hash[0];
@@ -3066,10 +2978,10 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
k = 0xCA62C1D6;
}
- unsigned int temp = ROTATE_LEFT(a, 5) + f + e + k + w[i];
+ unsigned int temp = SHA1_ROTATE_LEFT(a, 5) + f + e + k + w[i];
e = d;
d = c;
- c = ROTATE_LEFT(b, 30);
+ c = SHA1_ROTATE_LEFT(b, 30);
b = a;
a = temp;
}
@@ -3091,9 +3003,9 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
// NOTE: Returns a static int[8] array (32 bytes)
unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
{
- #define ROTATE_RIGHT(x, c) ((x >> c) | (x << ((sizeof(unsigned int) * 8) - c)))
- #define SHA256_A0(x) (ROTATE_RIGHT(x, 7) ^ ROTATE_RIGHT(x, 18) ^ (x >> 3))
- #define SHA256_A1(x) (ROTATE_RIGHT(x, 17) ^ ROTATE_RIGHT(x, 19) ^ (x >> 10))
+ #define SHA256_ROTATE_RIGHT(x, c) ((x >> c) | (x << ((sizeof(unsigned int)*8) - c)))
+ #define SHA256_A0(x) (SHA256_ROTATE_RIGHT(x, 7) ^ SHA256_ROTATE_RIGHT(x, 18) ^ (x >> 3))
+ #define SHA256_A1(x) (SHA256_ROTATE_RIGHT(x, 17) ^ SHA256_ROTATE_RIGHT(x, 19) ^ (x >> 10))
static const unsigned int k[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
@@ -3114,7 +3026,7 @@ unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
- static unsigned int hash[8];
+ static unsigned int hash[8] = { 0 };
hash[0] = 0x6A09e667;
hash[1] = 0xbb67ae85;
hash[2] = 0x3c6ef372;
@@ -3127,12 +3039,14 @@ unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
const unsigned long long int bitLen = ((unsigned long long int)dataSize)*8;
unsigned long long int paddedSize = dataSize + sizeof(dataSize);
paddedSize += (64 - (paddedSize%64));
- unsigned char *buffer = RL_CALLOC(paddedSize, sizeof(unsigned char));
+ unsigned char *buffer = (unsigned char *)RL_CALLOC(paddedSize, sizeof(unsigned char));
memcpy(buffer, data, dataSize);
buffer[dataSize] = 0x80;
for (int i = 1; i <= sizeof(bitLen); i++)
+ {
buffer[(paddedSize - sizeof(bitLen)) + (i - 1)] = (bitLen >> (8*(sizeof(bitLen) - i))) & 0xFF;
+ }
for (unsigned long long int blockN = 0; blockN < paddedSize/64; blockN++)
{
@@ -3146,23 +3060,22 @@ unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
unsigned int h = hash[7];
unsigned char *block = buffer + (blockN*64);
- unsigned int w[64];
+ unsigned int w[64] = { 0 };
for (int i = 0; i < 16; i++)
{
- w[i] =
- ((unsigned int)block[i*4 + 0] << 24) |
- ((unsigned int)block[i*4 + 1] << 16) |
- ((unsigned int)block[i*4 + 2] << 8) |
- ((unsigned int)block[i*4 + 3]);
+ w[i] = ((unsigned int)block[i*4 + 0] << 24) |
+ ((unsigned int)block[i*4 + 1] << 16) |
+ ((unsigned int)block[i*4 + 2] << 8) |
+ ((unsigned int)block[i*4 + 3]);
}
for (int t = 16; t < 64; t++) w[t] = SHA256_A1(w[t - 2]) + w[t - 7] + SHA256_A0(w[t - 15]) + w[t - 16];
for (unsigned long long int t = 0; t < 64; t++)
{
- unsigned int e1 = (ROTATE_RIGHT(e, 6) ^ ROTATE_RIGHT(e, 11) ^ ROTATE_RIGHT(e, 25));
+ unsigned int e1 = (SHA256_ROTATE_RIGHT(e, 6) ^ SHA256_ROTATE_RIGHT(e, 11) ^ SHA256_ROTATE_RIGHT(e, 25));
unsigned int ch = ((e & f) ^ (~e & g));
unsigned int t1 = (h + e1 + ch + k[t] + w[t]);
- unsigned int e0 = (ROTATE_RIGHT(a, 2) ^ ROTATE_RIGHT(a, 13) ^ ROTATE_RIGHT(a, 22));
+ unsigned int e0 = (SHA256_ROTATE_RIGHT(a, 2) ^ SHA256_ROTATE_RIGHT(a, 13) ^ SHA256_ROTATE_RIGHT(a, 22));
unsigned int maj = ((a & b) ^ (a & c) ^ (b & c));
unsigned int t2 = e0 + maj;
@@ -3185,7 +3098,9 @@ unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
hash[6] += g;
hash[7] += h;
}
+
RL_FREE(buffer);
+
return hash;
}
@@ -3301,7 +3216,7 @@ bool ExportAutomationEventList(AutomationEventList list, const char *fileName)
*/
// Export events as text
- // TODO: Save to memory buffer and SaveFileText()
+ // NOTE: Save to memory buffer and SaveFileText()
char *txtData = (char *)RL_CALLOC(256*list.count + 2048, sizeof(char)); // 256 characters per line plus some header
int byteCount = 0;
@@ -3370,7 +3285,7 @@ void PlayAutomationEvent(AutomationEvent event)
#if defined(SUPPORT_AUTOMATION_EVENTS)
// WARNING: When should event be played? After/before/replace PollInputEvents()? -> Up to the user!
- if (!automationEventRecording) // TODO: Allow recording events while playing?
+ if (!automationEventRecording)
{
switch (event.type)
{
@@ -3807,7 +3722,6 @@ int GetTouchY(void)
}
// Get touch position XY for a touch point index (relative to screen size)
-// TODO: Touch position should be scaled depending on display size and render size
Vector2 GetTouchPosition(int index)
{
Vector2 position = { -1.0f, -1.0f };
@@ -3850,20 +3764,20 @@ void InitTimer(void)
// High resolutions can also prevent the CPU power management system from entering power-saving modes
// Setting a higher resolution does not improve the accuracy of the high-resolution performance counter
#if defined(_WIN32) && defined(SUPPORT_WINMM_HIGHRES_TIMER) && !defined(SUPPORT_BUSY_WAIT_LOOP) && !defined(PLATFORM_DESKTOP_SDL)
- timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
+ timeBeginPeriod(1); // Setup high-resolution timer to 1ms (granularity of 1-2 ms)
#endif
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
struct timespec now = { 0 };
- if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
+ if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) // Success
{
CORE.Time.base = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec;
}
else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available");
#endif
- CORE.Time.previous = GetTime(); // Get time as double
+ CORE.Time.previous = GetTime(); // Get time as double
}
// Set viewport for a provided width and height
@@ -3989,6 +3903,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
if ((strcmp(dp->d_name, ".") != 0) &&
(strcmp(dp->d_name, "..") != 0))
{
+ // Construct new path from our base path
#if defined(_WIN32)
int pathLength = snprintf(path, MAX_FILEPATH_LENGTH - 1, "%s\\%s", basePath, dp->d_name);
#else
@@ -4106,13 +4021,11 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
#if defined(SUPPORT_AUTOMATION_EVENTS)
// Automation event recording
+// Checking events in current frame and save them into currentEventList
// NOTE: Recording is by default done at EndDrawing(), before PollInputEvents()
static void RecordAutomationEvent(void)
{
- // Checking events in current frame and save them into currentEventList
- // TODO: How important is the current frame? Could it be modified?
-
- if (currentEventList->count == currentEventList->capacity) return; // Security check
+ if (currentEventList->count == currentEventList->capacity) return;
// Keyboard input events recording
//-------------------------------------------------------------------------------------
diff --git a/src/rlgl.h b/src/rlgl.h
index e6a1c9432..6884ad183 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -21,6 +21,7 @@
* Internal buffer (and resources) must be manually unloaded calling rlglClose()
*
* CONFIGURATION:
+* #define GRAPHICS_API_OPENGL_11_SOFTWARE
* #define GRAPHICS_API_OPENGL_11
* #define GRAPHICS_API_OPENGL_21
* #define GRAPHICS_API_OPENGL_33
@@ -775,10 +776,9 @@ RLAPI unsigned int rlLoadFramebuffer(void); // Loa
RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer
RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete
RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+// WARNING: Copy and resize framebuffer functionality only defined for software backend
RLAPI void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels); // Copy framebuffer pixel data to internal buffer
RLAPI void rlResizeFramebuffer(int width, int height); // Resize internal framebuffer
-#endif
// Shaders management
RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings
@@ -902,6 +902,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
// It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi
// provided headers (despite being defined in official Khronos GLES2 headers)
+ // TODO: Avoid raylib platform-dependant code on rlgl, it should be a completely portable library
#if defined(PLATFORM_DRM)
typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);
typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
@@ -1251,7 +1252,7 @@ void rlPushMatrix(void)
RLGL.State.stackCounter++;
}
-// Pop lattest inserted matrix from RLGL.State.stack
+// Pop latest inserted matrix from RLGL.State.stack
void rlPopMatrix(void)
{
if (RLGL.State.stackCounter > 0)
@@ -2920,7 +2921,7 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
batch.bufferCount = numBuffers; // Record buffer count
batch.drawCounter = 1; // Reset draws counter
- batch.currentDepth = -1.0f; // Reset depth value
+ batch.currentDepth = -1.0f; // Reset depth value
//--------------------------------------------------------------------------------------------
#endif
@@ -2981,7 +2982,8 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
// Update batch vertex buffers
//------------------------------------------------------------------------------------------------------------
// NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0)
- // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (use a change detector flag?)
+ // TODO: If no data changed on the CPU arrays there is no need to re-upload data to GPU,
+ // a flag can be used to detect changes but it would imply keeping a copy buffer and memcmp() both, does it worth it?
if (RLGL.State.vertexCounter > 0)
{
// Activate elements VAO
@@ -3747,21 +3749,23 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
return pixels;
}
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
// Copy framebuffer pixel data to internal buffer
void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels)
{
+#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
unsigned int glInternalFormat, glFormat, glType;
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); // Get OpenGL texture format
swCopyFramebuffer(x, y, width, height, glFormat, glType, pixels);
+#endif
}
// Resize internal framebuffer
void rlResizeFramebuffer(int width, int height)
{
+#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
swResizeFramebuffer(width, height);
-}
#endif
+}
// Read screen pixel data (color buffer)
unsigned char *rlReadScreenPixels(int width, int height)
@@ -3899,7 +3903,7 @@ void rlUnloadFramebuffer(unsigned int id)
// TODO: Review warning retrieving object name in WebGL
// WARNING: WebGL: INVALID_ENUM: getFramebufferAttachmentParameter: invalid parameter name
- // https://registry.khronos.org/webgl/specs/latest/1.0/
+ // Ref: https://registry.khronos.org/webgl/specs/latest/1.0/
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthId);
unsigned int depthIdU = (unsigned int)depthId;
@@ -4426,8 +4430,6 @@ void rlSetUniform(int locIndex, const void *value, int uniformType, int count)
#endif
case RL_SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break;
default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized");
-
- // TODO: Support glUniform1uiv(), glUniform2uiv(), glUniform3uiv(), glUniform4uiv()
}
#endif
}
@@ -4468,7 +4470,7 @@ void rlSetUniformMatrices(int locIndex, const Matrix *matrices, int count)
glUniformMatrix4fv(locIndex, count, true, (const float *)matrices);
#elif defined(GRAPHICS_API_OPENGL_ES2)
// WARNING: WebGL does not support Matrix transpose ("true" parameter)
- // REF: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/uniformMatrix
+ // Ref: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/uniformMatrix
glUniformMatrix4fv(locIndex, count, false, (const float *)matrices);
#endif
}
diff --git a/src/rmodels.c b/src/rmodels.c
index 3c904c396..fad6ae78b 100644
--- a/src/rmodels.c
+++ b/src/rmodels.c
@@ -1435,7 +1435,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
#define GL_COLOR_ARRAY 0x8076
#define GL_TEXTURE_COORD_ARRAY 0x8078
- rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
+ if (mesh.texcoords && material.maps[MATERIAL_MAP_DIFFUSE].texture.id > 0) rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
if (mesh.animVertices) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animVertices);
else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
@@ -2352,8 +2352,6 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
Mesh mesh = model.meshes[m];
Vector3 animVertex = { 0 };
Vector3 animNormal = { 0 };
- Matrix boneMatrix = { 0 };
- Matrix InverseBoneMatrix = { 0 };
int boneId = 0;
int boneCounter = 0;
float boneWeight = 0.0;
@@ -2361,50 +2359,47 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
const int vValues = mesh.vertexCount*3;
// Skip if missing bone data, causes segfault without on some models
- if ((mesh.boneWeights == NULL) || (mesh.boneIds == NULL)) continue;
+ if ((mesh.boneWeights == NULL) || (mesh.boneIds == NULL)) continue;
- // Iterates over 4 bones per vertex
- for (int j = 0; j < 4; j++, boneCounter++)
- {
- boneWeight = mesh.boneWeights[boneCounter];
- boneId = mesh.boneIds[boneCounter];
+ for (int vCounter = 0; vCounter < vValues; vCounter += 3)
+ {
+ mesh.animVertices[vCounter] = 0;
+ mesh.animVertices[vCounter + 1] = 0;
+ mesh.animVertices[vCounter + 2] = 0;
+ if (mesh.animNormals != NULL)
+ {
+ mesh.animNormals[vCounter] = 0;
+ mesh.animNormals[vCounter + 1] = 0;
+ mesh.animNormals[vCounter + 2] = 0;
+ }
- // Early stop when no transformation will be applied
- if (boneWeight == 0.0f) continue;
+ // Iterates over 4 bones per vertex
+ for (int j = 0; j < 4; j++, boneCounter++)
+ {
+ boneWeight = mesh.boneWeights[boneCounter];
+ boneId = mesh.boneIds[boneCounter];
- boneMatrix = model.meshes[m].boneMatrices[boneId];
- InverseBoneMatrix = MatrixTranspose(MatrixInvert(boneMatrix));
+ // Early stop when no transformation will be applied
+ if (boneWeight == 0.0f) continue;
+ animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
+ animVertex = Vector3Transform(animVertex,model.meshes[m].boneMatrices[boneId]);
+ mesh.animVertices[vCounter] += animVertex.x*boneWeight;
+ mesh.animVertices[vCounter+1] += animVertex.y*boneWeight;
+ mesh.animVertices[vCounter+2] += animVertex.z*boneWeight;
+ updated = true;
- for (int vCounter = 0; vCounter < vValues; vCounter += 3)
- {
- mesh.animVertices[vCounter] = 0;
- mesh.animVertices[vCounter + 1] = 0;
- mesh.animVertices[vCounter + 2] = 0;
- if (mesh.animNormals != NULL)
- {
- mesh.animNormals[vCounter] = 0;
- mesh.animNormals[vCounter + 1] = 0;
- mesh.animNormals[vCounter + 2] = 0;
- }
- animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
- animVertex = Vector3Transform(animVertex, boneMatrix);
- mesh.animVertices[vCounter] += animVertex.x*boneWeight;
- mesh.animVertices[vCounter+1] += animVertex.y*boneWeight;
- mesh.animVertices[vCounter+2] += animVertex.z*boneWeight;
- updated = true;
-
- // Normals processing
- // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
- if ((mesh.normals != NULL) && (mesh.animNormals != NULL))
- {
- animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
- animNormal = Vector3Transform(animNormal, InverseBoneMatrix);
- mesh.animNormals[vCounter] += animNormal.x*boneWeight;
- mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
- mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
- }
- }
- }
+ // Normals processing
+ // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
+ if ((mesh.normals != NULL) && (mesh.animNormals != NULL ))
+ {
+ animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
+ animNormal = Vector3Transform(animNormal, MatrixTranspose(MatrixInvert(model.meshes[m].boneMatrices[boneId])));
+ mesh.animNormals[vCounter] += animNormal.x*boneWeight;
+ mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
+ mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
+ }
+ }
+ }
if (updated)
{
@@ -3294,7 +3289,7 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
for (int z = 0; z < cubicmap.height; ++z)
{
- for (int x = 0; x < cubicmap.width; ++x)
+ for (int x = 0; x < cubicmap.width; x++)
{
// Define the 8 vertex of the cube, we will combine them accordingly later...
Vector3 v1 = { w*(x - 0.5f), h2, h*(z - 0.5f) };
@@ -3850,7 +3845,6 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float
// Draw a model points
// WARNING: OpenGL ES 2.0 does not support point mode drawing
-// TODO: gate these properly for non es 2.0 versions only
void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
{
rlEnablePointMode();
@@ -4434,10 +4428,12 @@ static Model LoadOBJ(const char *fileName)
model.meshes[i].vertices = (float *)MemAlloc(sizeof(float)*vertexCount*3);
model.meshes[i].normals = (float *)MemAlloc(sizeof(float)*vertexCount*3);
- model.meshes[i].texcoords = (float *)MemAlloc(sizeof(float)*vertexCount*2);
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+ model.meshes[i].texcoords = (float *)MemAlloc(sizeof(float)*vertexCount*2);
model.meshes[i].colors = (unsigned char *)MemAlloc(sizeof(unsigned char)*vertexCount*4);
#else
+ if (objAttributes.texcoords != NULL && objAttributes.num_texcoords > 0) model.meshes[i].texcoords = (float *)MemAlloc(sizeof(float)*vertexCount*2);
+ else model.meshes[i].texcoords = NULL;
model.meshes[i].colors = NULL;
#endif
}
@@ -4493,16 +4489,11 @@ static Model LoadOBJ(const char *fileName)
for (int i = 0; i < 3; i++) model.meshes[meshIndex].vertices[localMeshVertexCount*3 + i] = objAttributes.vertices[vertIndex*3 + i];
- if ((objAttributes.texcoords != NULL) && (texcordIndex != TINYOBJ_INVALID_INDEX) && (texcordIndex >= 0))
+ if ((objAttributes.texcoords != NULL) && (texcordIndex != TINYOBJ_INVALID_INDEX) && (texcordIndex >= 0) && (model.meshes[meshIndex].texcoords))
{
for (int i = 0; i < 2; i++) model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + i] = objAttributes.texcoords[texcordIndex*2 + i];
model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1];
}
- else
- {
- model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 0] = 0.0f;
- model.meshes[meshIndex].texcoords[localMeshVertexCount*2 + 1] = 0.0f;
- }
if ((objAttributes.normals != NULL) && (normalIndex != TINYOBJ_INVALID_INDEX) && (normalIndex >= 0))
{
@@ -5027,9 +5018,9 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
animations[a].boneCount = iqmHeader->num_poses;
animations[a].bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
animations[a].framePoses = (Transform **)RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
- memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32); // I don't like this 32 here
+ memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32);
TRACELOG(LOG_INFO, "IQM Anim %s", animations[a].name);
- // animations[a].framerate = anim.framerate; // TODO: Use animation framerate data?
+ //animations[a].framerate = anim.framerate; // TODO: Use animation framerate data?
for (unsigned int j = 0; j < iqmHeader->num_poses; j++)
{
@@ -5037,7 +5028,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
if (iqmHeader->num_joints > 0)
memcpy(animations[a].bones[j].name, fileDataPtr + iqmHeader->ofs_text + joints[j].name, BONE_NAME_LENGTH*sizeof(char));
else
- strcpy(animations[a].bones[j].name, "ANIMJOINTNAME"); // default bone name otherwise
+ strcpy(animations[a].bones[j].name, "ANIMJOINTNAME"); // Default bone name otherwise
animations[a].bones[j].parent = poses[j].parent;
}
@@ -5883,8 +5874,8 @@ static Model LoadGLTF(const char *fileName)
//----------------------------------------------------------------------------------------------------
// Load animation data
- // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins
- // REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes
+ // Ref: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins
+ // Ref: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes
//
// LIMITATIONS:
// - Only supports 1 armature per file, and skips loading it if there are multiple armatures
diff --git a/src/rshapes.c b/src/rshapes.c
index 2b5854f86..528a362d5 100644
--- a/src/rshapes.c
+++ b/src/rshapes.c
@@ -1169,9 +1169,9 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
}
// Draw rectangle with rounded edges
-// TODO: This function should be refactored to use RL_LINES, for consistency with other Draw*Lines()
void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color)
{
+ // NOTE: For line thicknes <=1.0f we use RL_LINES, otherwise wee use RL_QUADS/RL_TRIANGLES
DrawRectangleRoundedLinesEx(rec, roundness, segments, 1.0f, color);
}
@@ -1395,7 +1395,6 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
{
// Use LINES to draw the outline
rlBegin(RL_LINES);
-
// Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
{
@@ -1418,7 +1417,6 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f
rlVertex2f(point[i].x, point[i].y);
rlVertex2f(point[i + 1].x, point[i + 1].y);
}
-
rlEnd();
}
}
diff --git a/src/rtext.c b/src/rtext.c
index b4cd560ba..8a3961a00 100644
--- a/src/rtext.c
+++ b/src/rtext.c
@@ -147,7 +147,7 @@ static int textLineSpacing = 2; // Text vertical line spacing in
static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file)
#endif
#if defined(SUPPORT_FILEFORMAT_BDF)
-static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, int *codepoints, int codepointCount, int *outFontSize);
+static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, const int *codepoints, int codepointCount, int *outFontSize);
#endif
#if defined(SUPPORT_DEFAULT_FONT)
@@ -647,7 +647,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
{
bool genFontChars = false;
stbtt_fontinfo fontInfo = { 0 };
- int *requiredCodepoints = (int *)codepoints;
+ int *requiredCodepoints = (int *)codepoints; // TODO: Should we create a shallow copy to avoid "dealing" with a const user array?
if (stbtt_InitFont(&fontInfo, (unsigned char *)fileData, 0)) // Initialize font for data reading
{
@@ -724,7 +724,8 @@ 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);
- if (cpHeight > fontSize) TRACELOG(LOG_WARNING, "FONT: [0x%04x] Glyph height is bigger than requested font size: %i > %i", cp, cpHeight, (int)fontSize);
+ // WARNING: If requested SDF font, sdf-glyph height is definitely bigger than fontSize due to FONT_SDF_CHAR_PADDING
+ if ((type != FONT_SDF) && (cpHeight > fontSize)) TRACELOG(LOG_WARNING, "FONT: [0x%04x] Glyph height is bigger than requested font size: %i > %i", cp, cpHeight, (int)fontSize);
// Load glyph image
glyphs[k].image.width = cpWidth;
@@ -1451,16 +1452,20 @@ Rectangle GetGlyphAtlasRec(Font font, int codepoint)
// NOTE: Returned lines end with null terminator '\0'
char **LoadTextLines(const char *text, int *count)
{
+ char **lines = NULL;
+
+ if (text == NULL) { *count = 0; return lines; }
+
int lineCount = 1;
int textSize = (int)strlen(text);
- // Text pass to get required line count
+ // First text scan pass to get required line count
for (int i = 0; i < textSize; i++)
{
if (text[i] == '\n') lineCount++;
}
- char **lines = (char **)RL_CALLOC(lineCount, sizeof(char *));
+ lines = (char **)RL_CALLOC(lineCount, sizeof(char *));
for (int i = 0, l = 0, lineLen = 0; i <= textSize; i++)
{
if ((text[i] == '\n') || (text[i] == '\0'))
@@ -1696,7 +1701,7 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
// Replace text string
// REQUIRES: strstr(), strncpy(), strcpy()
-// TODO: If (replacement == NULL) remove "search" text
+// TODO: If (replacement == "") remove "search" text
// WARNING: Allocated memory must be manually freed
char *TextReplace(const char *text, const char *search, const char *replacement)
{
@@ -1886,6 +1891,7 @@ void TextAppend(char *text, const char *append, int *position)
int TextFindIndex(const char *text, const char *search)
{
int position = -1;
+ if (text == NULL) return position;
char *ptr = (char *)strstr(text, search);
@@ -2517,7 +2523,7 @@ static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, c
char buffer[MAX_BUFFER_SIZE] = { 0 };
GlyphInfo *glyphs = NULL;
- bool genFontChars = false;
+ bool internalCodepoints = false;
int totalReadBytes = 0; // Data bytes read (total)
int readBytes = 0; // Data bytes read (line)
@@ -2545,21 +2551,23 @@ static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, c
int charDWidthX = 0; // Character advance X
int charDWidthY = 0; // Character advance Y (unused)
- GlyphInfo *glyphs = NULL; // Pointer to output glyph info (NULL if not set)
- int *requiredCodepoints = codepoints;
+ int *requiredCodepoints = (int *)RL_MALLOC(codepointCount*sizeof(int));
if (fileData == NULL) return glyphs;
// In case no chars count provided, default to 95
codepointCount = (codepointCount > 0)? codepointCount : 95;
- // Fill fontChars in case not provided externally
- // NOTE: By default we fill glyphCount consecutively, starting at 32 (Space)
- if (requiredCodepoints == NULL)
+ if (codepoints == NULL)
{
- requiredCodepoints = (int *)RL_MALLOC(codepointCount*sizeof(int));
+ // Fill internal codepoints array in case not provided externally
+ // NOTE: By default we fill glyphCount consecutively, starting at 32 (Space)
for (int i = 0; i < codepointCount; i++) requiredCodepoints[i] = i + 32;
- genFontChars = true;
+ internalCodepoints = true;
+ }
+ else
+ {
+ for (int i = 0; i < codepointCount; i++) requiredCodepoints[i] = codepoints[i];
}
glyphs = (GlyphInfo *)RL_CALLOC(codepointCount, sizeof(GlyphInfo));
@@ -2634,11 +2642,11 @@ static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, c
// Search for glyph index in codepoints
glyphs = NULL;
- for (int codepointIndex = 0; codepointIndex < codepointCount; codepointIndex++)
+ for (int index = 0; index < codepointCount; index++)
{
- if (codepoints[codepointIndex] == charEncoding)
+ if (requiredCodepoints[index] == charEncoding)
{
- glyphs = &glyphs[codepointIndex];
+ glyphs = &glyphs[index];
break;
}
}
@@ -2738,7 +2746,7 @@ static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, c
}
}
- if (genFontChars) RL_FREE(codepoints);
+ RL_FREE(requiredCodepoints);
if (fontMalformed)
{
diff --git a/src/rtextures.c b/src/rtextures.c
index ddaee2939..17065822a 100644
--- a/src/rtextures.c
+++ b/src/rtextures.c
@@ -514,7 +514,7 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i
image.data = qoi_decode(fileData, dataSize, &desc, (int) fileData[12]);
image.width = desc.width;
image.height = desc.height;
- image.format = desc.channels == 4 ? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : PIXELFORMAT_UNCOMPRESSED_R8G8B8;
+ image.format = (desc.channels == 4)? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : PIXELFORMAT_UNCOMPRESSED_R8G8B8;
image.mipmaps = 1;
}
}
@@ -1099,7 +1099,7 @@ Image GenImageCellular(int width, int height, int tileSize)
}
}
- // I made this up, but it seems to give good results at all tile sizes
+ // This approach seems to give good results at all tile sizes
int intensity = (int)(minDistance*256.0f/tileSize);
if (intensity > 255) intensity = 255;
@@ -3341,11 +3341,14 @@ void ImageClearBackground(Image *dst, Color color)
unsigned char *pSrcPixel = (unsigned char *)dst->data;
int bytesPerPixel = GetPixelDataSize(1, 1, dst->format);
+ int totalPixels = dst->width*dst->height;
- // Repeat the first pixel data throughout the image
- for (int i = 1; i < dst->width*dst->height; i++)
+ // Repeat the first pixel data throughout the image,
+ // doubling the pixels copied on each iteration
+ for (int i = 1; i < totalPixels; i *= 2)
{
- memcpy(pSrcPixel + i*bytesPerPixel, pSrcPixel, bytesPerPixel);
+ int pixelsToCopy = MIN(i, totalPixels - i);
+ memcpy(pSrcPixel + i*bytesPerPixel, pSrcPixel, pixelsToCopy*bytesPerPixel);
}
}
@@ -3724,9 +3727,10 @@ void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
unsigned char *pSrcPixel = (unsigned char *)dst->data + bytesOffset;
// Repeat the first pixel data throughout the row
- for (int x = 1; x < (int)rec.width; x++)
+ for (int x = 1; x < (int)rec.width; x *= 2)
{
- memcpy(pSrcPixel + x*bytesPerPixel, pSrcPixel, bytesPerPixel);
+ int pixelsToCopy = MIN(x, (int)rec.width - x);
+ memcpy(pSrcPixel + x*bytesPerPixel, pSrcPixel, pixelsToCopy*bytesPerPixel);
}
// Repeat the first row data for all other rows
@@ -3997,9 +4001,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
// [x] Consider fast path: no alpha blending required cases (src has no alpha)
// [x] Consider fast path: same src/dst format with no alpha -> direct line copy
// [-] GetPixelColor(): Get Vector4 instead of Color, easier for ColorAlphaBlend()
- // [ ] Support f32bit channels drawing
-
- // TODO: Support PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 and PIXELFORMAT_UNCOMPRESSED_R1616B16A16
+ // [ ] TODO: Support 16bit and 32bit (float) channels drawing
Color colSrc, colDst, blend;
bool blendRequired = true;
@@ -4197,7 +4199,7 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
}
/*else if (layout == CUBEMAP_LAYOUT_PANORAMA)
{
- // TODO: implement panorama by converting image to square faces...
+ // TODO: Implement panorama by converting image to square faces...
// Ref: https://github.com/denivip/panorama/blob/master/panorama.cpp
} */
else
@@ -4223,6 +4225,7 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
}
// Convert image data to 6 faces in a vertical column, that's the optimum layout for loading
+ // NOTE: Image formatting does not work with compressed textures
faces = GenImageColor(size, size*6, MAGENTA);
ImageFormat(&faces, image.format);
@@ -4235,8 +4238,6 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
}
#endif
- // NOTE: Image formatting does not work with compressed textures
-
for (int i = 0; i < 6; i++) ImageDraw(&faces, mipmapped, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, WHITE);
UnloadImage(mipmapped);
@@ -4305,13 +4306,11 @@ bool IsTextureValid(Texture2D texture)
{
bool result = false;
- // TODO: Validate maximum texture size supported by GPU
-
if ((texture.id > 0) && // Validate OpenGL id (texture uplaoded to GPU)
(texture.width > 0) && // Validate texture width
(texture.height > 0) && // Validate texture height
(texture.format > 0) && // Validate texture pixel format
- (texture.mipmaps > 0)) result = true; // Validate texture mipmaps (at least 1 for basic mipmap level)
+ (texture.mipmaps > 0)) result = true; // Validate texture mipmaps (at least 1 for basic mipmap level)
return result;
}
@@ -4601,7 +4600,7 @@ void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2
// NOTE: Vertex position can be transformed using matrices
// but the process is way more costly than just calculating
// the vertex positions manually, like done above
- // I leave here the old implementation for educational purposes,
+ // Old implementation is left here for educational purposes,
// just in case someone wants to do some performance test
/*
rlSetTexture(texture.id);
@@ -5408,7 +5407,7 @@ int GetPixelDataSize(int width, int height, int format)
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
// Convert half-float (stored as unsigned short) to float
-// REF: https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion/60047308#60047308
+// Ref: https://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion/60047308#60047308
static float HalfToFloat(unsigned short x)
{
float result = 0.0f;
diff --git a/src/utils.c b/src/utils.c
index 123c7b0b9..892f96cf4 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -451,7 +451,7 @@ FILE *android_fopen(const char *fileName, const char *mode)
{
if (mode[0] == 'w')
{
- // fopen() is mapped to android_fopen() that only grants read access to
+ // 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
diff --git a/tools/rexm/VS2022/raylib/raylib.vcxproj.filters b/tools/rexm/VS2022/raylib/raylib.vcxproj.filters
new file mode 100644
index 000000000..b5f5536dc
--- /dev/null
+++ b/tools/rexm/VS2022/raylib/raylib.vcxproj.filters
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+
+
+ {7c380c65-acd0-428f-83d9-70ef06f69b6d}
+
+
+
\ No newline at end of file
diff --git a/tools/rexm/examples_report_issues.md b/tools/rexm/reports/examples_issues.md
similarity index 90%
rename from tools/rexm/examples_report_issues.md
rename to tools/rexm/reports/examples_issues.md
index 5de76a17a..081170806 100644
--- a/tools/rexm/examples_report_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 | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| core_screen_recording | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| rlgl_standalone | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| rlgl_compute_shader | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
| embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| web_basic_window | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
diff --git a/tools/rexm/reports/examples_testing_drm.md b/tools/rexm/reports/examples_testing_drm.md
new file mode 100644
index 000000000..dba721a10
--- /dev/null
+++ b/tools/rexm/reports/examples_testing_drm.md
@@ -0,0 +1,21 @@
+# EXAMPLES COLLECTION - TESTING REPORT
+
+## Tested Platform: DRM
+
+```
+Example automated testing elements validated:
+ - [CWARN] : Compilation WARNING messages
+ - [LWARN] : Log WARNING messages count
+ - [INIT] : Initialization
+ - [CLOSE] : Closing
+ - [ASSETS] : Assets loading
+ - [RLGL] : OpenGL-wrapped initialization
+ - [PLAT] : Platform initialization
+ - [FONT] : Font default initialization
+ - [TIMER] : Timer initialization
+```
+| **EXAMPLE NAME** | [CWARN] | [LWARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |
+|:---------------------------------|:-------:|:-------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|
+| text_font_loading | 0 | 10 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| text_codepoints_loading | 0 | 1 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| models_animation_playing | 0 | 1 | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
diff --git a/tools/rexm/reports/examples_testing_linux.md b/tools/rexm/reports/examples_testing_linux.md
new file mode 100644
index 000000000..8f6c377ee
--- /dev/null
+++ b/tools/rexm/reports/examples_testing_linux.md
@@ -0,0 +1,22 @@
+# EXAMPLES COLLECTION - TESTING REPORT
+
+## Tested Platform: Linux
+
+```
+Example automated testing elements validated:
+ - [CWARN] : Compilation WARNING messages
+ - [LWARN] : Log WARNING messages count
+ - [INIT] : Initialization
+ - [CLOSE] : Closing
+ - [ASSETS] : Assets loading
+ - [RLGL] : OpenGL-wrapped initialization
+ - [PLAT] : Platform initialization
+ - [FONT] : Font default initialization
+ - [TIMER] : Timer initialization
+```
+| **EXAMPLE NAME** | [CWARN] | [LWARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |
+|:---------------------------------|:-------:|:-------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|
+| text_font_loading | 0 | 10 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| text_codepoints_loading | 0 | 1 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| models_animation_playing | 0 | 1 | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
+
diff --git a/tools/rexm/reports/examples_testing_macos.md b/tools/rexm/reports/examples_testing_macos.md
new file mode 100644
index 000000000..1fa686ee6
--- /dev/null
+++ b/tools/rexm/reports/examples_testing_macos.md
@@ -0,0 +1,24 @@
+# EXAMPLES COLLECTION - TESTING REPORT
+
+## Tested Platform: macOS
+
+```
+Example automated testing elements validated:
+ - [CWARN] : Compilation WARNING messages
+ - [LWARN] : Log WARNING messages count
+ - [INIT] : Initialization
+ - [CLOSE] : Closing
+ - [ASSETS] : Assets loading
+ - [RLGL] : OpenGL-wrapped initialization
+ - [PLAT] : Platform initialization
+ - [FONT] : Font default initialization
+ - [TIMER] : Timer initialization
+```
+| **EXAMPLE NAME** | [CWARN] | [LWARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |
+|:---------------------------------|:-------:|:-------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|
+| text_font_loading | 0 | 10 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| text_codepoints_loading | 0 | 1 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| models_animation_playing | 0 | 1 | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
+| shaders_palette_switch | 0 | 0 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
+| shaders_hybrid_rendering | 0 | 4 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+
diff --git a/tools/rexm/reports/examples_testing_web.md b/tools/rexm/reports/examples_testing_web.md
new file mode 100644
index 000000000..1f6ed58b3
--- /dev/null
+++ b/tools/rexm/reports/examples_testing_web.md
@@ -0,0 +1,36 @@
+# EXAMPLES COLLECTION - TESTING REPORT
+
+## Tested Platform: Web
+
+```
+Example automated testing elements validated:
+ - [CWARN] : Compilation WARNING messages
+ - [LWARN] : Log WARNING messages count
+ - [INIT] : Initialization
+ - [CLOSE] : Closing
+ - [ASSETS] : Assets loading
+ - [RLGL] : OpenGL-wrapped initialization
+ - [PLAT] : Platform initialization
+ - [FONT] : Font default initialization
+ - [TIMER] : Timer initialization
+```
+| **EXAMPLE NAME** | [CWARN] | [LWARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |
+|:---------------------------------|:-------:|:-------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|
+| core_monitor_detector | 0 | 1 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| textures_sprite_stacking | 0 | 0 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ |
+| text_sprite_fonts | 0 | 0 | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ |
+| text_font_loading | 0 | 3 | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
+| text_font_sdf | 0 | 22 | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ |
+| text_codepoints_loading | 0 | 1 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| models_animation_playing | 0 | 1 | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
+| models_mesh_generation | 0 | 0 | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| models_loading_gltf | 0 | 0 | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ |
+| models_bone_socket | 0 | 0 | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ |
+| models_decals | 0 | 0 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
+| shaders_postprocessing | 0 | 0 | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ |
+| shaders_deferred_rendering | 0 | 2 | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shaders_shadowmap_rendering | 0 | 0 | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ |
+| shaders_basic_pbr | 0 | 0 | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ |
+| audio_module_playing | 0 | 1 | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
+| audio_fft_spectrum_visualizer | 0 | 0 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
+
diff --git a/tools/rexm/reports/examples_testing_windows.md b/tools/rexm/reports/examples_testing_windows.md
new file mode 100644
index 000000000..8b8804bda
--- /dev/null
+++ b/tools/rexm/reports/examples_testing_windows.md
@@ -0,0 +1,22 @@
+# EXAMPLES COLLECTION - TESTING REPORT
+
+## Tested Platform: Windows
+
+```
+Example automated testing elements validated:
+ - [CWARN] : Compilation WARNING messages
+ - [LWARN] : Log WARNING messages count
+ - [INIT] : Initialization
+ - [CLOSE] : Closing
+ - [ASSETS] : Assets loading
+ - [RLGL] : OpenGL-wrapped initialization
+ - [PLAT] : Platform initialization
+ - [FONT] : Font default initialization
+ - [TIMER] : Timer initialization
+```
+| **EXAMPLE NAME** | [CWARN] | [LWARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |
+|:---------------------------------|:-------:|:-------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|
+| text_font_loading | 0 | 10 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| text_codepoints_loading | 0 | 1 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| models_animation_playing | 0 | 1 | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
+
diff --git a/tools/rexm/examples_report.md b/tools/rexm/reports/examples_validation.md
similarity index 93%
rename from tools/rexm/examples_report.md
rename to tools/rexm/reports/examples_validation.md
index fcc1f8839..af3befad9 100644
--- a/tools/rexm/examples_report.md
+++ b/tools/rexm/reports/examples_validation.md
@@ -59,11 +59,14 @@ Example elements validated:
| core_high_dpi | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_render_texture | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_undo_redo | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| core_viewport_scaling | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_input_actions | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_directory_files | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_highdpi_testbed | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| core_screen_recording | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| core_screen_recording | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_clipboard_text | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| core_text_file_loading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| core_compute_hash | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_basic_shapes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_bouncing_ball | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_bullet_hell | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -92,9 +95,14 @@ Example elements validated:
| shapes_pie_chart | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_kaleidoscope | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_clock_of_clocks | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_math_sine_cosine | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_mouse_trail | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_simple_particles | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_starfield_effect | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_lines_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_math_angle_rotation | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_rlgl_color_wheel | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_rlgl_triangle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -120,7 +128,9 @@ Example elements validated:
| textures_image_kernel | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_image_channel | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_image_rotate | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| textures_screen_buffer | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_textured_curve | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| textures_sprite_stacking | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_sprite_fonts | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_font_spritefont | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_font_filters | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -161,6 +171,8 @@ Example elements validated:
| models_tesseract_view | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| models_basic_voxel | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| models_rotating_cube | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| models_decals | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| models_directional_billboard | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_ascii_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_basic_lighting | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_model_shader | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -173,6 +185,8 @@ Example elements validated:
| shaders_texture_outline | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_texture_waves | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_julia_set | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shaders_mandelbrot_set | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shaders_color_correction | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_eratosthenes_sieve | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_fog_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_simple_mask | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -199,11 +213,10 @@ Example elements validated:
| audio_stream_effects | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| 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 | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| core_text_file_loading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| shaders_mandelbrot_set | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c
index d668655c8..72b962874 100644
--- a/tools/rexm/rexm.c
+++ b/tools/rexm/rexm.c
@@ -1,6 +1,6 @@
/*******************************************************************************************
*
-* rexm [raylib examples manager] - A simple command-line tool to manage raylib examples
+* rexm [raylib examples manager] - A simple and easy-to-use raylib examples collection manager
*
* Supported processes:
* - create
@@ -8,8 +8,9 @@
* - rename
* - remove
* - build
-* - validate
-* - update
+* - test
+* - validate // All examples
+* - update // All examples
*
* Files involved in the processes:
* - raylib/examples//_example_name.c
@@ -50,12 +51,12 @@
#include "raylib.h"
-#include
#include // Required for: rename(), remove()
#include // Required for: strcmp(), strcpy()
+#include // Required for: NULL, calloc(), free()
#define SUPPORT_LOG_INFO
-#if defined(SUPPORT_LOG_INFO) && defined(_DEBUG)
+#if defined(SUPPORT_LOG_INFO) //&& defined(_DEBUG)
#define LOG(...) printf("REXM: "__VA_ARGS__)
#else
#define LOG(...)
@@ -86,11 +87,18 @@ typedef struct {
char author[64]; // Example author
char authorGitHub[64]; // Example author, GitHub user name
- int status; // Example validation status info
+ int status; // Example validation status flags
int resCount; // Example resources counter
char **resPaths; // Example resources paths (MAX: 256)
} rlExampleInfo;
+// Automated testing data
+typedef struct {
+ int buildwarns; // Example building warnings count (by GCC compiler)
+ int warnings; // Example run output log warnings count
+ int status; // Example run testing status flags (>0 = FAILS)
+} rlExampleTesting;
+
// Validation status for a single example
typedef enum {
VALID_OK = 0, // All required files and entries are present
@@ -111,6 +119,18 @@ typedef enum {
VALID_UNKNOWN_ERROR = 1 << 14 // Unknown failure case (fallback)
} rlExampleValidationStatus;
+typedef enum {
+ TESTING_OK = 0, // All automated testing ok
+ TESTING_FAIL_INIT = 1 << 0, // Initialization (InitWindow()) -> "INFO: DISPLAY: Device initialized successfully"
+ TESTING_FAIL_CLOSE = 1 << 1, // Closing (CloseWindow()) -> "INFO: Window closed successfully"
+ TESTING_FAIL_ASSETS = 1 << 2, // Assets loading (WARNING: FILE:) -> "WARNING: FILEIO:"
+ TESTING_FAIL_RLGL = 1 << 3, // OpenGL-wrapped initialization -> "INFO: RLGL: Default OpenGL state initialized successfully"
+ TESTING_FAIL_PLATFORM = 1 << 4, // Platform initialization -> "INFO: PLATFORM: DESKTOP (GLFW - Win32): Initialized successfully"
+ TESTING_FAIL_FONT = 1 << 5, // Font deefault initialization -> "INFO: FONT: Default font loaded successfully (224 glyphs)"
+ TESTING_FAIL_TIMER = 1 << 6, // Timer initialization -> "INFO: TIMER: Target time per frame: 16.667 milliseconds"
+ TESTING_FAIL_OTHER = 1 << 7, // Other types of warnings (WARNING:)
+} rlExampleTestingStatus;
+
// Example management operations
typedef enum {
OP_NONE = 0, // No process to do
@@ -119,8 +139,10 @@ typedef enum {
OP_RENAME = 3, // Rename existing example
OP_REMOVE = 4, // Remove existing example
OP_VALIDATE = 5, // Validate examples, using [examples_list.txt] as main source by default
- OP_UPDATE = 6, // Validate and update required examples (as far as possible)
- OP_BUILD = 7, // Build example for desktop and web, copy web output
+ OP_UPDATE = 6, // Validate and update required examples (as far as possible): ALL
+ OP_BUILD = 7, // Build example(s) for desktop and web, copy web output - Multiple examples supported
+ OP_TEST = 8, // Test example(s), checking output log "WARNING" - Multiple examples supported
+ OP_TESTLOG = 9, // Process available examples logs to generate report
} rlExampleOperation;
static const char *exCategories[REXM_MAX_EXAMPLE_CATEGORIES] = { "core", "shapes", "textures", "text", "models", "shaders", "audio", "others" };
@@ -144,8 +166,8 @@ static int UpdateRequiredFiles(void);
// Load examples collection information
// NOTE 1: Load by category: "ALL", "core", "shapes", "textures", "text", "models", "shaders", others"
// NOTE 2: Sort examples list on request flag
-static rlExampleInfo *LoadExamplesData(const char *fileName, const char *category, bool sort, int *exCount);
-static void UnloadExamplesData(rlExampleInfo *exInfo);
+static rlExampleInfo *LoadExampleData(const char *filter, bool sort, int *exCount);
+static void UnloadExampleData(rlExampleInfo *exInfo);
// Load example info from file header
static rlExampleInfo *LoadExampleInfo(const char *exFileName);
@@ -160,10 +182,10 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry);
static void SortExampleByName(rlExampleInfo *items, int count);
// Scan resource paths in example file
-static char **ScanExampleResources(const char *filePath, int *resPathCount);
+static char **LoadExampleResourcePaths(const char *filePath, int *resPathCount);
// Clear resource paths scanned
-static void ClearExampleResources(char **resPaths);
+static void UnloadExampleResourcePaths(char **resPaths);
// Add/remove VS project (.vcxproj) tofrom existing VS solution (.sln)
static int AddVSProjectToSolution(const char *slnFile, const char *projFile, const char *category);
@@ -221,7 +243,8 @@ int main(int argc, char *argv[])
char exRecategory[32] = { 0 }; // Example re-name category: shapes
char exRename[64] = { 0 }; // Example re-name, without extension
- char exRebuildRequested[16] = { 0 }; // Example category/full rebuild request
+ char *exBuildList[256] = { 0 }; // Example build list for: ALL, , single-example
+ int exBuildListCount = 0; // Example build list file count
int opCode = OP_NONE; // Operation code: 0-None(Help), 1-Create, 2-Add, 3-Rename, 4-Remove
bool showUsage = false; // Flag to show usage help
@@ -381,35 +404,39 @@ int main(int argc, char *argv[])
opCode = OP_UPDATE;
}
- else if (strcmp(argv[1], "build") == 0)
+ else if ((strcmp(argv[1], "build") == 0) || (strcmp(argv[1], "test") == 0) || (strcmp(argv[1], "testlog") == 0))
{
- // Build example for PLATFORM_DESKTOP and PLATFORM_WEB
+ // Build/Test example(s) for PLATFORM_DESKTOP and PLATFORM_WEB
// NOTE: Build outputs to default directory, usually where the .c file is located,
// to avoid issues with copying resources (at least on Desktop)
// Web build files (.html, .wasm, .js, .data) are copied to raylib.com/examples repo
// Check for valid upcoming argument
- if (argc == 2) LOG("WARNING: No example name provided to build\n");
+ if (argc == 2) LOG("WARNING: No example name/category provided\n");
else if (argc > 3) LOG("WARNING: Too many arguments provided\n");
else
{
- // Support building not only individual examples but categories and "ALL"
- if ((strcmp(argv[2], "ALL") == 0) || TextInList(argv[2], exCategories, REXM_MAX_EXAMPLE_CATEGORIES))
+ // Support building/testing not only individual examples but multiple: ALL/
+ int exBuildListInfoCount = 0;
+ rlExampleInfo *exBuildListInfo = LoadExampleData(argv[2], false, &exBuildListInfoCount);
+
+ for (int i = 0; i < exBuildListInfoCount; i++)
{
- // Category/ALL rebuilt requested
- strcpy(exRebuildRequested, argv[2]);
+ if (!TextIsEqual(exBuildListInfo[i].category, "others"))
+ {
+ exBuildList[exBuildListCount] = (char *)RL_CALLOC(256, sizeof(char));
+ strcpy(exBuildList[exBuildListCount], exBuildListInfo[i].name);
+ exBuildListCount++;
+ }
}
+
+ UnloadExampleData(exBuildListInfo);
+
+ if (exBuildListCount == 0) LOG("WARNING: BUILD: Example requested not available in the collection\n");
else
{
- // Verify example exists in collection to be removed
- char *exColInfo = LoadFileText(exCollectionFilePath);
- if (TextFindIndex(exColInfo, argv[2]) != -1) // Example in the collection
- {
- strcpy(exName, argv[2]); // Register example name for removal
- strncpy(exCategory, exName, TextFindIndex(exName, "_"));
- opCode = OP_BUILD;
- }
- else LOG("WARNING: BUILD: Example requested not available in the collection\n");
- UnloadFileText(exColInfo);
+ if (strcmp(argv[1], "build") == 0) opCode = OP_BUILD;
+ else if (strcmp(argv[1], "test") == 0) opCode = OP_TEST;
+ else if (strcmp(argv[1], "testlog") == 0) opCode = OP_TESTLOG;
}
}
}
@@ -417,14 +444,8 @@ int main(int argc, char *argv[])
// Process command line options arguments
for (int i = 1; i < argc; i++)
{
- if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "--help") == 0))
- {
- showUsage = true;
- }
- else if ((strcmp(argv[i], "-v") == 0) || (strcmp(argv[i], "--verbose") == 0))
- {
- verbose = true;
- }
+ if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "--help") == 0)) showUsage = true;
+ else if ((strcmp(argv[i], "-v") == 0) || (strcmp(argv[i], "--verbose") == 0)) verbose = true;
}
}
@@ -464,12 +485,14 @@ int main(int argc, char *argv[])
// Create: raylib/examples//_example_name.png
if (FileExists(TextFormat("%s/%s.png", GetDirectoryPath(inFileName), exName)))
{
+ LOG("INFO: [%s] Copying file screenshot...\n", GetFileName(inFileName));
FileCopy(TextFormat("%s/%s.png", GetDirectoryPath(inFileName), exName),
TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName));
}
else // No screenshot available next to source file
{
// Copy screenshot template
+ LOG("WARNING: [%s] No screenshot found, using placeholder screenshot\n", GetFileName(inFileName));
FileCopy(exTemplateScreenshot, TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName));
}
@@ -478,10 +501,13 @@ int main(int argc, char *argv[])
// Scan resources used in example to copy
// NOTE: resources path will be relative to example source file directory
int resPathCount = 0;
- char **resPaths = ScanExampleResources(TextFormat("%s/%s.c", GetDirectoryPath(inFileName), exName), &resPathCount);
+ LOG("INFO: [%s] Scanning file for resources...\n", GetFileName(inFileName));
+ char **resPaths = LoadExampleResourcePaths(TextFormat("%s/%s.c", GetDirectoryPath(inFileName), exName), &resPathCount);
if (resPathCount > 0)
{
+ LOG("INFO: [%s] Required resources found: %i\n", GetFileName(inFileName), resPathCount);
+
for (int r = 0; r < resPathCount; r++)
{
// WARNING: Special case to consider: shaders, resource paths could use conditions: "glsl%i"
@@ -494,7 +520,7 @@ int main(int argc, char *argv[])
{
char *resPathUpdated = TextReplace(resPaths[r], "glsl%i", TextFormat("glsl%i", glslVer[v]));
- LOG("INFO: Example resource required: %s\n", resPathUpdated);
+ LOG("INFO: [%s] Resource required [%i/%i]: %s\n", GetFileName(inFileName), r, resPathCount, resPathUpdated);
if (FileExists(TextFormat("%s/%s", GetDirectoryPath(inFileName), resPathUpdated)))
{
@@ -515,7 +541,7 @@ int main(int argc, char *argv[])
}
else
{
- LOG("INFO: Example resource required: %s\n", resPaths[r]);
+ LOG("INFO: [%s] Resource required [%i/%i]: %s\n", GetFileName(inFileName), r, resPathCount, resPaths[r]);
if (FileExists(TextFormat("%s/%s", GetDirectoryPath(inFileName), resPaths[r])))
{
@@ -534,7 +560,7 @@ int main(int argc, char *argv[])
}
}
- ClearExampleResources(resPaths);
+ UnloadExampleResourcePaths(resPaths);
// -----------------------------------------------------------------------------------------
// Add example to the collection list, if not already there
@@ -543,6 +569,8 @@ int main(int argc, char *argv[])
char *exCollectionList = LoadFileText(exCollectionFilePath);
if (TextFindIndex(exCollectionList, exName) == -1) // Example not found
{
+ LOG("INFO: [%s] Adding example to collection list (%s)\n", GetFileName(inFileName), exCategory);
+
char *exCollectionListUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); // Updated list copy, 2MB
// Add example to the main list, by category
@@ -560,9 +588,15 @@ int main(int argc, char *argv[])
// Get required example info from example file header (if provided)
- // NOTE: If no example info is provided (other than category/name), just using some default values
+ // NOTE: Load example info from provided example header
rlExampleInfo *exInfo = LoadExampleInfo(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
+ LOG("INFO: [%s] Example info: \n", GetFileName(inFileName));
+ LOG(" > Author: %s (@%s)\n", exInfo->author, exInfo->authorGitHub);
+ LOG(" > Stars: %i\n", exInfo->stars);
+ LOG(" > Version-Update: %s-%s\n", exInfo->verCreated, exInfo->verUpdated);
+ LOG(" > Created-Reviewed: %i-%i\n", exInfo->yearCreated, exInfo->yearReviewed);
+
// Get example difficulty stars text
char starsText[16] = { 0 };
for (int i = 0; i < 4; i++)
@@ -599,13 +633,14 @@ int main(int argc, char *argv[])
UnloadFileText(exCollectionList);
//------------------------------------------------------------------------------------------------
- // Update: Makefile, Makefile.Web, README.md, examples.js
+ // Update: Metadata, Makefile, Makefile.Web, README.md, examples.js
//------------------------------------------------------------------------------------------------
UpdateRequiredFiles();
//------------------------------------------------------------------------------------------------
// Create: raylib/projects/VS2022/examples/_example_name.vcxproj
//------------------------------------------------------------------------------------------------
+ LOG("INFO: [%s] Creating example project\n", TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName));
// WARNING: When adding new project a unique UUID should be assigned!
FileCopy(TextFormat("%s/../projects/VS2022/examples/core_basic_window.vcxproj", exBasePath),
TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName));
@@ -619,6 +654,7 @@ 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));
AddVSProjectToSolution(exVSProjectSolutionFile,
TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName), exCategory);
//------------------------------------------------------------------------------------------------
@@ -633,17 +669,21 @@ int main(int argc, char *argv[])
// WARNING 1: EMSDK_PATH must be set to proper location when calling from GitHub Actions
// WARNING 2: raylib.a and raylib.web.a must be available when compiling locally
#if defined(_WIN32)
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", GetFileNameWithoutExt(inFileName));
//putenv("RAYLIB_DIR=C:\\GitHub\\raylib");
- putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
+ _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
#else
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", GetFileNameWithoutExt(inFileName));
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
#endif
// Update generated .html metadata
+ LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exName));
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
// Copy results to web side
+ LOG("INFO: [%s] Copy example build to raylib.com\n", exName);
FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
TextFormat("%s/%s/%s.html", exWebPath, exCategory, exName));
FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exCategory, exName),
@@ -676,13 +716,13 @@ int main(int argc, char *argv[])
// Edit: Update example source code metadata
int exListCount = 0;
- rlExampleInfo *exList = LoadExamplesData(exCollectionFilePath, exCategory, false, &exListCount);
+ rlExampleInfo *exList = LoadExampleData(exCategory, false, &exListCount);
for (int i = 0; i < exListCount; i++)
{
if (strcmp(exList[i].name, exRename) == 0)
UpdateSourceMetadata(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exRename), &exList[i]);
}
- UnloadExamplesData(exList);
+ UnloadExampleData(exList);
// NOTE: Example resource files do not need to be changed...
// unless the example is moved from one caegory to another
@@ -732,7 +772,7 @@ int main(int argc, char *argv[])
// Recompile example (on raylib side)
// WARNING: EMSDK_PATH must be set to proper location when calling from GitHub Actions
#if defined(_WIN32)
- putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
+ _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename));
#else
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename));
@@ -776,6 +816,7 @@ int main(int argc, char *argv[])
// Remove example from collection for files update
//------------------------------------------------------------------------------------------------
+ LOG("INFO: [%s] Removing example from collection\n", exName);
char *exCollectionList = LoadFileText(exCollectionFilePath);
int exIndex = TextFindIndex(exCollectionList, TextFormat("%s;%s", exCategory, exName));
if (exIndex > 0) // Example found
@@ -831,22 +872,33 @@ int main(int argc, char *argv[])
// Remove: raylib/examples//_example_name.c
// Remove: raylib/examples//_example_name.png
+ LOG("INFO: [%s] Removing example code file\n", TextFormat("%s.c", exName));
FileRemove(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
+ LOG("INFO: [%s] Removing example screenshot file\n", TextFormat("%s.png", exName));
FileRemove(TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName));
// Edit: Update required files: Makefile, Makefile.Web, README.md, examples.js
UpdateRequiredFiles();
// Remove: raylib/projects/VS2022/examples/_example_name.vcxproj
+ LOG("INFO: [%s] Removing example project file\n", TextFormat("%s.vcxproj", exName));
FileRemove(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName));
// Edit: raylib/projects/VS2022/raylib.sln --> Remove example project
+ LOG("INFO: [%s] Removing example from raylib solution (.sln)\n", exName);
RemoveVSProjectFromSolution(TextFormat("%s/../projects/VS2022/raylib.sln", exBasePath), exName);
+ // Remove: Delete example build from local copy (if exists)
+ FileRemove(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName));
+ FileRemove(TextFormat("%s/%s/%s.data", exBasePath, exCategory, exName));
+ FileRemove(TextFormat("%s/%s/%s.wasm", exBasePath, exCategory, exName));
+ FileRemove(TextFormat("%s/%s/%s.js", exBasePath, exCategory, exName));
+
// Remove: raylib.com/examples//_example_name.html
// Remove: raylib.com/examples//_example_name.data
// Remove: raylib.com/examples//_example_name.wasm
// Remove: raylib.com/examples//_example_name.js
+ LOG("INFO: [%s] Deleting example from raylib.com\n", exName);
FileRemove(TextFormat("%s/%s/%s.html", exWebPath, exCategory, exName));
FileRemove(TextFormat("%s/%s/%s.data", exWebPath, exCategory, exName));
FileRemove(TextFormat("%s/%s/%s.wasm", exWebPath, exCategory, exName));
@@ -856,59 +908,71 @@ int main(int argc, char *argv[])
case OP_BUILD:
{
LOG("INFO: Command requested: BUILD\n");
- LOG("INFO: Example to be built: %s\n", exRebuildRequested);
+ LOG("INFO: Example(s) to be built: %i [%s]\n", exBuildListCount, (exBuildListCount == 1)? exBuildList[0] : argv[2]);
- if ((strcmp(exRebuildRequested, "others") != 0) &&
- (strcmp(exCategory, "others") != 0)) // Skipping "others" category for rebuild: Special needs
+#if defined(_WIN32)
+ // Set required environment variables
+ //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
+ _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
+ //putenv("MAKE=mingw32-make");
+ //ChangeDirectory(exBasePath);
+#endif
+ for (int i = 0; i < exBuildListCount; i++)
{
- int exRebuildCount = 0;
- rlExampleInfo *exRebuildList = LoadExamplesData(exCollectionFilePath, exRebuildRequested, false, &exRebuildCount);
+ // Get example name and category
+ memset(exName, 0, 64);
+ strcpy(exName, exBuildList[i]);
+ memset(exCategory, 0, 32);
+ strncpy(exCategory, exName, TextFindIndex(exName, "_"));
+ LOG("INFO: [%i/%i] Building example: [%s]\n", i + 1, exBuildListCount, exName);
+
+ // Build example for PLATFORM_DESKTOP
+#if defined(_WIN32)
+ LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName);
+ system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName));
+#elif defined(PLATFORM_DRM)
+ LOG("INFO: [%s] Building example for PLATFORM_DRM (Host: POSIX)\n", exName);
+ system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DRM -B > %s/%s/logs/%s.build.log 2>&1",
+ exBasePath, exCategory, exName, exBasePath, exCategory, exName));
+#else
+ LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: POSIX)\n", exName);
+ system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName));
+#endif
+
+#if !defined(PLATFORM_DRM)
+ // Build example for PLATFORM_WEB
// Build: raylib.com/examples//_example_name.html
// Build: raylib.com/examples//_example_name.data
// Build: raylib.com/examples//_example_name.wasm
// Build: raylib.com/examples//_example_name.js
+ #if defined(_WIN32)
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName);
+ system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
+ #else
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName);
+ system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
+ #endif
+ // Update generated .html metadata
+ LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exName));
+ UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
+ TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
-#if defined(_WIN32)
- // Set required environment variables
- //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
- putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
- //putenv("MAKE=mingw32-make");
- //ChangeDirectory(exBasePath);
-#endif
- for (int i = 0; i < exRebuildCount; i++)
- {
- // Build example for PLATFORM_DESKTOP
-#if defined(_WIN32)
- system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
-#else
- system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
-#endif
+ // Copy results to web side
+ LOG("INFO: [%s] Copy example build to raylib.com\n", exName);
+ FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
+ TextFormat("%s/%s/%s.html", exWebPath, exCategory, exName));
+ FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exCategory, exName),
+ TextFormat("%s/%s/%s.data", exWebPath, exCategory, exName));
+ FileCopy(TextFormat("%s/%s/%s.wasm", exBasePath, exCategory, exName),
+ TextFormat("%s/%s/%s.wasm", exWebPath, exCategory, exName));
+ FileCopy(TextFormat("%s/%s/%s.js", exBasePath, exCategory, exName),
+ TextFormat("%s/%s/%s.js", exWebPath, exCategory, exName));
+#endif // !PLATFORM_DRM
- // Build example for PLATFORM_WEB
-#if defined(_WIN32)
- system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
-#else
- system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
-#endif
- // Update generated .html metadata
- UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
- TextFormat("%s/%s/%s.c", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
-
- // Copy results to web side
- FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
- TextFormat("%s/%s/%s.html", exWebPath, exRebuildList[i].category, exRebuildList[i].name));
- FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
- TextFormat("%s/%s/%s.data", exWebPath, exRebuildList[i].category, exRebuildList[i].name));
- FileCopy(TextFormat("%s/%s/%s.wasm", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
- TextFormat("%s/%s/%s.wasm", exWebPath, exRebuildList[i].category, exRebuildList[i].name));
- FileCopy(TextFormat("%s/%s/%s.js", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
- TextFormat("%s/%s/%s.js", exWebPath, exRebuildList[i].category, exRebuildList[i].name));
- }
-
- UnloadExamplesData(exRebuildList);
+ // Once example processed, free memory from list
+ RL_FREE(exBuildList[i]);
}
- else LOG("WARNING: [others] category examples should be build manually, they could have specific build requirements\n");
} break;
case OP_VALIDATE: // Validate: report and actions
@@ -933,10 +997,9 @@ int main(int argc, char *argv[])
VALID_INVALID_CATEGORY
*/
- // TODO: Log more details about the validation process
-
// 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");
FilePathList clist = LoadDirectoryFilesEx(exBasePath, ".c", true);
char *exList = LoadFileText(exCollectionFilePath);
@@ -968,6 +1031,9 @@ int main(int argc, char *argv[])
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
@@ -1007,8 +1073,9 @@ int main(int argc, char *argv[])
UnloadDirectoryFiles(clist);
// Check all examples in collection [examples_list.txt] -> Source of truth!
+ LOG("INFO: Validating examples in collection...\n");
int exCollectionCount = 0;
- rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, "ALL", false, &exCollectionCount);
+ rlExampleInfo *exCollection = LoadExampleData("ALL", false, &exCollectionCount);
// Set status information for all examples, using "status" field in the struct
for (int i = 0; i < exCollectionCount; i++)
@@ -1016,6 +1083,8 @@ int main(int argc, char *argv[])
rlExampleInfo *exInfo = &exCollection[i];
exInfo->status = 0;
+ LOG("INFO: [%s] Validating example...\n", exInfo->name);
+
// Validate: raylib/examples//_example_name.c -> File exists?
if (!FileExists(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name))) exInfo->status |= VALID_MISSING_C;
@@ -1051,7 +1120,7 @@ int main(int argc, char *argv[])
// Validate: raylib/examples//resources/.. -> Example resources available?
// Scan resources used in example to check for missing resource files
// WARNING: Some paths could be for files to save, not files to load, verify it
- char **resPaths = ScanExampleResources(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name), &exInfo->resCount);
+ char **resPaths = LoadExampleResourcePaths(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name), &exInfo->resCount);
if (exInfo->resCount > 0)
{
for (int r = 0; r < exInfo->resCount; r++)
@@ -1084,7 +1153,7 @@ int main(int argc, char *argv[])
}
}
}
- ClearExampleResources(resPaths);
+ UnloadExampleResourcePaths(resPaths);
// Validate: raylib.com/examples//_example_name.html -> File exists?
// Validate: raylib.com/examples//_example_name.data -> File exists?
@@ -1138,11 +1207,16 @@ int main(int argc, char *argv[])
exInfo->status |= VALID_INCONSISTENT_INFO;
}
+ if (exInfo->status == 0) LOG("INFO: [%s] Validation result: OK\n", exInfo->name);
+ else LOG("WARNING: [%s] Validation result: ISSUES FOUND\n", exInfo->name);
+
UnloadExampleInfo(exInfoHeader);
}
if (opCode == OP_UPDATE)
{
+ LOG("INFO: Updating examples with issues in collection...\n");
+
// Actions to fix/review anything possible from validation results
//------------------------------------------------------------------------------------------------
// Check examples "status" information
@@ -1162,16 +1236,16 @@ int main(int argc, char *argv[])
// NOTE: Some examples should be excluded from VS2022 solution because
// they have specific platform/linkage requirements:
- if ((strcmp(exInfo->name, "core_basic_window_web") == 0) ||
- (strcmp(exInfo->name, "core_input_gestures_web") == 0) ||
- (strcmp(exInfo->name, "raylib_opengl_interop") == 0) ||
- (strcmp(exInfo->name, "raymath_vector_angle") == 0)) continue;
+ if ((strcmp(exInfo->name, "web_basic_window") == 0) ||
+ (strcmp(exInfo->name, "raylib_opengl_interop") == 0)) continue;
// Review: Add: raylib/projects/VS2022/examples/_example_name.vcxproj
// Review: Add: raylib/projects/VS2022/raylib.sln
// Solves: VALID_MISSING_VCXPROJ, VALID_NOT_IN_VCXSOL
if (exInfo->status & VALID_MISSING_VCXPROJ)
{
+ LOG("WARNING: [%s] Missing VS2022 project file\n", exInfo->name);
+ LOG("INFO: [%s.vcxproj] Creating VS2022 project file\n", exInfo->name);
FileCopy(TextFormat("%s/../projects/VS2022/examples/core_basic_window.vcxproj", exBasePath),
TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name));
FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name),
@@ -1185,6 +1259,8 @@ int main(int argc, char *argv[])
// Add project (.vcxproj) to raylib solution (.sln)
if (exInfo->status & VALID_NOT_IN_VCXSOL)
{
+ LOG("WARNING: [%s.vcxproj] Project not included in raylib solution (.sln)\n", exInfo->name);
+ LOG("INFO: [%s.vcxproj] Adding project to raylib solution (.sln)\n", exInfo->name);
AddVSProjectToSolution(exVSProjectSolutionFile,
TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name), exInfo->category);
@@ -1199,19 +1275,25 @@ int main(int argc, char *argv[])
if ((strcmp(exInfo->category, "others") != 0) && // Skipping "others" category
((exInfo->status & VALID_MISSING_WEB_OUTPUT) || (exInfo->status & VALID_MISSING_WEB_METADATA)))
{
+ LOG("WARNING: [%s] Example not available on raylib web\n", exInfo->name);
+
// Build example for PLATFORM_WEB
#if defined(_WIN32)
- putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exInfo->name);
+ _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
#else
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->name);
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
#endif
// Update generated .html metadata
+ LOG("INFO: [%s.html] Updating HTML Metadata...\n", exInfo->name);
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exInfo->category, exInfo->name),
TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name));
// Copy results to web side
+ LOG("INFO: [%s] Copy example build to raylib.com\n", exInfo->name);
FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exInfo->category, exInfo->name),
TextFormat("%s/%s/%s.html", exWebPath, exInfo->category, exInfo->name));
FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exInfo->category, exInfo->name),
@@ -1228,6 +1310,8 @@ int main(int argc, char *argv[])
if (exInfo->status & VALID_INCONSISTENT_INFO)
{
// Update source code header info
+ LOG("WARNING: [%s.c] Inconsistent source code metadata\n", exInfo->name);
+ LOG("INFO: [%s.c] Updating source code metadata...\n", exInfo->name);
UpdateSourceMetadata(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name), exInfo);
exInfo->status &= ~VALID_INCONSISTENT_INFO;
@@ -1273,6 +1357,7 @@ int main(int argc, char *argv[])
| shapes_colors_palette | ✘ | ✔ | ✘ | ✔ | ✘ | ✔ | ✔ | ✘ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_format_text | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✔ | ✘ | ✔ | ✔ | ✔ | ✔ |
*/
+ LOG("INFO: [examples_validation.md] Generating examples validation report...\n");
char *report = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
@@ -1318,12 +1403,14 @@ int main(int argc, char *argv[])
(exCollection[i].status & VALID_MISSING_WEB_METADATA)? "❌" : "✔");
}
- SaveFileText(TextFormat("%s/../tools/rexm/%s", exBasePath, "examples_report.md"), report);
+ SaveFileText(TextFormat("%s/../tools/rexm/reports/%s", exBasePath, "examples_validation.md"), report);
RL_FREE(report);
//-----------------------------------------------------------------------------------------------------
// Generate a report with only the examples missing some elements
//-----------------------------------------------------------------------------------------------------
+ LOG("INFO: [examples_issues.md] Generating examples issues report...\n");
+
char *reportIssues = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
repIndex = 0;
@@ -1371,13 +1458,382 @@ int main(int argc, char *argv[])
}
}
- SaveFileText(TextFormat("%s/../tools/rexm/%s", exBasePath, "examples_report_issues.md"), reportIssues);
+ SaveFileText(TextFormat("%s/../tools/rexm/reports/%s", exBasePath, "examples_issues.md"), reportIssues);
RL_FREE(reportIssues);
//-----------------------------------------------------------------------------------------------------
- UnloadExamplesData(exCollection);
+ UnloadExampleData(exCollection);
//------------------------------------------------------------------------------------------------
+ } break;
+ case OP_TEST:
+ {
+ LOG("INFO: Command requested: TEST\n");
+ LOG("INFO: Example(s) to be build and tested: %i [%s]\n", exBuildListCount, (exBuildListCount == 1)? exBuildList[0] : argv[2]);
+
+#if defined(_WIN32)
+ // Set required environment variables
+ //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
+ //_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
+ //putenv("MAKE=mingw32-make");
+ //ChangeDirectory(exBasePath);
+ //_putenv("MAKE_PATH=C:\\raylib\\w64devkit\\bin");
+ //_putenv("EMSDK_PATH = C:\\raylib\\emsdk");
+ //_putenv("PYTHON_PATH=$(EMSDK_PATH)\\python\\3.9.2-nuget_64bit");
+ //_putenv("NODE_PATH=$(EMSDK_PATH)\\node\\20.18.0_64bit\\bin");
+ //_putenv("PATH=%PATH%;$(MAKE_PATH);$(EMSDK_PATH);$(NODE_PATH);$(PYTHON_PATH)");
+
+ _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin;C:\\raylib\\emsdk\\python\\3.9.2-nuget_64bit;C:\\raylib\\emsdk\\node\\20.18.0_64bit\\bin");
+#endif
+
+ for (int i = 0; i < exBuildListCount; i++)
+ {
+ // Get example name and category
+ memset(exName, 0, 64);
+ strcpy(exName, exBuildList[i]);
+ memset(exCategory, 0, 32);
+ strncpy(exCategory, exName, TextFindIndex(exName, "_"));
+
+ // Skip some examples from building
+ if ((strcmp(exName, "core_custom_logging") == 0) ||
+ (strcmp(exName, "core_window_should_close") == 0) ||
+ (strcmp(exName, "core_custom_frame_control") == 0)) continue;
+
+ LOG("INFO: [%i/%i] Testing example: [%s]\n", i + 1, exBuildListCount, exName);
+
+ // Create directory for logs (build and run logs)
+ MakeDirectory(TextFormat("%s/%s/logs", exBasePath, exCategory));
+
+ // Steps to follow
+ // STEP 1: Load example.c and replace required code to inject basic testing code: frames to run
+ // OPTION 1: Code injection required multiple changes for testing but it does not require raylib changes!
+ // OPTION 2: Support testing on raylib side: Args processing and events injection: SUPPORT_AUTOMATD_TESTING_SYSTEM, EVENTS_TESTING_MODE
+ // STEP 2: Build example (PLATFORM_DESKTOP)
+ // STEP 3: Run example with arguments: --frames 2 > .out.log
+ // STEP 4: Load .out.log and check "WARNING:" messages -> Some could maybe be ignored
+ // STEP 5: Generate report with results
+
+ // STEP 1: Load example and inject required code
+ // PROBLEM: As we need to modify the example source code for building, we need to keep a copy or something
+ // WARNING: If we make a copy and something fails, it could not be restored at the end
+ // PROBLEM: Trying to build a copy won't work because Makefile is setup to look for specific example on specific path -> No output dir config
+ // IDEA: Create directory for testing data -> It implies moving files and set working dir...
+ // SOLUTION: Make a copy of original file -> Modify original -> Build -> Rename to .test.exe
+ FileCopy(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName),
+ TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName));
+ char *srcText = LoadFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
+
+//#define BUILD_TESTING_WEB
+#if defined(BUILD_TESTING_WEB)
+ static const char *mainReplaceText =
+ "#include \n"
+ "#include \n"
+ "#include \n"
+ "#include \n\n"
+ "static char logText[4096] = {0};\n"
+ "static int logTextOffset = 0;\n\n"
+ "void CustomTraceLog(int msgType, const char *text, va_list args)\n{\n"
+ " if (logTextOffset < 3800)\n {\n"
+ " switch (msgType)\n {\n"
+ " case LOG_INFO: logTextOffset += sprintf(logText + logTextOffset, \"INFO: \"); break;\n"
+ " case LOG_ERROR: logTextOffset += sprintf(logText + logTextOffset, \"ERROR: \"); break;\n"
+ " case LOG_WARNING: logTextOffset += sprintf(logText + logTextOffset, \"WARNING: \"); break;\n"
+ " case LOG_DEBUG: logTextOffset += sprintf(logText + logTextOffset, \"DEBUG: \"); break;\n"
+ " default: break;\n }\n"
+ " logTextOffset += vsprintf(logText + logTextOffset, text, args);\n"
+ " logTextOffset += sprintf(logText + logTextOffset, \"\\n\");\n}\n}\n\n"
+ "int main(int argc, char *argv[])\n{\n"
+ " SetTraceLogCallback(CustomTraceLog);\n"
+ " int requestedTestFrames = 0;\n"
+ " int testFramesCount = 0;\n"
+ " if ((argc > 1) && (argc == 3) && (strcmp(argv[1], \"--frames\") != 0)) requestedTestFrames = atoi(argv[2]);\n";
+
+ static const char *returnReplaceText =
+ " SaveFileText(\"outputLogFileName\", logText);\n"
+ " emscripten_run_script(\"saveFileFromMEMFSToDisk('outputLogFileName','outputLogFileName')\");\n\n"
+ " return 0";
+ char *returnReplaceTextUpdated = TextReplace(returnReplaceText, "outputLogFileName", TextFormat("%s.log", exName));
+
+ char *srcTextUpdated[4] = { 0 };
+ srcTextUpdated[0] = TextReplace(srcText, "int main(void)\n{", mainReplaceText);
+ srcTextUpdated[1] = TextReplace(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)");
+ srcTextUpdated[2] = TextReplace(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;");
+ srcTextUpdated[3] = TextReplace(srcTextUpdated[2], " return 0", returnReplaceTextUpdated);
+ MemFree(returnReplaceTextUpdated);
+ UnloadFileText(srcText);
+
+ SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), srcTextUpdated[3]);
+ for (int i = 0; i < 4; i++) { MemFree(srcTextUpdated[i]); srcTextUpdated[i] = NULL; }
+
+ // Build example for PLATFORM_WEB
+ // Build: raylib.com/examples//_example_name.html
+ // Build: raylib.com/examples//_example_name.data
+ // Build: raylib.com/examples//_example_name.wasm
+ // Build: raylib.com/examples//_example_name.js
+ #if defined(_WIN32)
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName);
+ system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B > %s/%s/logs/%s.build.log 2>&1",
+ exBasePath, exCategory, exName, exBasePath, exCategory, exName));
+ #else
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName);
+ system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
+ #endif
+ // Restore original source code before continue
+ FileCopy(TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName),
+ TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
+ 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));
+
+ // NOTE: Example .log is automatically downloaded into system Downloads directory on browser-example exectution
+
+#else // BUILD_TESTING_DESKTOP
+
+ static const char *mainReplaceText =
+ "#include \n"
+ "#include \n"
+ "int main(int argc, char *argv[])\n{\n"
+ " int requestedTestFrames = 0;\n"
+ " int testFramesCount = 0;\n"
+ " if ((argc > 1) && (argc == 3) && (strcmp(argv[1], \"--frames\") != 0)) requestedTestFrames = atoi(argv[2]);\n";
+
+ char *srcTextUpdated[3] = { 0 };
+ srcTextUpdated[0] = TextReplace(srcText, "int main(void)\n{", mainReplaceText);
+ srcTextUpdated[1] = TextReplace(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)");
+ srcTextUpdated[2] = TextReplace(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;");
+ UnloadFileText(srcText);
+
+ SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), srcTextUpdated[2]);
+ for (int i = 0; i < 3; i++) { MemFree(srcTextUpdated[i]); srcTextUpdated[i] = NULL; }
+
+ // STEP 2: Build example for DESKTOP platform
+ #if defined(_WIN32)
+ // Set required environment variables
+ //putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
+ _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
+ //putenv("MAKE=mingw32-make");
+ //ChangeDirectory(exBasePath);
+ #endif
+ // Build example for PLATFORM_DESKTOP
+ #if defined(_WIN32)
+ LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName);
+ system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B > %s/%s/logs/%s.build.log 2>&1",
+ exBasePath, exCategory, exName, exBasePath, exCategory, exName));
+ #elif defined(PLATFORM_DRM)
+ LOG("INFO: [%s] Building example for PLATFORM_DRM (Host: POSIX)\n", exName);
+ system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DRM -B > %s/%s/logs/%s.build.log 2>&1",
+ exBasePath, exCategory, exName, exBasePath, exCategory, exName));
+ #else
+ LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: POSIX)\n", exName);
+ system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B > %s/%s/logs/%s.build.log 2>&1",
+ exBasePath, exCategory, exName, exBasePath, exCategory, exName));
+ #endif
+ // Restore original source code before continue
+ FileCopy(TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName),
+ TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
+ FileRemove(TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName));
+
+ // STEP 3: Run example with required arguments
+ // NOTE: Not easy to retrieve process return value from system(), it's platform dependant
+ ChangeDirectory(TextFormat("%s/%s", exBasePath, exCategory));
+
+ #if defined(_WIN32)
+ system(TextFormat("%s --frames 2 > logs/%s.log", exName, exName));
+ #else
+ system(TextFormat("./%s --frames 2 > logs/%s.log", exName, exName));
+ #endif
+#endif
+ }
+ } break;
+ case OP_TESTLOG:
+ {
+ // STEP 4: Load and validate available logs info
+ //---------------------------------------------------------------------------------------------
+ rlExampleTesting *testing = (rlExampleTesting *)RL_CALLOC(exBuildListCount, sizeof(rlExampleTesting));
+
+ for (int i = 0; i < exBuildListCount; i++)
+ {
+ // Get example name and category
+ memset(exName, 0, 64);
+ strcpy(exName, exBuildList[i]);
+ memset(exCategory, 0, 32);
+ strncpy(exCategory, exName, TextFindIndex(exName, "_"));
+
+ // Skip some examples from building
+ if ((strcmp(exName, "core_custom_logging") == 0) ||
+ (strcmp(exName, "core_window_should_close") == 0) ||
+ (strcmp(exName, "core_custom_frame_control") == 0)) continue;
+
+ LOG("INFO: [%i/%i] Checking example log: [%s]\n", i + 1, exBuildListCount, exName);
+
+ // Load .build.log to check for compilation warnings
+ char *exTestBuildLog = LoadFileText(TextFormat("%s/%s/logs/%s.build.log", exBasePath, exCategory, exName));
+ if (exTestBuildLog == NULL)
+ {
+ LOG("WARNING: [%s] Build log could not be loaded\n", exName);
+ continue;
+ }
+
+ // Load build log text lines
+ int exTestBuildLogLinesCount = 0;
+ char **exTestBuildLogLines = LoadTextLines(exTestBuildLog, &exTestBuildLogLinesCount);
+
+ for (int k = 0; k < exTestBuildLogLinesCount; k++)
+ {
+ // Checking compilation warnings generated
+ if (TextFindIndex(exTestBuildLogLines[k], "warning:") >= 0) testing[i].buildwarns++;
+ }
+
+ UnloadTextLines(exTestBuildLogLines, exTestBuildLogLinesCount);
+ UnloadFileText(exTestBuildLog);
+
+#if defined(BUILD_TESTING_WEB)
+ // TODO: REVIEW: Hardcoded path where web logs are copied after automatic download
+ char *exTestLog = LoadFileText(TextFormat("D:/testing_logs_web/%s.log", exName));
+#else
+ char *exTestLog = LoadFileText(TextFormat("%s/%s/logs/%s.log", exBasePath, exCategory, exName));
+#endif
+ if (exTestLog == NULL)
+ {
+ LOG("WARNING: [%s] Execution log could not be loaded\n", exName);
+ testing[i].status = 0b1111111;
+ continue;
+ }
+
+ /*
+ TESTING_FAIL_INIT = 1 << 0, // Initialization (InitWindow()) -> "INFO: DISPLAY: Device initialized successfully"
+ TESTING_FAIL_CLOSE = 1 << 1, // Closing (CloseWindow()) -> "INFO: Window closed successfully"
+ TESTING_FAIL_ASSETS = 1 << 2, // Assets loading (WARNING: FILE:) -> "WARNING: FILEIO:"
+ TESTING_FAIL_RLGL = 1 << 3, // OpenGL-wrapped initialization -> "INFO: RLGL: Default OpenGL state initialized successfully"
+ TESTING_FAIL_PLATFORM = 1 << 4, // Platform initialization -> "INFO: PLATFORM: DESKTOP (GLFW - Win32): Initialized successfully"
+ TESTING_FAIL_FONT = 1 << 5, // Font default initialization -> "INFO: FONT: Default font loaded successfully (224 glyphs)"
+ TESTING_FAIL_TIMER = 1 << 6, // Timer initialization -> "INFO: TIMER: Target time per frame: 16.667 milliseconds"
+ */
+
+ if (TextFindIndex(exTestLog, "INFO: DISPLAY: Device initialized successfully") == -1) testing[i].status |= TESTING_FAIL_INIT;
+ if (TextFindIndex(exTestLog, "INFO: Window closed successfully") == -1) testing[i].status |= TESTING_FAIL_CLOSE;
+ if (TextFindIndex(exTestLog, "WARNING: FILEIO:") >= 0) testing[i].status |= TESTING_FAIL_ASSETS;
+ if (TextFindIndex(exTestLog, "INFO: RLGL: Default OpenGL state initialized successfully") == -1) testing[i].status |= TESTING_FAIL_RLGL;
+ if (TextFindIndex(exTestLog, "INFO: PLATFORM:") == -1) testing[i].status |= TESTING_FAIL_PLATFORM;
+ if (TextFindIndex(exTestLog, "INFO: FONT: Default font loaded successfully") == -1) testing[i].status |= TESTING_FAIL_FONT;
+ if (TextFindIndex(exTestLog, "INFO: TIMER: Target time per frame:") == -1) testing[i].status |= TESTING_FAIL_TIMER;
+
+ // Load build log text lines
+ int exTestLogLinesCount = 0;
+ char **exTestLogLines = LoadTextLines(exTestLog, &exTestLogLinesCount);
+ for (int k = 0; k < exTestLogLinesCount; k++)
+ {
+#if defined(BUILD_TESTING_WEB)
+ if (TextFindIndex(exTestLogLines[k], "WARNING: GL: NPOT") >= 0) continue; // Ignore web-specific warning
+#endif
+#if defined(PLATFORM_DRM)
+ if (TextFindIndex(exTestLogLines[k], "WARNING: DISPLAY: No graphic") >= 0) continue; // Ignore specific warning
+ if (TextFindIndex(exTestLogLines[k], "WARNING: GetCurrentMonitor()") >= 0) continue; // Ignore specific warning
+ if (TextFindIndex(exTestLogLines[k], "WARNING: SetWindowPosition()") >= 0) continue; // Ignore specific warning
+#endif
+ if (TextFindIndex(exTestLogLines[k], "WARNING") >= 0) testing[i].warnings++;
+ }
+ UnloadTextLines(exTestLogLines, exTestLogLinesCount);
+ UnloadFileText(exTestLog);
+ }
+ //---------------------------------------------------------------------------------------------
+
+ // STEP 5: Generate testing report/table with results (.md)
+ //-----------------------------------------------------------------------------------------------------
+#if defined(BUILD_TESTING_WEB)
+ const char *osName = "Web";
+#else
+ #if defined(PLATFORM_DRM)
+ const char *osName = "DRM";
+ #elif defined(PLATFORM_DESKTOP)
+ #if defined(_WIN32)
+ const char *osName = "Windows";
+ #elif defined(__linux__)
+ const char *osName = "Linux";
+ #elif defined(__FreeBSD__)
+ const char *osName = "FreeBSD";
+ #elif defined(__APPLE__)
+ const char *osName = "macOS";
+ #endif // Desktop OSs
+ #endif
+#endif
+ /*
+ Columns:
+ - [CWARN] : Compilation WARNING messages
+ - [LWARN] : Log WARNING messages count
+ - [INIT] : Initialization
+ - [CLOSE] : Closing
+ - [ASSETS] : Assets loading
+ - [RLGL] : OpenGL-wrapped initialization
+ - [PLAT] : Platform initialization
+ - [FONT] : Font default initialization
+ - [TIMER] : Timer initialization
+
+ | **EXAMPLE NAME** | [CWARN] | [LWARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |
+ |:---------------------------------|:-------:|:-------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|
+ | core_basic window | 0 | 0 | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+ */
+ LOG("INFO: [examples_testing_os.md] Generating examples testing report...\n");
+
+ char *report = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
+
+ int repIndex = 0;
+ repIndex += sprintf(report + repIndex, "# EXAMPLES COLLECTION - TESTING REPORT\n\n");
+ repIndex += sprintf(report + repIndex, TextFormat("## Tested Platform: %s\n\n", osName));
+
+ repIndex += sprintf(report + repIndex, "```\nExample automated testing elements validated:\n");
+ repIndex += sprintf(report + repIndex, " - [CWARN] : Compilation WARNING messages\n");
+ repIndex += sprintf(report + repIndex, " - [LWARN] : Log WARNING messages count\n");
+ repIndex += sprintf(report + repIndex, " - [INIT] : Initialization\n");
+ repIndex += sprintf(report + repIndex, " - [CLOSE] : Closing\n");
+ repIndex += sprintf(report + repIndex, " - [ASSETS] : Assets loading\n");
+ repIndex += sprintf(report + repIndex, " - [RLGL] : OpenGL-wrapped initialization\n");
+ repIndex += sprintf(report + repIndex, " - [PLAT] : Platform initialization\n");
+ repIndex += sprintf(report + repIndex, " - [FONT] : Font default initialization\n");
+ repIndex += sprintf(report + repIndex, " - [TIMER] : Timer initialization\n```\n");
+
+ repIndex += sprintf(report + repIndex, "| **EXAMPLE NAME** | [CWARN] | [LWARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |\n");
+ repIndex += sprintf(report + repIndex, "|:---------------------------------|:-------:|:-------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|\n");
+
+ /*
+ TESTING_FAIL_INIT = 1 << 0, // Initialization (InitWindow()) -> "INFO: DISPLAY: Device initialized successfully"
+ TESTING_FAIL_CLOSE = 1 << 1, // Closing (CloseWindow()) -> "INFO: Window closed successfully"
+ TESTING_FAIL_ASSETS = 1 << 2, // Assets loading (WARNING: FILE:) -> "WARNING: FILEIO:"
+ TESTING_FAIL_RLGL = 1 << 3, // OpenGL-wrapped initialization -> "INFO: RLGL: Default OpenGL state initialized successfully"
+ TESTING_FAIL_PLATFORM = 1 << 4, // Platform initialization -> "INFO: PLATFORM: DESKTOP (GLFW - Win32): Initialized successfully"
+ TESTING_FAIL_FONT = 1 << 5, // Font default initialization -> "INFO: FONT: Default font loaded successfully (224 glyphs)"
+ TESTING_FAIL_TIMER = 1 << 6, // Timer initialization -> "INFO: TIMER: Target time per frame: 16.667 milliseconds"
+ */
+ for (int i = 0; i < exBuildListCount; i++)
+ {
+ if ((testing[i].buildwarns > 0) || (testing[i].warnings > 0) || (testing[i].status > 0))
+ {
+ repIndex += sprintf(report + repIndex, "| %-32s | %i | %i | %s | %s | %s | %s | %s | %s | %s |\n",
+ exBuildList[i],
+ testing[i].buildwarns,
+ testing[i].warnings,
+ (testing[i].status & TESTING_FAIL_INIT)? "❌" : "✔",
+ (testing[i].status & TESTING_FAIL_CLOSE)? "❌" : "✔",
+ (testing[i].status & TESTING_FAIL_ASSETS)? "❌" : "✔",
+ (testing[i].status & TESTING_FAIL_RLGL)? "❌" : "✔",
+ (testing[i].status & TESTING_FAIL_PLATFORM)? "❌" : "✔",
+ (testing[i].status & TESTING_FAIL_FONT)? "❌" : "✔",
+ (testing[i].status & TESTING_FAIL_TIMER)? "❌" : "✔");
+ }
+ }
+
+ repIndex += sprintf(report + repIndex, "\n");
+
+ SaveFileText(TextFormat("%s/../tools/rexm/reports/examples_testing_%s.md", exBasePath, TextToLower(osName)), report);
+
+ RL_FREE(report);
+ //-----------------------------------------------------------------------------------------------------
+
} break;
default: // Help
{
@@ -1409,6 +1865,7 @@ int main(int argc, char *argv[])
printf(" rename : Rename an existing example\n");
printf(" remove : Remove an existing example\n");
printf(" build : Build example for Desktop and Web platforms\n");
+ printf(" test : Build and Test example for Desktop and Web platforms\n");
printf(" validate : Validate examples collection, generates report\n");
printf(" update : Validate and update examples collection, generates report\n\n");
printf("OPTIONS:\n\n");
@@ -1437,18 +1894,20 @@ static int UpdateRequiredFiles(void)
// Edit: Example source code metadata for consistency
//------------------------------------------------------------------------------------------------
+ LOG("INFO: Updating all examples metadata...\n");
int exListCount = 0;
- rlExampleInfo *exList = LoadExamplesData(exCollectionFilePath, "ALL", true, &exListCount);
+ rlExampleInfo *exList = LoadExampleData("ALL", true, &exListCount);
for (int i = 0; i < exListCount; i++)
{
rlExampleInfo *info = &exList[i];
UpdateSourceMetadata(TextFormat("%s/%s/%s.c", exBasePath, info->category, info->name), info);
}
- UnloadExamplesData(exList);
+ UnloadExampleData(exList);
//------------------------------------------------------------------------------------------------
// Edit: raylib/examples/Makefile --> Update from collection
//------------------------------------------------------------------------------------------------
+ LOG("INFO: Updating raylib/examples/Makefile\n");
char *mkText = LoadFileText(TextFormat("%s/Makefile", exBasePath));
char *mkTextUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); // Updated Makefile copy, 2MB
@@ -1464,12 +1923,12 @@ static int UpdateRequiredFiles(void)
mkIndex += sprintf(mkTextUpdated + mkListStartIndex + mkIndex, TextFormat("%s = \\\n", TextToUpper(exCategories[i])));
int exCollectionCount = 0;
- rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], true, &exCollectionCount);
+ rlExampleInfo *exCollection = LoadExampleData(exCategories[i], true, &exCollectionCount);
for (int x = 0; x < exCollectionCount - 1; x++) mkIndex += sprintf(mkTextUpdated + mkListStartIndex + mkIndex, TextFormat(" %s/%s \\\n", exCollection[x].category, exCollection[x].name));
mkIndex += sprintf(mkTextUpdated + mkListStartIndex + mkIndex, TextFormat(" %s/%s\n\n", exCollection[exCollectionCount - 1].category, exCollection[exCollectionCount - 1].name));
- UnloadExamplesData(exCollection);
+ UnloadExampleData(exCollection);
}
// Add the remaining part of the original file
@@ -1484,6 +1943,7 @@ static int UpdateRequiredFiles(void)
// Edit: raylib/examples/Makefile.Web --> Update from collection
// NOTE: We avoid the "others" category on web building
//------------------------------------------------------------------------------------------------
+ LOG("INFO: Updating raylib/examples/Makefile.Web\n");
char *mkwText = LoadFileText(TextFormat("%s/Makefile.Web", exBasePath));
char *mkwTextUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); // Updated Makefile copy, 2MB
@@ -1500,12 +1960,12 @@ static int UpdateRequiredFiles(void)
mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat("%s = \\\n", TextToUpper(exCategories[i])));
int exCollectionCount = 0;
- rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], true, &exCollectionCount);
+ rlExampleInfo *exCollection = LoadExampleData(exCategories[i], true, &exCollectionCount);
for (int x = 0; x < exCollectionCount - 1; x++) mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat(" %s/%s \\\n", exCollection[x].category, exCollection[x].name));
mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat(" %s/%s\n\n", exCollection[exCollectionCount - 1].category, exCollection[exCollectionCount - 1].name));
- UnloadExamplesData(exCollection);
+ UnloadExampleData(exCollection);
}
// Add examples individual targets, considering every example resources
@@ -1526,13 +1986,13 @@ static int UpdateRequiredFiles(void)
mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat("# Compile %s examples\n", TextToUpper(exCategories[i])));
int exCollectionCount = 0;
- rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], true, &exCollectionCount);
+ rlExampleInfo *exCollection = LoadExampleData(exCategories[i], true, &exCollectionCount);
for (int x = 0; x < exCollectionCount; x++)
{
// Scan resources used in example to list
int resPathCount = 0;
- char **resPaths = ScanExampleResources(TextFormat("%s/%s/%s.c", exBasePath, exCollection[x].category, exCollection[x].name), &resPathCount);
+ char **resPaths = LoadExampleResourcePaths(TextFormat("%s/%s/%s.c", exBasePath, exCollection[x].category, exCollection[x].name), &resPathCount);
if (resPathCount > 0)
{
@@ -1585,10 +2045,10 @@ static int UpdateRequiredFiles(void)
mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, " $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)\n\n");
}
- ClearExampleResources(resPaths);
+ UnloadExampleResourcePaths(resPaths);
}
- UnloadExamplesData(exCollection);
+ UnloadExampleData(exCollection);
}
// Add the remaining part of the original file
@@ -1602,6 +2062,7 @@ static int UpdateRequiredFiles(void)
// Edit: raylib/examples/README.md --> Update from collection
//------------------------------------------------------------------------------------------------
+ LOG("INFO: Updating raylib/examples/README.md\n");
// NOTE: Using [examples_list.txt] to update/regen README.md
// Lines format: | 01 | [core_basic_window](core/core_basic_window.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
char *mdText = LoadFileText(TextFormat("%s/README.md", exBasePath));
@@ -1613,8 +2074,8 @@ static int UpdateRequiredFiles(void)
memcpy(mdTextUpdated, mdText, mdListStartIndex);
int exCollectionFullCount = 0;
- rlExampleInfo *exCollectionFull = LoadExamplesData(exCollectionFilePath, "ALL", false, &exCollectionFullCount);
- UnloadExamplesData(exCollectionFull);
+ rlExampleInfo *exCollectionFull = LoadExampleData("ALL", false, &exCollectionFullCount);
+ UnloadExampleData(exCollectionFull);
mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, TextFormat("## EXAMPLES COLLECTION [TOTAL: %i]\n", exCollectionFullCount));
@@ -1622,14 +2083,14 @@ static int UpdateRequiredFiles(void)
for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++)
{
int exCollectionCount = 0;
- rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], false, &exCollectionCount);
+ rlExampleInfo *exCollection = LoadExampleData(exCategories[i], false, &exCollectionCount);
// Every category includes some introductory text, as it is quite short, just copying it here
if (i == 0) // "core"
{
mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, TextFormat("\n### category: core [%i]\n\n", exCollectionCount));
mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex,
- "Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality.\n\n");
+ "Examples using raylib [core](../src/rcore.c) module platform functionality: window creation, inputs, drawing modes and system functionality.\n\n");
}
else if (i == 1) // "shapes"
{
@@ -1693,13 +2154,13 @@ static int UpdateRequiredFiles(void)
starsText, exCollection[x].verCreated, exCollection[x].verUpdated, exCollection[x].author, exCollection[x].authorGitHub));
}
- UnloadExamplesData(exCollection);
+ UnloadExampleData(exCollection);
}
mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex,
"\nSome example missing? As always, contributions are welcome, feel free to send new examples!\n");
mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex,
- "Here is an[examples template](examples_template.c) with instructions to start with!\n");
+ "Here is an [examples template](examples_template.c) with instructions to start with!\n");
// Save updated file
SaveFileText(TextFormat("%s/README.md", exBasePath), mdTextUpdated);
@@ -1710,6 +2171,7 @@ static int UpdateRequiredFiles(void)
// Edit: raylib.com/common/examples.js --> Update from collection
// NOTE: Entries format: exampleEntry('⭐️☆☆☆' , 'core' , 'basic_window'),
//------------------------------------------------------------------------------------------------
+ LOG("INFO: Updating raylib.com/common/examples.js\n");
char *jsText = LoadFileText(TextFormat("%s/../common/examples.js", exWebPath));
if (!jsText)
{
@@ -1738,7 +2200,7 @@ static int UpdateRequiredFiles(void)
for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES - 1; i++)
{
int exCollectionCount = 0;
- rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], false, &exCollectionCount);
+ rlExampleInfo *exCollection = LoadExampleData(exCategories[i], false, &exCollectionCount);
for (int x = 0; x < exCollectionCount; x++)
{
for (int s = 0; s < 4; s++)
@@ -1760,7 +2222,7 @@ static int UpdateRequiredFiles(void)
}
}
- UnloadExamplesData(exCollection);
+ UnloadExampleData(exCollection);
}
// Add the remaining part of the original file
@@ -1777,8 +2239,8 @@ static int UpdateRequiredFiles(void)
return result;
}
-// Load examples collection information
-static rlExampleInfo *LoadExamplesData(const char *fileName, const char *category, bool sort, int *exCount)
+// Load examples information from collection data
+static rlExampleInfo *LoadExampleData(const char *filter, bool sort, int *exCount)
{
#define MAX_EXAMPLES_INFO 256
@@ -1786,7 +2248,8 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor
int exCounter = 0;
*exCount = 0;
- char *text = LoadFileText(fileName);
+ // Load main collection list file: "raylib/examples/examples_list.txt"
+ char *text = LoadFileText(exCollectionFilePath);
if (text != NULL)
{
@@ -1808,18 +2271,25 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor
int result = ParseExampleInfoLine(lines[i], &info);
if (result == 1) // Success on parsing
{
- if (strcmp(category, "ALL") == 0)
+ if (strcmp(filter, "ALL") == 0)
{
// Add all examples to the list
memcpy(&exInfo[exCounter], &info, sizeof(rlExampleInfo));
exCounter++;
}
- else if (strcmp(info.category, category) == 0)
+ else if (strcmp(info.category, filter) == 0)
{
// Get only specific category examples
memcpy(&exInfo[exCounter], &info, sizeof(rlExampleInfo));
exCounter++;
}
+ else if (strcmp(info.name, filter) == 0)
+ {
+ // Get only requested example
+ memcpy(&exInfo[exCounter], &info, sizeof(rlExampleInfo));
+ exCounter++;
+ break;
+ }
}
}
}
@@ -1836,7 +2306,7 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor
}
// Unload examples collection data
-static void UnloadExamplesData(rlExampleInfo *exInfo)
+static void UnloadExampleData(rlExampleInfo *exInfo)
{
RL_FREE(exInfo);
}
@@ -1845,10 +2315,13 @@ static void UnloadExamplesData(rlExampleInfo *exInfo)
// WARNING: Expecting the example to follow raylib_example_template.c
static rlExampleInfo *LoadExampleInfo(const char *exFileName)
{
- rlExampleInfo *exInfo = (rlExampleInfo *)RL_CALLOC(1, sizeof(rlExampleInfo));
+ rlExampleInfo *exInfo = NULL;
if (FileExists(exFileName) && IsFileExtension(exFileName, ".c"))
{
+ // Example found in collection
+ exInfo = (rlExampleInfo *)RL_CALLOC(1, sizeof(rlExampleInfo));
+
strcpy(exInfo->name, GetFileNameWithoutExt(exFileName));
strncpy(exInfo->category, exInfo->name, TextFindIndex(exInfo->name, "_"));
@@ -1923,7 +2396,7 @@ static rlExampleInfo *LoadExampleInfo(const char *exFileName)
UnloadFileText(exText);
- exInfo->resPaths = ScanExampleResources(exFileName, &exInfo->resCount);
+ exInfo->resPaths = LoadExampleResourcePaths(exFileName, &exInfo->resCount);
}
return exInfo;
@@ -1932,7 +2405,7 @@ static rlExampleInfo *LoadExampleInfo(const char *exFileName)
// Unload example information
static void UnloadExampleInfo(rlExampleInfo *exInfo)
{
- ClearExampleResources(exInfo->resPaths);
+ UnloadExampleResourcePaths(exInfo->resPaths);
RL_FREE(exInfo);
}
@@ -2008,7 +2481,7 @@ static void SortExampleByName(rlExampleInfo *items, int count)
// but new examples could require other file extensions to be added,
// maybe it should look for '.xxx")' patterns instead
// TODO: WARNING: Some resources could require linked resources: .fnt --> .png, .mtl --> .png, .gltf --> .png, ...
-static char **ScanExampleResources(const char *filePath, int *resPathCount)
+static char **LoadExampleResourcePaths(const char *filePath, int *resPathCount)
{
#define REXM_MAX_RESOURCE_PATH_LEN 256
@@ -2037,11 +2510,14 @@ static char **ScanExampleResources(const char *filePath, int *resPathCount)
int functionIndex01 = TextFindIndex(ptr - 40, "ExportImage"); // Check ExportImage()
int functionIndex02 = TextFindIndex(ptr - 10, "TraceLog"); // Check TraceLog()
int functionIndex03 = TextFindIndex(ptr - 40, "TakeScreenshot"); // Check TakeScreenshot()
-
+ int functionIndex04 = TextFindIndex(ptr - 40, "SaveFileData"); // Check SaveFileData()
+ int functionIndex05 = TextFindIndex(ptr - 40, "SaveFileText"); // Check SaveFileText()
if (!((functionIndex01 != -1) && (functionIndex01 < 40)) && // Not found ExportImage() before ""
!((functionIndex02 != -1) && (functionIndex02 < 10)) && // Not found TraceLog() before ""
- !((functionIndex03 != -1) && (functionIndex03 < 40))) // Not found TakeScreenshot() before ""
+ !((functionIndex03 != -1) && (functionIndex03 < 40)) && // Not found TakeScreenshot() before ""
+ !((functionIndex04 != -1) && (functionIndex04 < 40)) && // Not found TakeScreenshot() before ""
+ !((functionIndex05 != -1) && (functionIndex05 < 40))) // Not found SaveFileText() before ""
{
int len = (int)(end - start);
if ((len > 0) && (len < REXM_MAX_RESOURCE_PATH_LEN))
@@ -2087,7 +2563,7 @@ static char **ScanExampleResources(const char *filePath, int *resPathCount)
}
// Clear resource paths scanned
-static void ClearExampleResources(char **resPaths)
+static void UnloadExampleResourcePaths(char **resPaths)
{
for (int i = 0; i < REXM_MAX_RESOURCE_PATHS; i++) RL_FREE(resPaths[i]);
@@ -2146,29 +2622,29 @@ static int AddVSProjectToSolution(const char *slnFile, const char *projFile, con
// Add project config lines
offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t{%s}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug.DLL|x64.Build.0 = Debug.DLL|x64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|ARM64.ActiveCfg = Debug|ARM64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|ARM64.Build.0 = Debug|ARM64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|x64.ActiveCfg = Debug|x64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|x64.Build.0 = Debug|x64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|x86.ActiveCfg = Debug|Win32\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|x86.Build.0 = Debug|Win32\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|x64.ActiveCfg = Release.DLL|x64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|x64.Build.0 = Release.DLL|x64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|x86.Build.0 = Release.DLL|Win32\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|ARM64.ActiveCfg = Release|ARM64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|ARM64.Build.0 = Release|ARM64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|x64.ActiveCfg = Release|x64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|x64.Build.0 = Release|x64\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|x86.ActiveCfg = Release|Win32\n", uuid));
- offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|x86.Build.0 = Release|Win32\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug.DLL|x64.Build.0 = Debug.DLL|x64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|ARM64.ActiveCfg = Debug|ARM64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|ARM64.Build.0 = Debug|ARM64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|x64.ActiveCfg = Debug|x64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|x64.Build.0 = Debug|x64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|x86.ActiveCfg = Debug|Win32\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Debug|x86.Build.0 = Debug|Win32\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|x64.ActiveCfg = Release.DLL|x64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|x64.Build.0 = Release.DLL|x64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release.DLL|x86.Build.0 = Release.DLL|Win32\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|ARM64.ActiveCfg = Release|ARM64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|ARM64.Build.0 = Release|ARM64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|x64.ActiveCfg = Release|x64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|x64.Build.0 = Release|x64\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|x86.ActiveCfg = Release|Win32\n", uuid));
+ offsetIndex += sprintf(slnTextUpdated + offsetIndex, TextFormat("\t\t{%s}.Release|x86.Build.0 = Release|Win32\n", uuid));
// Write next section directly to avoid copy logic
offsetIndex += sprintf(slnTextUpdated + offsetIndex, "\tEndGlobalSection\n");
offsetIndex += sprintf(slnTextUpdated + offsetIndex, "\tGlobalSection(SolutionProperties) = preSolution\n");
@@ -2233,7 +2709,7 @@ static int RemoveVSProjectFromSolution(const char *slnFile, const char *exName)
char uuid[38] = { 0 };
strcpy(uuid, "ABCDEF00-0123-4567-89AB-000000000012"); // Temp value
int textUpdatedOfsset = 0;
- int exNameLen = strlen(exName);
+ int exNameLen = (int)strlen(exName);
for (int i = 0, index = 0; i < lineCount; i++)
{
@@ -2304,7 +2780,7 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf
char exNameFormated[256] = { 0 }; // Example name without category and using spaces
int exNameIndex = TextFindIndex(info->name, "_");
strcpy(exNameFormated, info->name + exNameIndex + 1);
- int exNameLen = strlen(exNameFormated);
+ int exNameLen = (int)strlen(exNameFormated);
for (int i = 0; i < exNameLen; i++) { if (exNameFormated[i] == '_') exNameFormated[i] = ' '; }
// Update example header title (line #3 - ALWAYS)
diff --git a/tools/rexm/rexm.rc b/tools/rexm/rexm.rc
index ad125f796..4d3785a6a 100644
--- a/tools/rexm/rexm.rc
+++ b/tools/rexm/rexm.rc
@@ -6,8 +6,8 @@ PRODUCTVERSION 1,0,0,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
- //BLOCK "080904E4" // English UK
- BLOCK "040904E4" // English US
+ //BLOCK "080904E4" // English UK
+ BLOCK "040904E4" // English US
BEGIN
VALUE "CompanyName", "Ramon Santamaria"
VALUE "FileDescription", "rexm | raylib examples manager"
@@ -21,7 +21,7 @@ BEGIN
END
BLOCK "VarFileInfo"
BEGIN
- //VALUE "Translation", 0x809, 1252 // English UK
- VALUE "Translation", 0x409, 1252 // English US
+ //VALUE "Translation", 0x809, 1252 // English UK
+ VALUE "Translation", 0x409, 1252 // English US
END
END
diff --git a/tools/rlparser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json
index c0bc88681..b3d02a928 100644
--- a/tools/rlparser/output/raylib_api.json
+++ b/tools/rlparser/output/raylib_api.json
@@ -40,7 +40,7 @@
"name": "RLAPI",
"type": "UNKNOWN",
"value": "__declspec(dllexport)",
- "description": "We are building the library as a Win32 shared library (.dll)"
+ "description": "Building the library as a Win32 shared library (.dll)"
},
{
"name": "PI",
@@ -11897,7 +11897,7 @@
},
{
"name": "SetSoundPan",
- "description": "Set pan for a sound (0.5 is center)",
+ "description": "Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)",
"returnType": "void",
"params": [
{
@@ -12150,7 +12150,7 @@
},
{
"name": "SetMusicPan",
- "description": "Set pan for a music (0.5 is center)",
+ "description": "Set pan for a music (-1.0 left, 0.0 center, 1.0 right)",
"returnType": "void",
"params": [
{
diff --git a/tools/rlparser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua
index 5cb3c1d55..e680a5acf 100644
--- a/tools/rlparser/output/raylib_api.lua
+++ b/tools/rlparser/output/raylib_api.lua
@@ -40,7 +40,7 @@ return {
name = "RLAPI",
type = "UNKNOWN",
value = "__declspec(dllexport)",
- description = "We are building the library as a Win32 shared library (.dll)"
+ description = "Building the library as a Win32 shared library (.dll)"
},
{
name = "PI",
@@ -8105,7 +8105,7 @@ return {
},
{
name = "SetSoundPan",
- description = "Set pan for a sound (0.5 is center)",
+ description = "Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)",
returnType = "void",
params = {
{type = "Sound", name = "sound"},
@@ -8268,7 +8268,7 @@ return {
},
{
name = "SetMusicPan",
- description = "Set pan for a music (0.5 is center)",
+ description = "Set pan for a music (-1.0 left, 0.0 center, 1.0 right)",
returnType = "void",
params = {
{type = "Music", name = "music"},
diff --git a/tools/rlparser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt
index 9be8e517c..e2edb8f3f 100644
--- a/tools/rlparser/output/raylib_api.txt
+++ b/tools/rlparser/output/raylib_api.txt
@@ -35,7 +35,7 @@ Define 007: RLAPI
Name: RLAPI
Type: UNKNOWN
Value: __declspec(dllexport)
- Description: We are building the library as a Win32 shared library (.dll)
+ Description: Building the library as a Win32 shared library (.dll)
Define 008: PI
Name: PI
Type: FLOAT
@@ -4554,7 +4554,7 @@ Function 556: SetSoundPitch() (2 input parameters)
Function 557: SetSoundPan() (2 input parameters)
Name: SetSoundPan
Return type: void
- Description: Set pan for a sound (0.5 is center)
+ Description: Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)
Param[1]: sound (type: Sound)
Param[2]: pan (type: float)
Function 558: WaveCopy() (1 input parameters)
@@ -4660,7 +4660,7 @@ Function 575: SetMusicPitch() (2 input parameters)
Function 576: SetMusicPan() (2 input parameters)
Name: SetMusicPan
Return type: void
- Description: Set pan for a music (0.5 is center)
+ Description: Set pan for a music (-1.0 left, 0.0 center, 1.0 right)
Param[1]: music (type: Music)
Param[2]: pan (type: float)
Function 577: GetMusicTimeLength() (1 input parameters)
diff --git a/tools/rlparser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml
index 96dbdbf64..3d1892c7c 100644
--- a/tools/rlparser/output/raylib_api.xml
+++ b/tools/rlparser/output/raylib_api.xml
@@ -7,7 +7,7 @@
-
+
@@ -3043,7 +3043,7 @@
-
+
@@ -3111,7 +3111,7 @@
-
+
diff --git a/tools/rlparser/rlparser b/tools/rlparser/rlparser
deleted file mode 100755
index b68032c02..000000000
Binary files a/tools/rlparser/rlparser and /dev/null differ