diff --git a/.github/workflows/update_examples.yml b/.github/workflows/update_examples.yml
index 7feba7d89..c4ada2bd1 100644
--- a/.github/workflows/update_examples.yml
+++ b/.github/workflows/update_examples.yml
@@ -29,8 +29,9 @@ jobs:
shell: bash
- name: Build and run rexm tool (requires GNU Makefile)
- # "rexm update" validates and updates all required examples in raylib and even raylib.com repos,
- # note that it calls examples/Makefile.Web internally, so it requires [make] tool available
+ # "rexm validate" validates examples collection, looking for inconsistencies, it does not rebuild examples
+ # "rexm update" validates and updates all examples with inconsistencies, pushing fixes to raylib and raylib.com repos
+ # note that rexm calls examples/Makefile.Web internally, so it requires [make] tool available
run: |
sudo apt-get update && sudo apt-get install -y libopengl0 libglu1-mesa libx11-dev libxrandr-dev libxcursor-dev libxi-dev libxinerama-dev libgl1-mesa-dev libglu1-mesa-dev
cd "${{ github.workspace }}/src"
@@ -47,7 +48,7 @@ jobs:
export REXM_EXAMPLES_COLLECTION_FILE_PATH="${{ github.workspace }}/examples/examples_list.txt"
export REXM_EXAMPLES_VS2022_SLN_FILE="${{ github.workspace }}/projects/VS2022/raylib.sln"
export EMSDK_PATH="${{ github.workspace }}/emsdk-cache/emsdk-main"
- ./rexm update
+ ./rexm validate
shell: bash
- name: Commit changes to raylib repo (DISABLED)
diff --git a/.gitignore b/.gitignore
index 67afa01ab..498b377cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,6 +58,10 @@ packages/
*.h.pch
./*.obj
+# Ignore SDL libs for testing
+src/external/SDL2
+src/external/SDL3
+
# Emscripten
emsdk
diff --git a/BINDINGS.md b/BINDINGS.md
index 07f590d7d..ee7da46f4 100644
--- a/BINDINGS.md
+++ b/BINDINGS.md
@@ -76,6 +76,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [raylib-rs](https://github.com/raylib-rs/raylib-rs) | **5.5** | [Rust](https://www.rust-lang.org) | Zlib |
| [raylib-ruby](https://github.com/wilsonsilva/raylib-ruby) | 4.5 | [Ruby](https://www.ruby-lang.org) | Zlib |
| [Relib](https://github.com/RedCubeDev-ByteSpace/Relib) | 3.5 | [ReCT](https://github.com/RedCubeDev-ByteSpace/ReCT) | **???** |
+| [ringraylib5](https://github.com/ring-lang/ring/tree/master/extensions/ringraylib5) | **5.0** | [Ring](https://ring-lang.github.io/) | **???** |
| [racket-raylib](https://github.com/eutro/racket-raylib) | **5.5** | [Racket](https://racket-lang.org) | MIT/Apache-2.0 |
| [raylib-swift](https://github.com/STREGAsGate/Raylib) | 4.0 | [Swift](https://swift.org) | MIT |
| [raylib-scopes](https://github.com/salotz/raylib-scopes) | auto | [Scopes](http://scopes.rocks) | MIT |
diff --git a/CHANGELOG b/CHANGELOG
index f792bca4d..29e4d8174 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -565,7 +565,7 @@ Detailed changes:
[rtext] ADDED: SetTextLineSpacing() to define line breaks text drawing spacing by @raysan5
[rtext] RENAMED: LoadFont*() parameter names for consistency and coherence by @raysan5
[rtext] REVIEWED: GetCodepointCount(), ignore unused return value of GetCodepointNext by @ashn-dot-dev
-[rtext] REVIEWED: TextFormat() warn user if buffer overflow occured (#3399) by @Murlocohol
+[rtext] REVIEWED: TextFormat() warn user if buffer overflow occurred (#3399) by @Murlocohol
[rtext] REVIEWED: TextFormat(), added "..." for truncation (#3366) by @raysan5
[rtext] REVIEWED: GetGlyphIndex() (#3000) by @raysan5
[rtext] REVIEWED: GetCodepointNext() to return default value by @chocolate42
diff --git a/CMakeOptions.txt b/CMakeOptions.txt
index 32cfb814e..cb1b95b0c 100644
--- a/CMakeOptions.txt
+++ b/CMakeOptions.txt
@@ -6,7 +6,7 @@ if(EMSCRIPTEN)
# When configuring web builds with "emcmake cmake -B build -S .", set PLATFORM to Web by default
SET(PLATFORM Web CACHE STRING "Platform to build for.")
endif()
-enum_option(PLATFORM "Desktop;Web;Android;Raspberry Pi;DRM;SDL" "Platform to build for.")
+enum_option(PLATFORM "Desktop;Web;Android;Raspberry Pi;DRM;SDL;RGFW" "Platform to build for.")
enum_option(OPENGL_VERSION "OFF;4.3;3.3;2.1;1.1;ES 2.0;ES 3.0;Software" "Force a specific OpenGL Version?")
diff --git a/build.zig b/build.zig
index 031a6824d..239b10f9e 100644
--- a/build.zig
+++ b/build.zig
@@ -106,9 +106,9 @@ const config_h_flags = outer: {
if (std.mem.startsWith(u8, line, "//")) continue;
if (std.mem.startsWith(u8, line, "#if")) continue;
- var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace
+ var flag = std.mem.trimStart(u8, line, " \t"); // Trim whitespace
flag = flag["#define ".len - 1 ..]; // Remove #define
- flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace
+ flag = std.mem.trimStart(u8, flag, " \t"); // Trim whitespace
flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space
flag = "-D" ++ flag; // Prepend with -D
@@ -155,9 +155,9 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
);
}
- // Sets a flag indiciating the use of a custom `config.h`
- try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
if (options.config.len > 0) {
+ // Sets a flag indicating the use of a custom `config.h`
+ try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
// Splits a space-separated list of config flags into multiple flags
//
// Note: This means certain flags like `-x c++` won't be processed properly.
@@ -187,13 +187,13 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
try raylib_flags_arr.append(b.allocator, flag);
}
} else {
- // Set default config if no custome config got set
+ // Set default config if no custom config got set
try raylib_flags_arr.appendSlice(b.allocator, &config_h_flags);
}
// No GLFW required on PLATFORM_DRM
if (options.platform != .drm) {
- raylib.addIncludePath(b.path("src/external/glfw/include"));
+ raylib.root_module.addIncludePath(b.path("src/external/glfw/include"));
}
var c_source_files: std.ArrayList([]const u8) = try .initCapacity(b.allocator, 2);
@@ -224,7 +224,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
raylib.root_module.addCMacro(options.opengl_version.toCMacroStr(), "");
}
- raylib.addIncludePath(b.path("src/platforms"));
+ raylib.root_module.addIncludePath(b.path("src/platforms"));
switch (target.result.os.tag) {
.windows => {
switch (options.platform) {
@@ -438,7 +438,7 @@ pub const Options = struct {
pub fn getOptions(b: *std.Build) Options {
return .{
- .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform,
+ .platform = b.option(PlatformBackend, "platform", "Choose the platform backend for desktop target") orelse defaults.platform,
.raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio,
.rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels,
.rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext,
diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake
index 8f127fc23..96abeea93 100644
--- a/cmake/LibraryConfigurations.cmake
+++ b/cmake/LibraryConfigurations.cmake
@@ -141,6 +141,8 @@ elseif ("${PLATFORM}" MATCHES "SDL")
add_compile_definitions(USING_SDL2_PACKAGE)
endif()
endif()
+elseif ("${PLATFORM}" MATCHES "RGFW")
+ set(PLATFORM_CPP "PLATFORM_DESKTOP_RGFW")
endif ()
if (NOT ${OPENGL_VERSION} MATCHES "OFF")
diff --git a/examples/Makefile b/examples/Makefile
index 72df8571a..bc2afbb3c 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -531,7 +531,7 @@ CORE = \
core/core_delta_time \
core/core_directory_files \
core/core_drop_files \
- core/core_high_dpi \
+ core/core_highdpi_demo \
core/core_highdpi_testbed \
core/core_input_actions \
core/core_input_gamepad \
@@ -560,6 +560,7 @@ CORE = \
core/core_world_screen
SHAPES = \
+ shapes/shapes_ball_physics \
shapes/shapes_basic_shapes \
shapes/shapes_bouncing_ball \
shapes/shapes_bullet_hell \
@@ -582,6 +583,7 @@ SHAPES = \
shapes/shapes_math_angle_rotation \
shapes/shapes_math_sine_cosine \
shapes/shapes_mouse_trail \
+ shapes/shapes_penrose_tile \
shapes/shapes_pie_chart \
shapes/shapes_rectangle_advanced \
shapes/shapes_rectangle_scaling \
@@ -601,6 +603,7 @@ TEXTURES = \
textures/textures_background_scrolling \
textures/textures_blend_modes \
textures/textures_bunnymark \
+ textures/textures_cellular_automata \
textures/textures_fog_of_war \
textures/textures_gif_player \
textures/textures_image_channel \
@@ -639,6 +642,7 @@ TEXT = \
text/text_input_box \
text/text_rectangle_bounds \
text/text_sprite_fonts \
+ text/text_strings_management \
text/text_unicode_emojis \
text/text_unicode_ranges \
text/text_words_alignment \
@@ -684,6 +688,7 @@ SHADERS = \
shaders/shaders_depth_writing \
shaders/shaders_eratosthenes_sieve \
shaders/shaders_fog_rendering \
+ shaders/shaders_game_of_life \
shaders/shaders_hot_reloading \
shaders/shaders_hybrid_rendering \
shaders/shaders_julia_set \
diff --git a/examples/Makefile.Android b/examples/Makefile.Android
index c00da171e..cf4ad1257 100644
--- a/examples/Makefile.Android
+++ b/examples/Makefile.Android
@@ -130,7 +130,7 @@ ifeq ($(ANDROID_ARCH),ARM)
CFLAGS = -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16
endif
ifeq ($(ANDROID_ARCH),ARM64)
- CFLAGS = -std=c99 -target aarch64 -mfix-cortex-a53-835769
+ CFLAGS = -std=c99 -mfix-cortex-a53-835769
endif
# Compilation functions attributes options
CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC
diff --git a/examples/Makefile.Web b/examples/Makefile.Web
index 431b2cad9..f36113f15 100644
--- a/examples/Makefile.Web
+++ b/examples/Makefile.Web
@@ -519,7 +519,7 @@ CORE = \
core/core_delta_time \
core/core_directory_files \
core/core_drop_files \
- core/core_high_dpi \
+ core/core_highdpi_demo \
core/core_highdpi_testbed \
core/core_input_actions \
core/core_input_gamepad \
@@ -548,6 +548,7 @@ CORE = \
core/core_world_screen
SHAPES = \
+ shapes/shapes_ball_physics \
shapes/shapes_basic_shapes \
shapes/shapes_bouncing_ball \
shapes/shapes_bullet_hell \
@@ -570,6 +571,7 @@ SHAPES = \
shapes/shapes_math_angle_rotation \
shapes/shapes_math_sine_cosine \
shapes/shapes_mouse_trail \
+ shapes/shapes_penrose_tile \
shapes/shapes_pie_chart \
shapes/shapes_rectangle_advanced \
shapes/shapes_rectangle_scaling \
@@ -589,6 +591,7 @@ TEXTURES = \
textures/textures_background_scrolling \
textures/textures_blend_modes \
textures/textures_bunnymark \
+ textures/textures_cellular_automata \
textures/textures_fog_of_war \
textures/textures_gif_player \
textures/textures_image_channel \
@@ -627,6 +630,7 @@ TEXT = \
text/text_input_box \
text/text_rectangle_bounds \
text/text_sprite_fonts \
+ text/text_strings_management \
text/text_unicode_emojis \
text/text_unicode_ranges \
text/text_words_alignment \
@@ -672,6 +676,7 @@ SHADERS = \
shaders/shaders_depth_writing \
shaders/shaders_eratosthenes_sieve \
shaders/shaders_fog_rendering \
+ shaders/shaders_game_of_life \
shaders/shaders_hot_reloading \
shaders/shaders_hybrid_rendering \
shaders/shaders_julia_set \
@@ -778,7 +783,7 @@ core/core_directory_files: core/core_directory_files.c
core/core_drop_files: core/core_drop_files.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
-core/core_high_dpi: core/core_high_dpi.c
+core/core_highdpi_demo: core/core_highdpi_demo.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
core/core_highdpi_testbed: core/core_highdpi_testbed.c
@@ -864,6 +869,9 @@ core/core_world_screen: core/core_world_screen.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
# Compile SHAPES examples
+shapes/shapes_ball_physics: shapes/shapes_ball_physics.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
shapes/shapes_basic_shapes: shapes/shapes_basic_shapes.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@@ -930,6 +938,9 @@ shapes/shapes_math_sine_cosine: shapes/shapes_math_sine_cosine.c
shapes/shapes_mouse_trail: shapes/shapes_mouse_trail.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+shapes/shapes_penrose_tile: shapes/shapes_penrose_tile.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
shapes/shapes_pie_chart: shapes/shapes_pie_chart.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@@ -988,6 +999,9 @@ textures/textures_bunnymark: textures/textures_bunnymark.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/raybunny.png@resources/raybunny.png
+textures/textures_cellular_automata: textures/textures_cellular_automata.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
textures/textures_fog_of_war: textures/textures_fog_of_war.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@@ -1139,6 +1153,9 @@ text/text_sprite_fonts: text/text_sprite_fonts.c
--preload-file text/resources/sprite_fonts/alpha_beta.png@resources/sprite_fonts/alpha_beta.png \
--preload-file text/resources/sprite_fonts/jupiter_crash.png@resources/sprite_fonts/jupiter_crash.png
+text/text_strings_management: text/text_strings_management.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
text/text_unicode_emojis: text/text_unicode_emojis.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file text/resources/dejavu.fnt@resources/dejavu.fnt \
@@ -1347,6 +1364,19 @@ shaders/shaders_fog_rendering: shaders/shaders_fog_rendering.c
--preload-file shaders/resources/shaders/glsl100/lighting.vs@resources/shaders/glsl100/lighting.vs \
--preload-file shaders/resources/shaders/glsl100/fog.fs@resources/shaders/glsl100/fog.fs
+shaders/shaders_game_of_life: shaders/shaders_game_of_life.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
+ --preload-file shaders/resources/shaders/glsl100/game_of_life.fs@resources/shaders/glsl100/game_of_life.fs \
+ --preload-file shaders/resources/game_of_life/acorn.png@resources/game_of_life/acorn.png \
+ --preload-file shaders/resources/game_of_life/breeder.png@resources/game_of_life/breeder.png \
+ --preload-file shaders/resources/game_of_life/glider.png@resources/game_of_life/glider.png \
+ --preload-file shaders/resources/game_of_life/glider_gun.png@resources/game_of_life/glider_gun.png \
+ --preload-file shaders/resources/game_of_life/oscillators.png@resources/game_of_life/oscillators.png \
+ --preload-file shaders/resources/game_of_life/puffer_train.png@resources/game_of_life/puffer_train.png \
+ --preload-file shaders/resources/game_of_life/r_pentomino.png@resources/game_of_life/r_pentomino.png \
+ --preload-file shaders/resources/game_of_life/spaceships.png@resources/game_of_life/spaceships.png \
+ --preload-file shaders/resources/game_of_life/still_lifes.png@resources/game_of_life/still_lifes.png
+
shaders/shaders_hot_reloading: shaders/shaders_hot_reloading.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file shaders/resources/shaders/glsl100/reload.fs@resources/shaders/glsl100/reload.fs
diff --git a/examples/README.md b/examples/README.md
index 77b6ff37e..367bfa0ab 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -17,7 +17,7 @@ You may find it easier to use than other toolchains, especially when it comes to
- `zig build [module]` to compile all examples for a module (e.g. `zig build core`)
- `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`)
-## EXAMPLES COLLECTION [TOTAL: 200]
+## EXAMPLES COLLECTION [TOTAL: 205]
### category: core [47]
@@ -61,7 +61,7 @@ Examples using raylib [core](../src/rcore.c) module platform functionality: wind
| [core_smooth_pixelperfect](core/core_smooth_pixelperfect.c) |
| ⭐⭐⭐☆ | 3.7 | 4.0 | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) |
| [core_random_sequence](core/core_random_sequence.c) |
| ⭐☆☆☆ | 5.0 | 5.0 | [Dalton Overmyer](https://github.com/REDl3east) |
| [core_automation_events](core/core_automation_events.c) |
| ⭐⭐⭐☆ | 5.0 | 5.0 | [Ramon Santamaria](https://github.com/raysan5) |
-| [core_high_dpi](core/core_high_dpi.c) |
| ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) |
+| [core_highdpi_demo](core/core_highdpi_demo.c) |
| ⭐⭐☆☆ | 5.0 | 5.5 | [Jonathan Marler](https://github.com/marler8997) |
| [core_render_texture](core/core_render_texture.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_undo_redo](core/core_undo_redo.c) |
| ⭐⭐⭐☆ | 5.5 | 5.6 | [Ramon Santamaria](https://github.com/raysan5) |
| [core_viewport_scaling](core/core_viewport_scaling.c) |
| ⭐⭐☆☆ | 5.5 | 5.5 | [Agnis Aldiņš](https://github.com/nezvers) |
@@ -73,7 +73,7 @@ Examples using raylib [core](../src/rcore.c) module platform functionality: wind
| [core_text_file_loading](core/core_text_file_loading.c) |
| ⭐☆☆☆ | 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 [36]
+### category: shapes [38]
Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module.
@@ -115,8 +115,10 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes](
| [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) |
+| [shapes_ball_physics](shapes/shapes_ball_physics.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) |
+| [shapes_penrose_tile](shapes/shapes_penrose_tile.c) |
| ⭐⭐⭐⭐️ | 5.5 | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) |
-### category: textures [28]
+### category: textures [29]
Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/rtextures.c) module.
@@ -150,8 +152,9 @@ Examples using raylib textures functionality, including image/textures loading/g
| [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) |
+| [textures_cellular_automata](textures/textures_cellular_automata.c) |
| ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
-### category: text [15]
+### category: text [16]
Examples using raylib text functionality, including sprite fonts loading/generation and text drawing, provided by raylib [text](../src/rtext.c) module.
@@ -172,6 +175,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat
| [text_codepoints_loading](text/text_codepoints_loading.c) |
| ⭐⭐⭐☆ | 4.2 | 4.2 | [Ramon Santamaria](https://github.com/raysan5) |
| [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) |
+| [text_strings_management](text/text_strings_management.c) |
| ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [David Buzatto](https://github.com/davidbuzatto) |
### category: models [27]
@@ -207,7 +211,7 @@ Examples using raylib models functionality, including models loading/generation
| [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 [32]
+### category: shaders [33]
Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.c) module.
@@ -245,6 +249,7 @@ 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_game_of_life](shaders/shaders_game_of_life.c) |
| ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
### category: audio [9]
diff --git a/examples/core/core_2d_camera.c b/examples/core/core_2d_camera.c
index b752a9640..7e5a14a70 100644
--- a/examples/core/core_2d_camera.c
+++ b/examples/core/core_2d_camera.c
@@ -125,8 +125,8 @@ int main(void)
DrawRectangle( 10, 10, 250, 113, Fade(SKYBLUE, 0.5f));
DrawRectangleLines( 10, 10, 250, 113, BLUE);
- DrawText("Free 2d camera controls:", 20, 20, 10, BLACK);
- DrawText("- Right/Left to move Offset", 40, 40, 10, DARKGRAY);
+ DrawText("Free 2D camera controls:", 20, 20, 10, BLACK);
+ DrawText("- Right/Left to move player", 40, 40, 10, DARKGRAY);
DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, DARKGRAY);
DrawText("- A / S to Rotate", 40, 80, 10, DARKGRAY);
DrawText("- R to reset Zoom and Rotation", 40, 100, 10, DARKGRAY);
diff --git a/examples/core/core_2d_camera.png b/examples/core/core_2d_camera.png
index d2f9e634f..a0fdabb49 100644
Binary files a/examples/core/core_2d_camera.png and b/examples/core/core_2d_camera.png differ
diff --git a/examples/core/core_clipboard_text.c b/examples/core/core_clipboard_text.c
index 2f8e5712b..59de6509c 100644
--- a/examples/core/core_clipboard_text.c
+++ b/examples/core/core_clipboard_text.c
@@ -2,6 +2,8 @@
*
* raylib [core] example - clipboard text
*
+* Example complexity rating: [★★☆☆] 2/4
+*
* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
*
* Example contributed by Ananth S (@Ananth1839) and reviewed by Ramon Santamaria (@raysan5)
diff --git a/examples/core/core_high_dpi.c b/examples/core/core_highdpi_demo.c
similarity index 98%
rename from examples/core/core_high_dpi.c
rename to examples/core/core_highdpi_demo.c
index 312f0c3e2..b1f706d98 100644
--- a/examples/core/core_high_dpi.c
+++ b/examples/core/core_highdpi_demo.c
@@ -1,6 +1,6 @@
/*******************************************************************************************
*
-* raylib [core] example - high dpi
+* raylib [core] example - highdpi demo
*
* Example complexity rating: [★★☆☆] 2/4
*
@@ -33,7 +33,7 @@ int main(void)
const int screenHeight = 450;
SetConfigFlags(FLAG_WINDOW_HIGHDPI | FLAG_WINDOW_RESIZABLE);
- InitWindow(screenWidth, screenHeight, "raylib [core] example - high dpi");
+ InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi demo");
SetWindowMinSize(450, 450);
int logicalGridDescY = 120;
diff --git a/examples/core/core_high_dpi.png b/examples/core/core_highdpi_demo.png
similarity index 100%
rename from examples/core/core_high_dpi.png
rename to examples/core/core_highdpi_demo.png
diff --git a/examples/core/core_highdpi_testbed.c b/examples/core/core_highdpi_testbed.c
index a341d081c..6a036bbfc 100644
--- a/examples/core/core_highdpi_testbed.c
+++ b/examples/core/core_highdpi_testbed.c
@@ -30,6 +30,10 @@ int main(void)
SetConfigFlags(FLAG_WINDOW_HIGHDPI | FLAG_WINDOW_RESIZABLE);
InitWindow(screenWidth, screenHeight, "raylib [core] example - highdpi testbed");
+ Vector2 scaleDpi = GetWindowScaleDPI();
+ Vector2 mousePos = GetMousePosition();
+ int currentMonitor = GetCurrentMonitor();
+
int gridSpacing = 40; // Grid spacing in pixels
SetTargetFPS(60);
@@ -40,7 +44,11 @@ int main(void)
{
// Update
//----------------------------------------------------------------------------------
- // TODO: Update variables / Implement example logic at this point
+ mousePos = GetMousePosition();
+ currentMonitor = GetCurrentMonitor();
+ scaleDpi = GetWindowScaleDPI();
+
+ if (IsKeyPressed(KEY_SPACE)) ToggleBorderlessWindowed();
//----------------------------------------------------------------------------------
// Draw
@@ -50,11 +58,30 @@ int main(void)
ClearBackground(RAYWHITE);
// Draw grid
- for (int h = 0; h < 20; h++) DrawLine(0, h*gridSpacing, GetRenderWidth(), h*gridSpacing, LIGHTGRAY);
- for (int v = 0; v < 40; v++) DrawLine(v*gridSpacing, 0, v*gridSpacing, GetScreenHeight(), LIGHTGRAY);
+ for (int h = 0; h < 20; h++)
+ {
+ DrawText(TextFormat("%02i", h*gridSpacing), 4, h*gridSpacing - 4, 10, GRAY);
+ DrawLine(24, h*gridSpacing, GetScreenWidth(), h*gridSpacing, LIGHTGRAY);
+ }
+ for (int v = 0; v < 40; v++)
+ {
+ DrawText(TextFormat("%02i", v*gridSpacing), v*gridSpacing - 10, 4, 10, GRAY);
+ DrawLine(v*gridSpacing, 20, v*gridSpacing, GetScreenHeight(), LIGHTGRAY);
+ }
// Draw UI info
- DrawText(TextFormat("SCREEN SIZE: %ix%i", GetScreenWidth(), GetScreenHeight()), 10, 10, 20, BLACK);
+ DrawText(TextFormat("CURRENT MONITOR: %i/%i (%ix%i)", currentMonitor + 1, GetMonitorCount(),
+ GetMonitorWidth(currentMonitor), GetMonitorHeight(currentMonitor)), 50, 50, 20, DARKGRAY);
+ DrawText(TextFormat("SCREEN SIZE: %ix%i", GetScreenWidth(), GetScreenHeight()), 50, 90, 20, DARKGRAY);
+ DrawText(TextFormat("RENDER SIZE: %ix%i", GetRenderWidth(), GetRenderHeight()), 50, 130, 20, DARKGRAY);
+ DrawText(TextFormat("SCALE FACTOR: %.1fx%.1f", scaleDpi.x, scaleDpi.y), 50, 170, 20, GRAY);
+
+ // Draw mouse position
+ DrawCircleV(GetMousePosition(), 20, MAROON);
+ DrawRectangle(mousePos.x - 25, mousePos.y, 50, 2, BLACK);
+ DrawRectangle(mousePos.x, mousePos.y - 25, 2, 50, BLACK);
+ DrawText(TextFormat("[%i,%i]", GetMouseX(), GetMouseY()), mousePos.x - 44,
+ (mousePos.y > GetScreenHeight() - 60)? mousePos.y - 46 : mousePos.y + 30, 20, BLACK);
EndDrawing();
//----------------------------------------------------------------------------------
diff --git a/examples/core/core_window_flags.c b/examples/core/core_window_flags.c
index a8096eeb4..185e7f22c 100644
--- a/examples/core/core_window_flags.c
+++ b/examples/core/core_window_flags.c
@@ -43,7 +43,7 @@ int main(void)
*/
// Set configuration flags for window creation
- //SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT | FLAG_WINDOW_HIGHDPI);
+ //SetConfigFlags(FLAG_VSYNC_HINT | FLAG_MSAA_4X_HINT | FLAG_WINDOW_HIGHDPI);// | FLAG_WINDOW_TRANSPARENT);
InitWindow(screenWidth, screenHeight, "raylib [core] example - window flags");
Vector2 ballPosition = { GetScreenWidth()/2.0f, GetScreenHeight()/2.0f };
diff --git a/examples/examples_list.txt b/examples/examples_list.txt
index 605ddf263..3310cf2d2 100644
--- a/examples/examples_list.txt
+++ b/examples/examples_list.txt
@@ -43,7 +43,7 @@ core;core_custom_frame_control;★★★★;4.0;4.0;2021;2025;"Ramon Santamaria"
core;core_smooth_pixelperfect;★★★☆;3.7;4.0;2021;2025;"Giancamillo Alessandroni";@NotManyIdeasDev
core;core_random_sequence;★☆☆☆;5.0;5.0;2023;2025;"Dalton Overmyer";@REDl3east
core;core_automation_events;★★★☆;5.0;5.0;2023;2025;"Ramon Santamaria";@raysan5
-core;core_high_dpi;★★☆☆;5.0;5.5;2025;2025;"Jonathan Marler";@marler8997
+core;core_highdpi_demo;★★☆☆;5.0;5.5;2025;2025;"Jonathan Marler";@marler8997
core;core_render_texture;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
core;core_undo_redo;★★★☆;5.5;5.6;2025;2025;"Ramon Santamaria";@raysan5
core;core_viewport_scaling;★★☆☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers
@@ -51,7 +51,7 @@ core;core_input_actions;★★☆☆;5.5;5.6;2025;2025;"Jett";@JettMonstersGoBoo
core;core_directory_files;★☆☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal
core;core_highdpi_testbed;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
core;core_screen_recording;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
-core;core_clipboard_text;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ananth S";@Ananth1839
+core;core_clipboard_text;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ananth S";@Ananth1839
core;core_text_file_loading;★☆☆☆;5.5;5.6;0;0;"Aanjishnu Bhattacharyya";@NimComPoo-04
core;core_compute_hash;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ramon Santamaria";@raysan5
@@ -90,6 +90,8 @@ shapes;shapes_lines_drawing;★☆☆☆;5.6-dev;5.6;2025;2025;"Robin";@RobinsAv
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
+shapes;shapes_ball_physics;★★☆☆;5.6-dev;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto
+shapes;shapes_penrose_tile;★★★★;5.5;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto
textures;textures_logo_raylib;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5
textures;textures_srcrec_dstrec;★★★☆;1.3;1.3;2015;2025;"Ramon Santamaria";@raysan5
textures;textures_image_drawing;★★☆☆;1.4;1.4;2016;2025;"Ramon Santamaria";@raysan5
@@ -118,6 +120,7 @@ textures;textures_image_rotate;★★☆☆;1.0;1.0;2014;2025;"Ramon Santamaria"
textures;textures_screen_buffer;★★☆☆;5.5;5.5;2025;2025;"Agnis Aldiņš";@nezvers
textures;textures_textured_curve;★★★☆;4.5;4.5;2022;2025;"Jeffery Myers";@JeffM2501
textures;textures_sprite_stacking;★★☆☆;5.6-dev;6.0;2025;2025;"Robin";@RobinsAviary
+textures;textures_cellular_automata;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
text;text_sprite_fonts;★☆☆☆;1.7;3.7;2017;2025;"Ramon Santamaria";@raysan5
text;text_font_spritefont;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5
text;text_font_filters;★★☆☆;1.3;4.2;2015;2025;"Ramon Santamaria";@raysan5
@@ -133,6 +136,7 @@ text;text_3d_drawing;★★★★;3.5;4.0;2021;2025;"Vlad Adrian";@demizdor
text;text_codepoints_loading;★★★☆;4.2;4.2;2022;2025;"Ramon Santamaria";@raysan5
text;text_inline_styling;★★★☆;5.6-dev;5.6-dev;2025;2025;"Wagner Barongello";@SultansOfCode
text;text_words_alignment;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates
+text;text_strings_management;★★★☆;5.6-dev;5.6-dev;2025;2025;"David Buzatto";@davidbuzatto
models;models_animation_playing;★★☆☆;2.5;3.5;2019;2025;"Culacant";@culacant
models;models_billboard_rendering;★★★☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5
models;models_box_collisions;★☆☆☆;1.3;3.5;2015;2025;"Ramon Santamaria";@raysan5
@@ -192,6 +196,7 @@ shaders;shaders_basic_pbr;★★★★;5.0;5.5;2023;2025;"Afan OLOVCIC";@_DevDad
shaders;shaders_lightmap_rendering;★★★☆;4.5;4.5;2019;2025;"Jussi Viitala";@nullstare
shaders;shaders_rounded_rectangle;★★★☆;5.5;5.5;2025;2025;"Anstro Pleuton";@anstropleuton
shaders;shaders_depth_rendering;★★★☆;5.6-dev;5.6-dev;2025;2025;"Luís Almeida";@luis605
+shaders;shaders_game_of_life;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
audio;audio_module_playing;★☆☆☆;1.5;3.5;2016;2025;"Ramon Santamaria";@raysan5
audio;audio_music_stream;★☆☆☆;1.3;4.2;2015;2025;"Ramon Santamaria";@raysan5
audio;audio_raw_stream;★★★☆;1.6;4.2;2015;2025;"Ramon Santamaria";@raysan5
diff --git a/examples/shaders/resources/game_of_life/acorn.png b/examples/shaders/resources/game_of_life/acorn.png
new file mode 100644
index 000000000..58ea0b4d1
Binary files /dev/null and b/examples/shaders/resources/game_of_life/acorn.png differ
diff --git a/examples/shaders/resources/game_of_life/breeder.png b/examples/shaders/resources/game_of_life/breeder.png
new file mode 100644
index 000000000..88aa073d3
Binary files /dev/null and b/examples/shaders/resources/game_of_life/breeder.png differ
diff --git a/examples/shaders/resources/game_of_life/glider.png b/examples/shaders/resources/game_of_life/glider.png
new file mode 100644
index 000000000..921adb8ed
Binary files /dev/null and b/examples/shaders/resources/game_of_life/glider.png differ
diff --git a/examples/shaders/resources/game_of_life/glider_gun.png b/examples/shaders/resources/game_of_life/glider_gun.png
new file mode 100644
index 000000000..29b65d3de
Binary files /dev/null and b/examples/shaders/resources/game_of_life/glider_gun.png differ
diff --git a/examples/shaders/resources/game_of_life/oscillators.png b/examples/shaders/resources/game_of_life/oscillators.png
new file mode 100644
index 000000000..badd6a92d
Binary files /dev/null and b/examples/shaders/resources/game_of_life/oscillators.png differ
diff --git a/examples/shaders/resources/game_of_life/puffer_train.png b/examples/shaders/resources/game_of_life/puffer_train.png
new file mode 100644
index 000000000..8d77219b0
Binary files /dev/null and b/examples/shaders/resources/game_of_life/puffer_train.png differ
diff --git a/examples/shaders/resources/game_of_life/r_pentomino.png b/examples/shaders/resources/game_of_life/r_pentomino.png
new file mode 100644
index 000000000..1707f3c12
Binary files /dev/null and b/examples/shaders/resources/game_of_life/r_pentomino.png differ
diff --git a/examples/shaders/resources/game_of_life/spaceships.png b/examples/shaders/resources/game_of_life/spaceships.png
new file mode 100644
index 000000000..867f6fea3
Binary files /dev/null and b/examples/shaders/resources/game_of_life/spaceships.png differ
diff --git a/examples/shaders/resources/game_of_life/still_lifes.png b/examples/shaders/resources/game_of_life/still_lifes.png
new file mode 100644
index 000000000..ac184ac49
Binary files /dev/null and b/examples/shaders/resources/game_of_life/still_lifes.png differ
diff --git a/examples/shaders/resources/shaders/glsl100/game_of_life.fs b/examples/shaders/resources/shaders/glsl100/game_of_life.fs
new file mode 100644
index 000000000..70c12ac2c
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl100/game_of_life.fs
@@ -0,0 +1,44 @@
+#version 100
+
+precision highp float;
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+// Input size in pixels of the textures
+uniform vec2 resolution;
+
+void main()
+{
+ // Size of one pixel in texture coordinates (from 0.0 to 1.0)
+ float x = 1.0/resolution.x;
+ float y = 1.0/resolution.y;
+
+ // Status of the current cell (1 = alive, 0 = dead)
+ int origValue = (texture2D(texture0, fragTexCoord).r < 0.1)? 1 : 0;
+
+ // Sum of alive neighbors
+ int sumValue = (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right
+
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right
+
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right
+
+ // Game of life rules:
+ // Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise
+ // Current cell goes from dead to alive when exactly 3 neighbors are alive
+ if ((origValue == 1 && sumValue == 2) || sumValue == 3)
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black
+ else
+ gl_FragColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE
+}
diff --git a/examples/shaders/resources/shaders/glsl120/game_of_life.fs b/examples/shaders/resources/shaders/glsl120/game_of_life.fs
new file mode 100644
index 000000000..611f961bc
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl120/game_of_life.fs
@@ -0,0 +1,42 @@
+#version 120
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+// Input size in pixels of the textures
+uniform vec2 resolution;
+
+void main()
+{
+ // Size of one pixel in texture coordinates (from 0.0 to 1.0)
+ float x = 1.0/resolution.x;
+ float y = 1.0/resolution.y;
+
+ // Status of the current cell (1 = alive, 0 = dead)
+ int origValue = (texture2D(texture0, fragTexCoord).r < 0.1)? 1 : 0;
+
+ // Sum of alive neighbors
+ int sumValue = (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right
+
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right
+
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom
+ sumValue += (texture2D(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right
+
+ // Game of life rules:
+ // Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise
+ // Current cell goes from dead to alive when exactly 3 neighbors are alive
+ if (((origValue == 1) && (sumValue == 2)) || sumValue == 3)
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black
+ else
+ gl_FragColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE
+}
diff --git a/examples/shaders/resources/shaders/glsl330/game_of_life.fs b/examples/shaders/resources/shaders/glsl330/game_of_life.fs
new file mode 100644
index 000000000..cc80861d6
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl330/game_of_life.fs
@@ -0,0 +1,45 @@
+#version 330
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+// Output fragment color
+out vec4 finalColor;
+
+// Input size in pixels of the textures
+uniform vec2 resolution;
+
+void main()
+{
+ // Size of one pixel in texture coordinates (from 0.0 to 1.0)
+ float x = 1.0/resolution.x;
+ float y = 1.0/resolution.y;
+
+ // Status of the current cell (1 = alive, 0 = dead)
+ int origValue = (texture(texture0, fragTexCoord).r < 0.1)? 1 : 0;
+
+ // Sum of alive neighbors
+ int sumValue = (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Top-left
+ sumValue += (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Top
+ sumValue += (texture(texture0, vec2(fragTexCoord.x - x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Top-right
+
+ sumValue += (texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Left
+ sumValue += (texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Right
+
+ sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y - y)).r < 0.1)? 1 : 0; // Bottom-left
+ sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y )).r < 0.1)? 1 : 0; // Bottom
+ sumValue += (texture(texture0, vec2(fragTexCoord.x + x, fragTexCoord.y + y)).r < 0.1)? 1 : 0; // Bottom-right
+
+ // Game of life rules:
+ // Current cell remains alive when 2 or 3 neighbors are alive, dies otherwise
+ // Current cell goes from dead to alive when exactly 3 neighbors are alive
+ if (((origValue == 1) && (sumValue == 2)) || sumValue == 3)
+ finalColor = vec4(0.0, 0.0, 0.0, 255.0); // Alive: draw the pixel black
+ else
+ finalColor = fragColor; // Dead: draw the pixel with the background color, RAYWHITE
+}
diff --git a/examples/shaders/shaders_game_of_life.c b/examples/shaders/shaders_game_of_life.c
new file mode 100644
index 000000000..9b9242a0d
--- /dev/null
+++ b/examples/shaders/shaders_game_of_life.c
@@ -0,0 +1,353 @@
+/*******************************************************************************************
+*
+* raylib [shaders] example - game of life
+*
+* Example complexity rating: [★★★☆] 3/4
+*
+* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
+* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
+*
+* Example originally created with raylib 5.6, last time updated with raylib 5.6
+*
+* Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 Jordi Santonja (@JordSant)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h" // Required for GUI controls
+
+#if defined(PLATFORM_DESKTOP)
+ #define GLSL_VERSION 330
+#else // PLATFORM_ANDROID, PLATFORM_WEB
+ #define GLSL_VERSION 100
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Interaction mode
+typedef enum {
+ MODE_RUN = 0,
+ MODE_PAUSE,
+ MODE_DRAW,
+} InteractionMode;
+
+// Struct to store example preset patterns
+typedef struct {
+ char *name;
+ Vector2 position;
+} PresetPattern;
+
+//----------------------------------------------------------------------------------
+// Functions declaration
+//----------------------------------------------------------------------------------
+void FreeImageToDraw(Image **imageToDraw);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [shaders] example - game of life");
+
+ const int menuWidth = 100;
+ const int windowWidth = screenWidth - menuWidth;
+ const int windowHeight = screenHeight;
+
+ const int worldWidth = 2048;
+ const int worldHeight = 2048;
+
+ const int randomTiles = 8; // Random preset: divide the world to compute random points in each tile
+
+ const Rectangle worldRectSource = { 0, 0, (float)worldWidth, (float)-worldHeight };
+ const Rectangle worldRectDest = { 0, 0, (float)worldWidth, (float)worldHeight };
+ const Rectangle textureOnScreen = { 0, 0, (float)windowWidth, (float)windowHeight };
+
+ const PresetPattern presetPatterns[] = {
+ { "Glider", { 0.5f, 0.5f } }, { "R-pentomino", { 0.5f, 0.5f } }, { "Acorn", { 0.5f,0.5f } },
+ { "Spaceships", { 0.1f, 0.5f } }, { "Still lifes", { 0.5f, 0.5f } }, { "Oscillators", { 0.5f, 0.5f } },
+ { "Puffer train", { 0.1f, 0.5f } }, { "Glider Gun", { 0.2f, 0.2f } }, { "Breeder", { 0.1f, 0.5f } },
+ { "Random", { 0.5f, 0.5f } }
+ };
+
+ const int numberOfPresets = sizeof(presetPatterns)/sizeof(presetPatterns[0]);
+
+ int zoom = 1;
+ float offsetX = (worldWidth - windowWidth)/2.0f; // Centered on window
+ float offsetY = (worldHeight - windowHeight)/2.0f; // Centered on window
+ int framesPerStep = 1;
+ int frame = 0;
+
+ int preset = -1; // No button pressed for preset
+ int mode = MODE_RUN; // Starting mode: running
+ bool buttonZoomIn = false; // Button states: false not pressed
+ bool buttonZomOut = false;
+ bool buttonFaster = false;
+ bool buttonSlower = false;
+
+ // Load shader
+ Shader shdrGameOfLife = LoadShader(0, TextFormat("resources/shaders/glsl%i/game_of_life.fs", GLSL_VERSION));
+
+ // Set shader uniform size of the world
+ int resolutionLoc = GetShaderLocation(shdrGameOfLife, "resolution");
+ const float resolution[2] = { (float)worldWidth, (float)worldHeight };
+ SetShaderValue(shdrGameOfLife, resolutionLoc, resolution, SHADER_UNIFORM_VEC2);
+
+ // Define two textures: the current world and the previous world
+ RenderTexture2D world1 = LoadRenderTexture(worldWidth, worldHeight);
+ RenderTexture2D world2 = LoadRenderTexture(worldWidth, worldHeight);
+ BeginTextureMode(world2);
+ ClearBackground(RAYWHITE);
+ EndTextureMode();
+
+ Image startPattern = LoadImage("resources/game_of_life/r_pentomino.png");
+ UpdateTextureRec(world2.texture, (Rectangle){ worldWidth/2.0f, worldHeight/2.0f, (float)(startPattern.width), (float)(startPattern.height) }, startPattern.data);
+ UnloadImage(startPattern);
+
+ // Pointers to the two textures, to be swapped
+ RenderTexture2D *currentWorld = &world2;
+ RenderTexture2D *previousWorld = &world1;
+
+ // Image to be used in DRAW mode, to be changed with mouse input
+ Image *imageToDraw = NULL;
+
+ SetTargetFPS(60); // Set at 60 frames-per-second
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ frame++;
+
+ // Change zoom: both by buttons or by mouse wheel
+ float mouseWheelMove = GetMouseWheelMove();
+ if (buttonZoomIn || (buttonZomOut && (zoom > 1)) || (mouseWheelMove != 0.0f))
+ {
+ FreeImageToDraw(&imageToDraw); // Zoom change: free the image to draw to be recreated again
+
+ const float centerX = offsetX + (windowWidth/2.0f)/zoom;
+ const float centerY = offsetY + (windowHeight/2.0f)/zoom;
+ if (buttonZoomIn || (mouseWheelMove > 0.0f)) zoom *= 2;
+ if ((buttonZomOut || (mouseWheelMove < 0.0f)) && (zoom > 1)) zoom /= 2;
+ offsetX = centerX - (windowWidth/2.0f)/zoom;
+ offsetY = centerY - (windowHeight/2.0f)/zoom;
+ }
+
+ // Change speed: number of frames per step
+ if (buttonFaster && framesPerStep > 1) framesPerStep--;
+ if (buttonSlower) framesPerStep++;
+
+ // Mouse management
+ if ((mode == MODE_RUN) || (mode == MODE_PAUSE))
+ {
+ FreeImageToDraw(&imageToDraw); // Free the image to draw: no longer needed in these modes
+
+ // Pan with mouse left button
+ static Vector2 previousMousePosition = { 0.0f, 0.0f };
+ const Vector2 mousePosition = GetMousePosition();
+ if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && (mousePosition.x < windowWidth))
+ {
+ offsetX -= (mousePosition.x - previousMousePosition.x)/zoom;
+ offsetY -= (mousePosition.y - previousMousePosition.y)/zoom;
+ }
+ previousMousePosition = mousePosition;
+ }
+ else // MODE_DRAW
+ {
+ const float offsetDecimalX = offsetX - floorf(offsetX);
+ const float offsetDecimalY = offsetY - floorf(offsetY);
+ int sizeInWorldX = (int)(ceilf((float)(windowWidth + offsetDecimalX*zoom)/zoom));
+ int sizeInWorldY = (int)(ceilf((float)(windowHeight + offsetDecimalY*zoom)/zoom));
+ if (offsetX + sizeInWorldX >= worldWidth) sizeInWorldX = worldWidth - (int)floorf(offsetX);
+ if (offsetY + sizeInWorldY >= worldHeight) sizeInWorldY = worldHeight - (int)floorf(offsetY);
+
+ // Create image to draw if not created yet
+ if (imageToDraw == NULL)
+ {
+ RenderTexture2D worldOnScreen = LoadRenderTexture(sizeInWorldX, sizeInWorldY);
+ BeginTextureMode(worldOnScreen);
+ DrawTexturePro(currentWorld->texture, (Rectangle) { floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), -(float)(sizeInWorldY) },
+ (Rectangle) { 0, 0, (float)(sizeInWorldX), (float)(sizeInWorldY) }, (Vector2) { 0, 0 }, 0.0f, WHITE);
+ EndTextureMode();
+ imageToDraw = (Image*)RL_MALLOC(sizeof(Image));
+ *imageToDraw = LoadImageFromTexture(worldOnScreen.texture);
+
+ UnloadRenderTexture(worldOnScreen);
+ }
+
+ const Vector2 mousePosition = GetMousePosition();
+ static int firstColor = -1;
+ if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && (mousePosition.x < windowWidth))
+ {
+ int mouseX = (int)(mousePosition.x + offsetDecimalX*zoom)/zoom;
+ int mouseY = (int)(mousePosition.y + offsetDecimalY*zoom)/zoom;
+ if (mouseX >= sizeInWorldX) mouseX = sizeInWorldX - 1;
+ if (mouseY >= sizeInWorldY) mouseY = sizeInWorldY - 1;
+ if (firstColor == -1) firstColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1;
+ const int prevColor = (GetImageColor(*imageToDraw, mouseX, mouseY).r < 5)? 0 : 1;
+
+ ImageDrawPixel(imageToDraw, mouseX, mouseY, (firstColor) ? BLACK : RAYWHITE);
+
+ if (prevColor != firstColor) UpdateTextureRec(currentWorld->texture, (Rectangle){ floorf(offsetX), floorf(offsetY), (float)(sizeInWorldX), (float)(sizeInWorldY) }, imageToDraw->data);
+ }
+ else firstColor = -1;
+ }
+
+ // Load selected preset
+ if (preset >= 0)
+ {
+ Image pattern;
+ if (preset < numberOfPresets - 1) // Preset with pattern image lo load
+ {
+ switch (preset)
+ {
+ case 0: pattern = LoadImage("resources/game_of_life/glider.png"); break;
+ case 1: pattern = LoadImage("resources/game_of_life/r_pentomino.png"); break;
+ case 2: pattern = LoadImage("resources/game_of_life/acorn.png"); break;
+ case 3: pattern = LoadImage("resources/game_of_life/spaceships.png"); break;
+ case 4: pattern = LoadImage("resources/game_of_life/still_lifes.png"); break;
+ case 5: pattern = LoadImage("resources/game_of_life/oscillators.png"); break;
+ case 6: pattern = LoadImage("resources/game_of_life/puffer_train.png"); break;
+ case 7: pattern = LoadImage("resources/game_of_life/glider_gun.png"); break;
+ case 8: pattern = LoadImage("resources/game_of_life/breeder.png"); break;
+ }
+ BeginTextureMode(*currentWorld);
+ ClearBackground(RAYWHITE);
+ EndTextureMode();
+
+ UpdateTextureRec(currentWorld->texture, (Rectangle){ worldWidth*presetPatterns[preset].position.x - pattern.width/2.0f,
+ worldHeight*presetPatterns[preset].position.y - pattern.height/2.0f,
+ (float)(pattern.width), (float)(pattern.height) }, pattern.data);
+ }
+ else // Last preset: Random values
+ {
+ pattern = GenImageColor(worldWidth/randomTiles, worldHeight/randomTiles, RAYWHITE);
+ for (int i = 0; i < randomTiles; i++)
+ {
+ for (int j = 0; j < randomTiles; j++)
+ {
+ ImageClearBackground(&pattern, RAYWHITE);
+ for (int x = 0; x < pattern.width; x++)
+ {
+ for (int y = 0; y < pattern.height; y++)
+ {
+ if (GetRandomValue(0, 100) < 15) ImageDrawPixel(&pattern, x, y, BLACK);
+ }
+ }
+ UpdateTextureRec(currentWorld->texture,
+ (Rectangle){ (float)(pattern.width*i), (float)(pattern.height*j),
+ (float)(pattern.width), (float)(pattern.height) }, pattern.data);
+ }
+ }
+ }
+
+ UnloadImage(pattern);
+
+ mode = MODE_PAUSE;
+ offsetX = worldWidth*presetPatterns[preset].position.x - windowWidth/zoom/2.0f;
+ offsetY = worldHeight*presetPatterns[preset].position.y - windowHeight/zoom/2.0f;
+ }
+
+ // Check window draw inside world limits
+ if (offsetX < 0) offsetX = 0;
+ if (offsetY < 0) offsetY = 0;
+ if (offsetX > worldWidth - (float)(windowWidth)/zoom) offsetX = worldWidth - (float)(windowWidth)/zoom;
+ if (offsetY > worldHeight - (float)(windowHeight)/zoom) offsetY = worldHeight - (float)(windowHeight)/zoom;
+
+ // Rectangles for drawing texture portion to screen
+ const Rectangle textureSourceToScreen = { offsetX, offsetY, (float)windowWidth/zoom, (float)windowHeight/zoom };
+ //----------------------------------------------------------------------------------
+
+ // Draw to texture
+ //----------------------------------------------------------------------------------
+ if ((mode == MODE_RUN) && ((frame%framesPerStep) == 0))
+ {
+ // Swap worlds
+ RenderTexture2D *tempWorld = currentWorld;
+ currentWorld = previousWorld;
+ previousWorld = tempWorld;
+
+ // Draw to texture
+ BeginTextureMode(*currentWorld);
+ BeginShaderMode(shdrGameOfLife);
+ DrawTexturePro(previousWorld->texture, worldRectSource, worldRectDest, (Vector2){ 0, 0 }, 0.0f, RAYWHITE);
+ EndShaderMode();
+ EndTextureMode();
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw to screen
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ DrawTexturePro(currentWorld->texture, textureSourceToScreen, textureOnScreen, (Vector2){ 0, 0 }, 0.0f, WHITE);
+
+ DrawLine(windowWidth, 0, windowWidth, screenHeight, (Color){ 218, 218, 218, 255 });
+ DrawRectangle(windowWidth, 0, screenWidth - windowWidth, screenHeight, (Color){ 232, 232, 232, 255 });
+
+ DrawText("Conway's", 704, 4, 20, DARKBLUE);
+ DrawText(" game of", 704, 19, 20, DARKBLUE);
+ DrawText(" life", 708, 34, 20, DARKBLUE);
+ DrawText("in raylib", 757, 42, 6, BLACK);
+
+ DrawText("Presets", 710, 58, 8, GRAY);
+ preset = -1;
+ for (int i = 0; i < numberOfPresets; i++)
+ if (GuiButton((Rectangle){ 710.0f, 70.0f + 18*i, 80.0f, 16.0f }, presetPatterns[i].name)) preset = i;
+
+ GuiToggleGroup((Rectangle){ 710, 258, 80, 16 }, "Run\nPause\nDraw", &mode);
+
+ DrawText(TextFormat("Zoom: %ix", zoom), 710, 316, 8, GRAY);
+ buttonZoomIn = GuiButton((Rectangle){ 710, 328, 80, 16 }, "Zoom in");
+ buttonZomOut = GuiButton((Rectangle){ 710, 346, 80, 16 }, "Zoom out");
+
+ DrawText(TextFormat("Speed: %i frame%s", framesPerStep, (framesPerStep > 1)? "s" : ""), 710, 370, 8, GRAY);
+ buttonFaster = GuiButton((Rectangle){ 710, 382, 80, 16 }, "Faster");
+ buttonSlower = GuiButton((Rectangle){ 710, 400, 80, 16 }, "Slower");
+
+ DrawFPS(712, 426);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadShader(shdrGameOfLife);
+ UnloadRenderTexture(world1);
+ UnloadRenderTexture(world2);
+
+ FreeImageToDraw(&imageToDraw);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Functions definition
+//----------------------------------------------------------------------------------
+void FreeImageToDraw(Image **imageToDraw)
+{
+ if (*imageToDraw != NULL)
+ {
+ UnloadImage(**imageToDraw);
+ RL_FREE(*imageToDraw);
+ *imageToDraw = NULL;
+ }
+}
diff --git a/examples/shaders/shaders_game_of_life.png b/examples/shaders/shaders_game_of_life.png
new file mode 100644
index 000000000..8ebc2c12e
Binary files /dev/null and b/examples/shaders/shaders_game_of_life.png differ
diff --git a/examples/shapes/shapes_ball_physics.c b/examples/shapes/shapes_ball_physics.c
new file mode 100644
index 000000000..f9b620d28
--- /dev/null
+++ b/examples/shapes/shapes_ball_physics.c
@@ -0,0 +1,221 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - ball physics
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*
+* Example contributed by David Buzatto (@davidbuzatto) 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 David Buzatto (@davidbuzatto)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include
+#include
+
+#define MAX_BALLS 5000 // Maximum quantity of balls
+
+typedef struct Ball {
+ Vector2 pos; // Position
+ Vector2 vel; // Velocity
+ Vector2 ppos; // Previous position
+ float radius;
+ float friction;
+ float elasticity;
+ Color color;
+ bool grabbed;
+} Ball;
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - ball physics");
+
+ Ball balls[MAX_BALLS] = {{
+ .pos = { GetScreenWidth()/2, GetScreenHeight()/2 },
+ .vel = { 200, 200 },
+ .ppos = { 0 },
+ .radius = 40,
+ .friction = 0.99,
+ .elasticity = 0.9,
+ .color = BLUE,
+ .grabbed = false
+ }};
+
+ int ballCount = 1;
+ Ball *grabbedBall = NULL; // A pointer to the current ball that is grabbed
+ Vector2 pressOffset = {0}; // Mouse press offset relative to the ball that grabbedd
+
+ float gravity = 100; // World gravity
+
+ 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 delta = GetFrameTime();
+ Vector2 mousePos = GetMousePosition();
+
+ // Checks if a ball was grabbed
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
+ {
+ for (int i = ballCount - 1; i >= 0; i--)
+ {
+ Ball *ball = &balls[i];
+ pressOffset.x = mousePos.x - ball->pos.x;
+ pressOffset.y = mousePos.y - ball->pos.y;
+
+ // If the distance between the ball position and the mouse press position
+ // is less than or equal to the ball radius, the event occurred inside the ball
+ if (hypot(pressOffset.x, pressOffset.y) <= ball->radius)
+ {
+ ball->grabbed = true;
+ grabbedBall = ball;
+ break;
+ }
+ }
+ }
+
+ // Releases any ball the was grabbed
+ if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT))
+ {
+ if (grabbedBall != NULL)
+ {
+ grabbedBall->grabbed = false;
+ grabbedBall = NULL;
+ }
+ }
+
+ // Creates a new ball
+ if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT) || (IsKeyDown(KEY_LEFT_CONTROL) && IsMouseButtonDown(MOUSE_BUTTON_RIGHT)))
+ {
+ if (ballCount < MAX_BALLS)
+ {
+ balls[ballCount++] = (Ball){
+ .pos = mousePos,
+ .vel = { GetRandomValue(-300, 300), GetRandomValue(-300, 300) },
+ .ppos = { 0 },
+ .radius = 20 + GetRandomValue(0, 30),
+ .friction = 0.99,
+ .elasticity = 0.9,
+ .color = { GetRandomValue(0, 255), GetRandomValue(0, 255), GetRandomValue(0, 255), 255 },
+ .grabbed = false
+ };
+ }
+ }
+
+ // Shake balls
+ if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))
+ {
+ for (int i = 0; i < ballCount; i++)
+ {
+ if (!balls[i].grabbed) balls[i].vel = (Vector2){ GetRandomValue(-2000, 2000), GetRandomValue(-2000, 2000) };
+ }
+ }
+
+ // Changes gravity
+ gravity += GetMouseWheelMove()*5;
+
+ // Updates each ball state
+ for (int i = 0; i < ballCount; i++)
+ {
+ Ball *ball = &balls[i];
+
+ // The ball is not grabbed
+ if (!ball->grabbed)
+ {
+ // Ball repositioning using the velocity
+ ball->pos.x += ball->vel.x * delta;
+ ball->pos.y += ball->vel.y * delta;
+
+ // Does the ball hit the screen right boundary?
+ if ((ball->pos.x + ball->radius) >= screenWidth)
+ {
+ ball->pos.x = screenWidth - ball->radius; // Ball repositioning
+ ball->vel.x = -ball->vel.x*ball->elasticity; // Elasticity makes the ball lose 10% of its velocity on hit
+ }
+ // Does the ball hit the screen left boundary?
+ else if ((ball->pos.x - ball->radius) <= 0)
+ {
+ ball->pos.x = ball->radius;
+ ball->vel.x = -ball->vel.x*ball->elasticity;
+ }
+
+ // The same for y axis
+ if ((ball->pos.y + ball->radius) >= screenHeight)
+ {
+ ball->pos.y = screenHeight - ball->radius;
+ ball->vel.y = -ball->vel.y*ball->elasticity;
+ }
+ else if ((ball->pos.y - ball->radius) <= 0)
+ {
+ ball->pos.y = ball->radius;
+ ball->vel.y = -ball->vel.y*ball->elasticity;
+ }
+
+ // Friction makes the ball lose 1% of its velocity each frame
+ ball->vel.x = ball->vel.x*ball->friction;
+ // Gravity affects only the y axis
+ ball->vel.y = ball->vel.y*ball->friction + gravity;
+ }
+ else
+ {
+ // Ball repositioning using the mouse position
+ ball->pos.x = mousePos.x - pressOffset.x;
+ ball->pos.y = mousePos.y - pressOffset.y;
+
+ // While the ball is grabbed, recalculates its velocity
+ ball->vel.x = (ball->pos.x - ball->ppos.x)/delta;
+ ball->vel.y = (ball->pos.y - ball->ppos.y)/delta;
+ ball->ppos = ball->pos;
+ }
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ for (int i = 0; i < ballCount; i++)
+ {
+ DrawCircleV(balls[i].pos, balls[i].radius, balls[i].color);
+ DrawCircleLinesV(balls[i].pos, balls[i].radius, BLACK);
+ }
+
+ DrawText("grab a ball by pressing with the mouse and throw it by releasing", 10, 10, 10, DARKGRAY);
+ DrawText("right click to create new balls (keep left control pressed to create a lot)", 10, 30, 10, DARKGRAY);
+ DrawText("use mouse wheel to change gravity", 10, 50, 10, DARKGRAY);
+ DrawText("middle click to shake", 10, 70, 10, DARKGRAY);
+ DrawText(TextFormat("BALL COUNT: %d", ballCount), 10, GetScreenHeight() - 70, 20, BLACK);
+ DrawText(TextFormat("GRAVITY: %.2f", gravity), 10, GetScreenHeight() - 40, 20, BLACK);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/shapes/shapes_ball_physics.png b/examples/shapes/shapes_ball_physics.png
new file mode 100644
index 000000000..89493275c
Binary files /dev/null and b/examples/shapes/shapes_ball_physics.png differ
diff --git a/examples/shapes/shapes_double_pendulum.c b/examples/shapes/shapes_double_pendulum.c
index cbf487f93..760d66203 100644
--- a/examples/shapes/shapes_double_pendulum.c
+++ b/examples/shapes/shapes_double_pendulum.c
@@ -42,7 +42,7 @@ int main(void)
SetConfigFlags(FLAG_WINDOW_HIGHDPI);
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - double pendulum");
- // Simulation Paramters
+ // Simulation Parameters
float l1 = 15.0f, m1 = 0.2f, theta1 = DEG2RAD*170, w1 = 0;
float l2 = 15.0f, m2 = 0.1f, theta2 = DEG2RAD*0, w2 = 0;
float lengthScaler = 0.1f;
diff --git a/examples/shapes/shapes_penrose_tile.c b/examples/shapes/shapes_penrose_tile.c
new file mode 100644
index 000000000..304dca3cc
--- /dev/null
+++ b/examples/shapes/shapes_penrose_tile.c
@@ -0,0 +1,271 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - penrose tile
+*
+* Example complexity rating: [★★★★] 4/4
+*
+* Example originally created with raylib 5.5, last time updated with raylib 5.6-dev
+* Based on: https://processing.org/examples/penrosetile.html
+*
+* Example contributed by David Buzatto (@davidbuzatto) and reviewed by Ramon Santamaria (@raysan5)
+*
+* 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 David Buzatto (@davidbuzatto)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include
+#include
+#include
+
+#define STR_MAX_SIZE 10000
+#define TURTLE_STACK_MAX_SIZE 50
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct TurtleState {
+ Vector2 origin;
+ double angle;
+} TurtleState;
+
+typedef struct PenroseLSystem {
+ int steps;
+ char *production;
+ const char *ruleW;
+ const char *ruleX;
+ const char *ruleY;
+ const char *ruleZ;
+ float drawLength;
+ float theta;
+} PenroseLSystem;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+static TurtleState turtleStack[TURTLE_STACK_MAX_SIZE];
+static int turtleTop = -1;
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+static void PushTurtleState(TurtleState state);
+static TurtleState PopTurtleState(void);
+static PenroseLSystem CreatePenroseLSystem(float drawLength);
+static void BuildProductionStep(PenroseLSystem *ls);
+static void DrawPenroseLSystem(PenroseLSystem *ls);
+
+//------------------------------------------------------------------------------------
+// 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 - penrose tile");
+
+ float drawLength = 460.0f;
+ int minGenerations = 0;
+ int maxGenerations = 4;
+ int generations = 0;
+
+ // Initializee new penrose tile
+ PenroseLSystem ls = CreatePenroseLSystem(drawLength*(generations/(float)maxGenerations));
+ for (int i = 0; i < generations; i++) BuildProductionStep(&ls);
+
+ SetTargetFPS(120); // Set our game to run at 120 frames-per-second
+ //---------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ bool rebuild = false;
+ if (IsKeyPressed(KEY_UP))
+ {
+ if (generations < maxGenerations)
+ {
+ generations++;
+ rebuild = true;
+ }
+ }
+ else if (IsKeyPressed(KEY_DOWN))
+ {
+ if (generations > minGenerations)
+ {
+ generations--;
+ if (generations > 0) rebuild = true;
+ }
+ }
+
+ if (rebuild)
+ {
+ RL_FREE(ls.production); // Free previous production for re-creation
+ ls = CreatePenroseLSystem(drawLength*(generations/(float)maxGenerations));
+ for (int i = 0; i < generations; i++) BuildProductionStep(&ls);
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground( RAYWHITE );
+
+ if (generations > 0) DrawPenroseLSystem(&ls);
+
+ DrawText("penrose l-system", 10, 10, 20, DARKGRAY);
+ DrawText("press up or down to change generations", 10, 30, 20, DARKGRAY);
+ DrawText(TextFormat("generations: %d", generations), 10, 50, 20, DARKGRAY);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+// Push turtle state for next step
+static void PushTurtleState(TurtleState state)
+{
+ if (turtleTop < (TURTLE_STACK_MAX_SIZE - 1)) turtleStack[++turtleTop] = state;
+ else TraceLog(LOG_WARNING, "TURTLE STACK OVERFLOW!");
+}
+
+// Pop turtle state step
+static TurtleState PopTurtleState(void)
+{
+ if (turtleTop >= 0) return turtleStack[turtleTop--];
+ else TraceLog(LOG_WARNING, "TURTLE STACK UNDERFLOW!");
+
+ return (TurtleState){ 0 };
+}
+
+// Create a new penrose tile structure
+static PenroseLSystem CreatePenroseLSystem(float drawLength)
+{
+ // TODO: Review constant values assignment on recreation?
+ PenroseLSystem ls = {
+ .steps = 0,
+ .ruleW = "YF++ZF4-XF[-YF4-WF]++",
+ .ruleX = "+YF--ZF[3-WF--XF]+",
+ .ruleY = "-WF++XF[+++YF++ZF]-",
+ .ruleZ = "--YF++++WF[+ZF++++XF]--XF",
+ .drawLength = drawLength,
+ .theta = 36.0f // Degrees
+ };
+
+ ls.production = (char *)RL_MALLOC(sizeof(char)*STR_MAX_SIZE);
+ ls.production[0] = '\0';
+ strncpy(ls.production, "[X]++[X]++[X]++[X]++[X]", STR_MAX_SIZE);
+
+ return ls;
+}
+
+// Build next penrose step
+static void BuildProductionStep(PenroseLSystem *ls)
+{
+ char *newProduction = (char *)RL_MALLOC(sizeof(char)*STR_MAX_SIZE);
+ newProduction[0] = '\0';
+
+ int productionLength = strnlen(ls->production, STR_MAX_SIZE);
+
+ for (int i = 0; i < productionLength; i++)
+ {
+ char step = ls->production[i];
+ int remainingSpace = STR_MAX_SIZE - strnlen(newProduction, STR_MAX_SIZE) - 1;
+ switch (step)
+ {
+ case 'W': strncat(newProduction, ls->ruleW, remainingSpace); break;
+ case 'X': strncat(newProduction, ls->ruleX, remainingSpace); break;
+ case 'Y': strncat(newProduction, ls->ruleY, remainingSpace); break;
+ case 'Z': strncat(newProduction, ls->ruleZ, remainingSpace); break;
+ default:
+ {
+ if (step != 'F')
+ {
+ int t = strnlen(newProduction, STR_MAX_SIZE);
+ newProduction[t] = step;
+ newProduction[t + 1] = '\0';
+ }
+ } break;
+ }
+ }
+
+ ls->drawLength *= 0.5f;
+ strncpy(ls->production, newProduction, STR_MAX_SIZE);
+
+ RL_FREE(newProduction);
+}
+
+// Draw penrose tile lines
+static void DrawPenroseLSystem(PenroseLSystem *ls)
+{
+ Vector2 screenCenter = { GetScreenWidth()/2, GetScreenHeight()/2 };
+
+ TurtleState turtle = {
+ .origin = { 0 },
+ .angle = -90.0f
+ };
+
+ int repeats = 1;
+ int productionLength = (int)strnlen(ls->production, STR_MAX_SIZE);
+ ls->steps += 12;
+
+ if (ls->steps > productionLength) ls->steps = productionLength;
+
+ for (int i = 0; i < ls->steps; i++)
+ {
+ char step = ls->production[i];
+ if (step == 'F')
+ {
+ for (int j = 0; j < repeats; j++)
+ {
+ Vector2 startPosWorld = turtle.origin;
+ float radAngle = DEG2RAD*turtle.angle;
+ turtle.origin.x += ls->drawLength*cosf(radAngle);
+ turtle.origin.y += ls->drawLength*sinf(radAngle);
+ Vector2 startPosScreen = { startPosWorld.x + screenCenter.x, startPosWorld.y + screenCenter.y };
+ Vector2 endPosScreen = { turtle.origin.x + screenCenter.x, turtle.origin.y + screenCenter.y };
+
+ DrawLineEx(startPosScreen, endPosScreen, 2, Fade(BLACK, 0.2));
+ }
+
+ repeats = 1;
+ }
+ else if (step == '+')
+ {
+ for (int j = 0; j < repeats; j++) turtle.angle += ls->theta;
+
+ repeats = 1;
+ }
+ else if (step == '-')
+ {
+ for (int j = 0; j < repeats; j++) turtle.angle += -ls->theta;
+
+ repeats = 1;
+ }
+ else if (step == '[') PushTurtleState(turtle);
+ else if (step == ']') turtle = PopTurtleState();
+ else if ((step >= 48) && (step <= 57)) repeats = (int) step - 48;
+ }
+
+ turtleTop = -1;
+}
diff --git a/examples/shapes/shapes_penrose_tile.png b/examples/shapes/shapes_penrose_tile.png
new file mode 100644
index 000000000..dffc35cc4
Binary files /dev/null and b/examples/shapes/shapes_penrose_tile.png differ
diff --git a/examples/text/resources/LICENSE.md b/examples/text/resources/LICENSE.md
index 506a4aaf0..91fd618fd 100644
--- a/examples/text/resources/LICENSE.md
+++ b/examples/text/resources/LICENSE.md
@@ -8,13 +8,15 @@
| fonts/mecha.png | Captain Falcon | [Freeware](https://www.dafont.com/es/mecha-cf.font) | Atlas created by [@raysan5](https://github.com/raysan5) |
| fonts/pixelplay.png | Aleksander Shevchuk | [Freeware](https://www.dafont.com/es/pixelplay.font) | Atlas created by [@raysan5](https://github.com/raysan5) |
| fonts/pixantiqua.ttf | Gerhard Großmann | [Freeware](https://www.dafont.com/es/pixantiqua.font) | Atlas created by [@raysan5](https://github.com/raysan5) |
-| anonymous_pro_bold.ttf | [Mark Simonson](https://fonts.google.com/specimen/Anonymous+Pro) | [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) | - |
+| anonymous_pro_bold.ttf | [Mark Simonson](https://fonts.google.com/specimen/Anonymous+Pro) | [SIL Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) | - |
| custom_alagard.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) |
| 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) |
| custom_mecha.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) |
| dejavu.fnt, dejavu.png | [DejaVu Fonts](https://dejavu-fonts.github.io/) | [Free](https://dejavu-fonts.github.io/License.html) | Atlas made with [BMFont](https://www.angelcode.com/products/bmfont/) 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 |
-| noto_cjk.fnt, noto_cjk.png | [Google Fonts](https://www.google.com/get/noto/help/cjk/) | [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) | Atlas made with [BMFont](https://www.angelcode.com/products/bmfont/) by [@raysan5](https://github.com/raysan5) |
+| noto_cjk.fnt, noto_cjk.png | [Google Fonts](https://www.google.com/get/noto/help/cjk/) | [SIL Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) | Atlas made with [BMFont](https://www.angelcode.com/products/bmfont/) by [@raysan5](https://github.com/raysan5) |
| pixantiqua.fnt, pixantiqua.png | Gerhard Großmann | [Freeware](https://www.dafont.com/es/pixantiqua.font) | Atlas made with [BMFont](https://www.angelcode.com/products/bmfont/) by [@raysan5](https://github.com/raysan5) |
| pixantiqua.ttf | Gerhard Großmann | [Freeware](https://www.dafont.com/es/pixantiqua.font) | - |
| symbola.fnt, symbola.png | George Douros | [Freeware](https://fontlibrary.org/en/font/symbola) | Atlas made with [BMFont](https://www.angelcode.com/products/bmfont/) by [@raysan5](https://github.com/raysan5) |
+| DotGothic16-Regular.ttf | [The DotGothic16 Project Authors](https://github.com/fontworks-fonts/DotGothic16) | [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL) | - |
+| NotoSansTC-Regular.ttf | [Adobe](http://www.adobe.com/) | [SIL Open Font License](https://openfontlicense.org/documents/OFL.txt) | - |
diff --git a/examples/text/text_inline_styling.c b/examples/text/text_inline_styling.c
index aeebe0abc..8faef30eb 100644
--- a/examples/text/text_inline_styling.c
+++ b/examples/text/text_inline_styling.c
@@ -70,6 +70,8 @@ int main(void)
// - Define foreground color: [cRRGGBBAA]
// - Define background color: [bRRGGBBAA]
// - Reset formating: [r]
+ // Colors defined with [cRRGGBBAA] or [bRRGGBBAA] are multiplied by the base color alpha
+ // This allows global transparency control while keeping per-section styling (ex. text fade effects)
// Example: [bAA00AAFF][cFF0000FF]red text on gray background[r] normal text
DrawTextStyled(GetFontDefault(), "This changes the [cFF0000FF]foreground color[r] of provided text!!!",
@@ -81,12 +83,15 @@ int main(void)
DrawTextStyled(GetFontDefault(), "This changes the [c00ff00ff][bff0000ff]foreground and background colors[r]!!!",
(Vector2){ 100, 160 }, 20.0f, 2.0f, BLACK);
+ DrawTextStyled(GetFontDefault(), "This changes the [c00ff00ff]alpha[r] relative [cffffffff][b000000ff]from source[r] [cff000088]color[r]!!!",
+ (Vector2){ 100, 200 }, 20.0f, 2.0f, (Color){ 0, 0, 0, 100 });
+
// 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);
+ DrawTextStyled(GetFontDefault(), text, (Vector2){ 100, 240 }, 40.0f, 2.0f, BLACK);
textSize = MeasureTextStyled(GetFontDefault(), text, 40.0f, 2.0f);
- DrawRectangleLines(100, 220, (int)textSize.x, (int)textSize.y, GREEN);
+ DrawRectangleLines(100, 240, (int)textSize.x, (int)textSize.y, GREEN);
EndDrawing();
//----------------------------------------------------------------------------------
@@ -105,6 +110,7 @@ int main(void)
//----------------------------------------------------------------------------------
// Draw text using inline styling
// PARAM: color is the default text color, background color is BLANK by default
+// NOTE: Using input color as the base alpha multiplied to inline styles
static void DrawTextStyled(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color color)
{
// Text inline styling strategy used: [ ] delimiters for format
@@ -171,8 +177,16 @@ static void DrawTextStyled(Font font, const char *text, Vector2 position, float
// Convert hex color text into actual Color
unsigned int colHexValue = strtoul(colHexText, NULL, 16);
- if (text[i - 1] == 'c') colFront = GetColor(colHexValue);
- else if (text[i - 1] == 'b') colBack = GetColor(colHexValue);
+ if (text[i - 1] == 'c')
+ {
+ colFront = GetColor(colHexValue);
+ colFront.a *= (float)color.a/255.0f;
+ }
+ else if (text[i - 1] == 'b')
+ {
+ colBack = GetColor(colHexValue);
+ colBack.a *= (float)color.a/255.0f;
+ }
i += (colHexCount + 1); // Skip color value retrieved and ']'
continue; // Do not draw characters
diff --git a/examples/text/text_strings_management.c b/examples/text/text_strings_management.c
new file mode 100644
index 000000000..d2e349279
--- /dev/null
+++ b/examples/text/text_strings_management.c
@@ -0,0 +1,400 @@
+/*******************************************************************************************
+*
+* raylib [text] example - strings management
+*
+* Example complexity rating: [★★★☆] 3/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*
+* Example contributed by David Buzatto (@davidbuzatto) 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 David Buzatto (@davidbuzatto)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include
+
+#define MAX_TEXT_LENGTH 100
+#define MAX_TEXT_PARTICLES 100
+#define FONT_SIZE 30
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct TextParticle {
+ char text[MAX_TEXT_LENGTH];
+ Rectangle rect; // Boundary
+ Vector2 vel; // Velocity
+ Vector2 ppos; // Previous position
+ float padding;
+ float borderWidth;
+ float friction;
+ float elasticity;
+ Color color;
+ bool grabbed;
+} TextParticle;
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+void PrepareFirstTextParticle(const char* text, TextParticle *tps, int *particleCount);
+TextParticle CreateTextParticle(const char *text, float x, float y, Color color);
+void SliceTextParticle(TextParticle *tp, int particlePos, int sliceLength, TextParticle *tps, int *particleCount);
+void SliceTextParticleByChar(TextParticle *tp, char charToSlice, TextParticle *tps, int *particleCount);
+void ShatterTextParticle(TextParticle *tp, int particlePos, TextParticle *tps, int *particleCount);
+void GlueTextParticles(TextParticle *grabbed, TextParticle *target, TextParticle *tps, int *particleCount);
+void RealocateTextParticles(TextParticle *tps, int particlePos, int *particleCount);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [text] example - strings management");
+
+ TextParticle textParticles[MAX_TEXT_PARTICLES] = { 0 };
+ int particleCount = 0;
+ TextParticle *grabbedTextParticle = NULL;
+ Vector2 pressOffset = {0};
+
+ PrepareFirstTextParticle("raylib => fun videogames programming!", textParticles, &particleCount);
+
+ 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 delta = GetFrameTime();
+ Vector2 mousePos = GetMousePosition();
+
+ // Checks if a text particle was grabbed
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
+ {
+ for (int i = particleCount - 1; i >= 0; i--)
+ {
+ TextParticle *tp = &textParticles[i];
+ pressOffset.x = mousePos.x - tp->rect.x;
+ pressOffset.y = mousePos.y - tp->rect.y;
+ if (CheckCollisionPointRec(mousePos, tp->rect))
+ {
+ tp->grabbed = true;
+ grabbedTextParticle = tp;
+ break;
+ }
+ }
+ }
+
+ // Releases any text particle the was grabbed
+ if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT))
+ {
+ if (grabbedTextParticle != NULL)
+ {
+ grabbedTextParticle->grabbed = false;
+ grabbedTextParticle = NULL;
+ }
+ }
+
+ // Slice os shatter a text particle
+ if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT))
+ {
+ for (int i = particleCount - 1; i >= 0; i--)
+ {
+ TextParticle *tp = &textParticles[i];
+ if (CheckCollisionPointRec(mousePos, tp->rect))
+ {
+ if (IsKeyDown(KEY_LEFT_SHIFT))
+ {
+ ShatterTextParticle(tp, i, textParticles, &particleCount);
+ }
+ else
+ {
+ SliceTextParticle(tp, i, TextLength(tp->text)/2, textParticles, &particleCount);
+ }
+ break;
+ }
+ }
+ }
+
+ // Shake text particles
+ if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))
+ {
+ for (int i = 0; i < particleCount; i++)
+ {
+ if (!textParticles[i].grabbed) textParticles[i].vel = (Vector2){ GetRandomValue(-2000, 2000), GetRandomValue(-2000, 2000) };
+ }
+ }
+
+ // Reset using TextTo* functions
+ if (IsKeyPressed(KEY_ONE)) PrepareFirstTextParticle("raylib => fun videogames programming!", textParticles, &particleCount);
+ if (IsKeyPressed(KEY_TWO)) PrepareFirstTextParticle(TextToUpper("raylib => fun videogames programming!"), textParticles, &particleCount);
+ if (IsKeyPressed(KEY_THREE)) PrepareFirstTextParticle(TextToLower("raylib => fun videogames programming!"), textParticles, &particleCount);
+ if (IsKeyPressed(KEY_FOUR)) PrepareFirstTextParticle(TextToPascal("raylib_fun_videogames_programming"), textParticles, &particleCount);
+ if (IsKeyPressed(KEY_FIVE)) PrepareFirstTextParticle(TextToSnake("RaylibFunVideogamesProgramming"), textParticles, &particleCount);
+ if (IsKeyPressed(KEY_SIX)) PrepareFirstTextParticle(TextToCamel("raylib_fun_videogames_programming"), textParticles, &particleCount);
+
+ // Slice by char pressed only when we have one text particle
+ char charPressed = GetCharPressed();
+ if ((charPressed >= 'A') && (charPressed <= 'z') && (particleCount == 1))
+ {
+ SliceTextParticleByChar(&textParticles[0], charPressed, textParticles, &particleCount);
+ }
+
+ // Updates each text particle state
+ for (int i = 0; i < particleCount; i++)
+ {
+ TextParticle *tp = &textParticles[i];
+
+ // The text particle is not grabbed
+ if (!tp->grabbed)
+ {
+ // text particle repositioning using the velocity
+ tp->rect.x += tp->vel.x * delta;
+ tp->rect.y += tp->vel.y * delta;
+
+ // Does the text particle hit the screen right boundary?
+ if ((tp->rect.x + tp->rect.width) >= screenWidth)
+ {
+ tp->rect.x = screenWidth - tp->rect.width; // Text particle repositioning
+ tp->vel.x = -tp->vel.x*tp->elasticity; // Elasticity makes the text particle lose 10% of its velocity on hit
+ }
+ // Does the text particle hit the screen left boundary?
+ else if (tp->rect.x <= 0)
+ {
+ tp->rect.x = 0.0f;
+ tp->vel.x = -tp->vel.x*tp->elasticity;
+ }
+
+ // The same for y axis
+ if ((tp->rect.y + tp->rect.height) >= screenHeight)
+ {
+ tp->rect.y = screenHeight - tp->rect.height;
+ tp->vel.y = -tp->vel.y*tp->elasticity;
+ }
+ else if (tp->rect.y <= 0)
+ {
+ tp->rect.y = 0.0f;
+ tp->vel.y = -tp->vel.y*tp->elasticity;
+ }
+
+ // Friction makes the text particle lose 1% of its velocity each frame
+ tp->vel.x = tp->vel.x*tp->friction;
+ tp->vel.y = tp->vel.y*tp->friction;
+ }
+ else
+ {
+ // Text particle repositioning using the mouse position
+ tp->rect.x = mousePos.x - pressOffset.x;
+ tp->rect.y = mousePos.y - pressOffset.y;
+
+ // While the text particle is grabbed, recalculates its velocity
+ tp->vel.x = (tp->rect.x - tp->ppos.x)/delta;
+ tp->vel.y = (tp->rect.y - tp->ppos.y)/delta;
+ tp->ppos.x = tp->rect.x;
+ tp->ppos.y = tp->rect.y;
+
+ // Glue text particles when dragging and pressing left ctrl
+ if (IsKeyDown(KEY_LEFT_CONTROL))
+ {
+ for (int i = 0; i < particleCount; i++)
+ {
+ if (&textParticles[i] != grabbedTextParticle && grabbedTextParticle->grabbed)
+ {
+ if (CheckCollisionRecs(grabbedTextParticle->rect, textParticles[i].rect))
+ {
+ GlueTextParticles(grabbedTextParticle, &textParticles[i], textParticles, &particleCount);
+ grabbedTextParticle = &textParticles[particleCount-1];
+ }
+ }
+ }
+ }
+ }
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ for (int i = 0; i < particleCount; i++)
+ {
+ TextParticle *tp = &textParticles[i];
+ DrawRectangle(tp->rect.x-tp->borderWidth, tp->rect.y-tp->borderWidth, tp->rect.width+tp->borderWidth*2, tp->rect.height+tp->borderWidth*2, BLACK);
+ DrawRectangleRec(tp->rect, tp->color);
+ DrawText(tp->text, tp->rect.x+tp->padding, tp->rect.y+tp->padding, FONT_SIZE, BLACK);
+ }
+
+ DrawText("grab a text particle by pressing with the mouse and throw it by releasing", 10, 10, 10, DARKGRAY);
+ DrawText("slice a text particle by pressing it with the mouse right button", 10, 30, 10, DARKGRAY);
+ DrawText("shatter a text particle keeping left shift pressed and pressing it with the mouse right button", 10, 50, 10, DARKGRAY);
+ DrawText("glue text particles by grabbing than and keeping left control pressed", 10, 70, 10, DARKGRAY);
+ DrawText("1 to 6 to reset", 10, 90, 10, DARKGRAY);
+ DrawText("when you have only one text particle, you can slice it by pressing a char", 10, 110, 10, DARKGRAY);
+ DrawText(TextFormat("TEXT PARTICLE COUNT: %d", particleCount), 10, GetScreenHeight() - 30, 20, BLACK);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+void PrepareFirstTextParticle(const char* text, TextParticle *tps, int *particleCount)
+{
+ tps[0] = CreateTextParticle(
+ text,
+ GetScreenWidth()/2,
+ GetScreenHeight()/2,
+ RAYWHITE
+ );
+ *particleCount = 1;
+}
+
+TextParticle CreateTextParticle(const char *text, float x, float y, Color color)
+{
+ TextParticle tp = {
+ .text = "",
+ .rect = { x, y, 30, 30 },
+ .vel = { GetRandomValue(-200, 200), GetRandomValue(-200, 200) },
+ .ppos = { 0 },
+ .padding = 5.0f,
+ .borderWidth = 5.0f,
+ .friction = 0.99,
+ .elasticity = 0.9,
+ .color = color,
+ .grabbed = false
+ };
+
+ TextCopy(tp.text, text);
+ tp.rect.width = MeasureText(tp.text, FONT_SIZE)+tp.padding*2;
+ tp.rect.height = FONT_SIZE+tp.padding*2;
+ return tp;
+}
+
+void SliceTextParticle(TextParticle *tp, int particlePos, int sliceLength, TextParticle *tps, int *particleCount)
+{
+ int length = TextLength(tp->text);
+
+ if((length > 1) && ((*particleCount+length) < MAX_TEXT_PARTICLES))
+ {
+ for (int i = 0; i < length; i += sliceLength)
+ {
+ const char *text = sliceLength == 1 ? TextFormat("%c", tp->text[i]) : TextSubtext(tp->text, i, sliceLength);
+ tps[(*particleCount)++] = CreateTextParticle(
+ text,
+ tp->rect.x + i * tp->rect.width/length,
+ tp->rect.y,
+ (Color) { GetRandomValue(0, 255), GetRandomValue(0, 255), GetRandomValue(0, 255), 255 }
+ );
+ }
+ RealocateTextParticles(tps, particlePos, particleCount);
+ }
+}
+
+void SliceTextParticleByChar(TextParticle *tp, char charToSlice, TextParticle *tps, int *particleCount)
+{
+ int tokenCount = 0;
+ char **tokens = TextSplit(tp->text, charToSlice, &tokenCount);
+
+ if (tokenCount > 1)
+ {
+ int textLength = TextLength(tp->text);
+ for (int i = 0; i < textLength; i++)
+ {
+ if (tp->text[i] == charToSlice)
+ {
+ tps[(*particleCount)++] = CreateTextParticle(
+ TextFormat("%c", charToSlice),
+ tp->rect.x,
+ tp->rect.y,
+ (Color) { GetRandomValue(0, 255), GetRandomValue(0, 255), GetRandomValue(0, 255), 255 }
+ );
+ }
+ }
+ for (int i = 0; i < tokenCount; i++)
+ {
+ int tokenLength = TextLength(tokens[i]);
+ tps[(*particleCount)++] = CreateTextParticle(
+ TextFormat("%s", tokens[i]),
+ tp->rect.x + i * tp->rect.width/tokenLength,
+ tp->rect.y,
+ (Color) { GetRandomValue(0, 255), GetRandomValue(0, 255), GetRandomValue(0, 255), 255 }
+ );
+ }
+ if (tokenCount)
+ {
+ RealocateTextParticles(tps, 0, particleCount);
+ }
+ }
+}
+
+void ShatterTextParticle(TextParticle *tp, int particlePos, TextParticle *tps, int *particleCount)
+{
+ SliceTextParticle(tp, particlePos, 1, tps, particleCount);
+}
+
+void GlueTextParticles(TextParticle *grabbed, TextParticle *target, TextParticle *tps, int *particleCount)
+{
+ int p1 = -1;
+ int p2 = -1;
+
+ for (int i = 0; i < *particleCount; i++)
+ {
+ if (&tps[i] == grabbed) p1 = i;
+ if (&tps[i] == target) p2 = i;
+ }
+
+ if ((p1 != -1) && (p2 != -1))
+ {
+ TextParticle tp = CreateTextParticle(
+ TextFormat( "%s%s", grabbed->text, target->text),
+ grabbed->rect.x,
+ grabbed->rect.y,
+ RAYWHITE
+ );
+ tp.grabbed = true;
+ tps[(*particleCount)++] = tp;
+ grabbed->grabbed = false;
+ if (p1 < p2)
+ {
+ RealocateTextParticles(tps, p2, particleCount);
+ RealocateTextParticles(tps, p1, particleCount);
+ }
+ else
+ {
+ RealocateTextParticles(tps, p1, particleCount);
+ RealocateTextParticles(tps, p2, particleCount);
+ }
+ }
+}
+
+void RealocateTextParticles(TextParticle *tps, int particlePos, int *particleCount)
+{
+ for (int i = particlePos+1; i < *particleCount; i++)
+ {
+ tps[i-1] = tps[i];
+ }
+ (*particleCount)--;
+}
\ No newline at end of file
diff --git a/examples/text/text_strings_management.png b/examples/text/text_strings_management.png
new file mode 100644
index 000000000..d9b6cc4ed
Binary files /dev/null and b/examples/text/text_strings_management.png differ
diff --git a/examples/text/text_words_alignment.c b/examples/text/text_words_alignment.c
index 6cfd2a85c..a558d5b11 100644
--- a/examples/text/text_words_alignment.c
+++ b/examples/text/text_words_alignment.c
@@ -19,6 +19,8 @@
#include "raymath.h" // Required for: Lerp()
+#include
+
typedef enum TextAlignment {
TEXT_ALIGN_LEFT = 0,
TEXT_ALIGN_TOP = 0,
@@ -58,7 +60,7 @@ int main(void)
// And of course the font...
Font font = GetFontDefault();
- // Intialize the alignment variables
+ // Initialize the alignment variables
TextAlignment hAlign = TEXT_ALIGN_CENTRE;
TextAlignment vAlign = TEXT_ALIGN_MIDDLE;
@@ -72,8 +74,7 @@ int main(void)
//----------------------------------------------------------------------------------
if (IsKeyPressed(KEY_LEFT))
{
- hAlign = hAlign - 1;
- if (hAlign < 0) hAlign = 0;
+ if (hAlign > 0) hAlign = hAlign - 1;
}
if (IsKeyPressed(KEY_RIGHT))
@@ -84,8 +85,7 @@ int main(void)
if (IsKeyPressed(KEY_UP))
{
- vAlign = vAlign - 1;
- if (vAlign < 0) vAlign = 0;
+ if (vAlign > 0) vAlign = vAlign - 1;
}
if (IsKeyPressed(KEY_DOWN))
@@ -95,7 +95,8 @@ int main(void)
}
// One word per second
- wordIndex = (int)GetTime()%wordCount;
+ if (wordCount > 0) wordIndex = (int)GetTime()%wordCount;
+ else wordIndex = 0;
//----------------------------------------------------------------------------------
// Draw
@@ -132,4 +133,4 @@ int main(void)
//--------------------------------------------------------------------------------------
return 0;
-}
\ No newline at end of file
+}
diff --git a/examples/textures/textures_cellular_automata.c b/examples/textures/textures_cellular_automata.c
new file mode 100644
index 000000000..affeeda93
--- /dev/null
+++ b/examples/textures/textures_cellular_automata.c
@@ -0,0 +1,212 @@
+/*******************************************************************************************
+*
+* raylib [textures] example - cellular automata
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.6, last time updated with raylib 5.6
+*
+* Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 Jordi Santonja (@JordSant)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+// Initialization constants
+//--------------------------------------------------------------------------------------
+const int screenWidth = 800;
+const int screenHeight = 450;
+const int imageWidth = 800;
+const int imageHeight = 800/2;
+
+// Rule button sizes and positions
+const int drawRuleStartX = 585;
+const int drawRuleStartY = 10;
+const int drawRuleSpacing = 15;
+const int drawRuleGroupSpacing = 50;
+const int drawRuleSize = 14;
+const int drawRuleInnerSize = 10;
+
+// Preset button sizes
+const int presetsSizeX = 42;
+const int presetsSizeY = 22;
+
+const int linesUpdatedPerFrame = 4;
+
+//----------------------------------------------------------------------------------
+// Functions
+//----------------------------------------------------------------------------------
+void ComputeLine(Image *image, int line, int rule)
+{
+ // Compute next line pixels. Boundaries are not computed, always 0
+ for (int i = 1; i < imageWidth - 1; i++)
+ {
+ // Get, from the previous line, the 3 pixels states as a binary value
+ const int prevValue = ((GetImageColor(*image, i - 1, line - 1).r < 5)? 4 : 0) + // Left pixel
+ ((GetImageColor(*image, i, line - 1).r < 5)? 2 : 0) + // Center pixel
+ ((GetImageColor(*image, i + 1, line - 1).r < 5)? 1 : 0); // Right pixel
+ // Get next value from rule bitmask
+ const bool currValue = (rule & (1 << prevValue));
+ // Update pixel color
+ ImageDrawPixel(image, i, line, (currValue)? BLACK : RAYWHITE);
+ }
+}
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "raylib [textures] example - cellular automata");
+
+ // Image that contains the cellular automaton
+ Image image = GenImageColor(imageWidth, imageHeight, RAYWHITE);
+ // The top central pixel set as black
+ ImageDrawPixel(&image, imageWidth/2, 0, BLACK);
+
+ Texture2D texture = LoadTextureFromImage(image);
+
+ // Some interesting rules
+ const int presetValues[] = { 18, 30, 60, 86, 102, 124, 126, 150, 182, 225 };
+ const int presetsCount = sizeof(presetValues)/sizeof(presetValues[0]);
+
+ // Variables
+ int rule = 30; // Starting rule
+ int line = 1; // Line to compute, starting from line 1. One point in line 0 is already set
+
+ SetTargetFPS(60);
+ //---------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ // Handle mouse
+ const Vector2 mouse = GetMousePosition();
+ int mouseInCell = -1; // -1: outside any button; 0-7: rule cells; 8+: preset cells
+
+ // Check mouse on rule cells
+ for (int i = 0; i < 8; i++)
+ {
+ const int cellX = drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing;
+ const int cellY = drawRuleStartY + drawRuleSpacing;
+ if ((mouse.x >= cellX) && (mouse.x <= cellX + drawRuleSize) &&
+ (mouse.y >= cellY) && (mouse.y <= cellY + drawRuleSize))
+ {
+ mouseInCell = i; // 0-7: rule cells
+ break;
+ }
+ }
+
+ // Check mouse on preset cells
+ if (mouseInCell < 0)
+ {
+ for (int i = 0; i < presetsCount; i++)
+ {
+ const int cellX = 4 + (presetsSizeX + 2)*(i/2);
+ const int cellY = 2 + (presetsSizeY + 2)*(i%2);
+ if ((mouse.x >= cellX) && (mouse.x <= cellX + presetsSizeX) &&
+ (mouse.y >= cellY) && (mouse.y <= cellY + presetsSizeY))
+ {
+ mouseInCell = i + 8; // 8+: preset cells
+ break;
+ }
+ }
+ }
+
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (mouseInCell >= 0))
+ {
+ // Rule changed both by selecting a preset or toggling a bit
+ if (mouseInCell < 8)
+ rule ^= (1 << mouseInCell);
+ else
+ rule = presetValues[mouseInCell - 8];
+
+ // Reset image
+ ImageClearBackground(&image, RAYWHITE);
+ ImageDrawPixel(&image, imageWidth/2, 0, BLACK);
+ line = 1;
+ }
+
+ // Compute next lines
+ //----------------------------------------------------------------------------------
+ if (line < imageHeight)
+ {
+ for (int i = 0; (i < linesUpdatedPerFrame) && (line + i < imageHeight); i++)
+ ComputeLine(&image, line + i, rule);
+ line += linesUpdatedPerFrame;
+
+ UpdateTexture(texture, image.data);
+ }
+
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(RAYWHITE);
+
+ // Draw cellular automaton texture
+ DrawTexture(texture, 0, screenHeight - imageHeight, WHITE);
+
+ // Draw preset values
+ for (int i = 0; i < presetsCount; i++)
+ {
+ DrawText(TextFormat("%i", presetValues[i]), 8 + (presetsSizeX + 2)*(i/2), 4 + (presetsSizeY + 2)*(i%2), 20, GRAY);
+ DrawRectangleLines(4 + (presetsSizeX + 2)*(i/2), 2 + (presetsSizeY + 2)*(i%2), presetsSizeX, presetsSizeY, BLUE);
+
+ // If the mouse is on this preset, highlight it
+ if (mouseInCell == i + 8)
+ DrawRectangleLinesEx((Rectangle) { 2 + (presetsSizeX + 2.0f)*(i/2),
+ (presetsSizeY + 2.0f)*(i%2),
+ presetsSizeX + 4.0f, presetsSizeY + 4.0f }, 3, RED);
+ }
+
+ // Draw rule bits
+ for (int i = 0; i < 8; i++)
+ {
+ // The three input bits
+ for (int j = 0; j < 3; j++)
+ {
+ DrawRectangleLines(drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing*j, drawRuleStartY, drawRuleSize, drawRuleSize, GRAY);
+ if (i & (4 >> j))
+ DrawRectangle(drawRuleStartX + 2 - drawRuleGroupSpacing*i + drawRuleSpacing*j, drawRuleStartY + 2, drawRuleInnerSize, drawRuleInnerSize, BLACK);
+ }
+
+ // The output bit
+ DrawRectangleLines(drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing, drawRuleStartY + drawRuleSpacing, drawRuleSize, drawRuleSize, BLUE);
+ if (rule & (1 << i))
+ DrawRectangle(drawRuleStartX + 2 - drawRuleGroupSpacing*i + drawRuleSpacing, drawRuleStartY + 2 + drawRuleSpacing, drawRuleInnerSize, drawRuleInnerSize, BLACK);
+
+ // If the mouse is on this rule bit, highlight it
+ if (mouseInCell == i)
+ DrawRectangleLinesEx((Rectangle){ drawRuleStartX - drawRuleGroupSpacing*i + drawRuleSpacing - 2.0f,
+ drawRuleStartY + drawRuleSpacing - 2.0f,
+ drawRuleSize + 4.0f, drawRuleSize + 4.0f }, 3, RED);
+ }
+
+ DrawText(TextFormat("RULE: %i", rule), drawRuleStartX + drawRuleSpacing*4, drawRuleStartY + 1, 30, GRAY);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadImage(image);
+ UnloadTexture(texture);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
diff --git a/examples/textures/textures_cellular_automata.png b/examples/textures/textures_cellular_automata.png
new file mode 100644
index 000000000..2d88041d2
Binary files /dev/null and b/examples/textures/textures_cellular_automata.png differ
diff --git a/projects/4coder/Makefile.Android b/projects/4coder/Makefile.Android
index 29d437b1b..9e6773651 100644
--- a/projects/4coder/Makefile.Android
+++ b/projects/4coder/Makefile.Android
@@ -96,7 +96,7 @@ ifeq ($(ANDROID_ARCH),ARM)
CFLAGS = -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16
endif
ifeq ($(ANDROID_ARCH),ARM64)
- CFLAGS = -std=c99 -target aarch64 -mfix-cortex-a53-835769
+ CFLAGS = -std=c99 -mfix-cortex-a53-835769
endif
# Compilation functions attributes options
CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC
diff --git a/projects/VS2022/examples/core_high_dpi.vcxproj b/projects/VS2022/examples/core_highdpi_demo.vcxproj
similarity index 97%
rename from projects/VS2022/examples/core_high_dpi.vcxproj
rename to projects/VS2022/examples/core_highdpi_demo.vcxproj
index 11e1b41c0..8a7cdce40 100644
--- a/projects/VS2022/examples/core_high_dpi.vcxproj
+++ b/projects/VS2022/examples/core_highdpi_demo.vcxproj
@@ -1,569 +1,569 @@
-
-
-
-
- Debug.DLL
- ARM64
-
-
- Debug.DLL
- Win32
-
-
- Debug.DLL
- x64
-
-
- Debug
- ARM64
-
-
- Debug
- Win32
-
-
- Debug
- x64
-
-
- Release.DLL
- ARM64
-
-
- Release.DLL
- Win32
-
-
- Release.DLL
- x64
-
-
- Release
- ARM64
-
-
- Release
- Win32
-
-
- Release
- x64
-
-
-
- {BCB71111-8505-4B35-8CEF-EC6115DC9D4D}
- Win32Proj
- core_high_dpi
- 10.0
- core_high_dpi
-
-
-
- Application
- true
- $(DefaultPlatformToolset)
- Unicode
-
-
- Application
- true
- $(DefaultPlatformToolset)
- Unicode
-
-
- Application
- true
- $(DefaultPlatformToolset)
- Unicode
-
-
- Application
- true
- $(DefaultPlatformToolset)
- Unicode
-
-
- Application
- true
- $(DefaultPlatformToolset)
- Unicode
-
-
- Application
- true
- $(DefaultPlatformToolset)
- Unicode
-
-
- Application
- false
- $(DefaultPlatformToolset)
- true
- Unicode
-
-
- Application
- false
- $(DefaultPlatformToolset)
- true
- Unicode
-
-
- Application
- false
- $(DefaultPlatformToolset)
- true
- Unicode
-
-
- Application
- false
- $(DefaultPlatformToolset)
- true
- Unicode
-
-
- Application
- false
- $(DefaultPlatformToolset)
- true
- Unicode
-
-
- Application
- false
- $(DefaultPlatformToolset)
- true
- Unicode
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- true
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- true
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- true
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- true
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- true
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- false
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- false
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- false
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- false
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- false
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- false
- $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
- $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
- $(SolutionDir)..\..\examples\core
- WindowsLocalDebugger
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
- CompileAsC
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
-
-
- Console
- true
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
-
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
- CompileAsC
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
- /FS %(AdditionalOptions)
-
-
- Console
- true
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
-
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
- CompileAsC
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
- /FS %(AdditionalOptions)
-
-
- Console
- true
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
-
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
- CompileAsC
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
-
-
- Console
- true
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
-
-
- xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
- Copy Debug DLL to output directory
-
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
- CompileAsC
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
-
-
- Console
- true
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
-
-
- xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
- Copy Debug DLL to output directory
-
-
-
-
-
-
- Level3
- Disabled
- WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
- CompileAsC
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
-
-
- Console
- true
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
-
-
- xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
- Copy Debug DLL to output directory
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
- CompileAsC
- true
-
-
- Console
- true
- true
- true
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
- CompileAsC
- true
-
-
- Console
- true
- true
- true
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
- CompileAsC
- true
-
-
- Console
- true
- true
- true
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
- CompileAsC
- true
-
-
- Console
- true
- true
- true
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
-
-
- xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
-
-
- Copy Release DLL to output directory
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
- CompileAsC
- true
-
-
- Console
- true
- true
- true
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
-
-
- xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
-
-
- Copy Release DLL to output directory
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
- $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
- CompileAsC
- true
-
-
- Console
- true
- true
- true
- raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
- $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
-
-
- xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
-
-
- Copy Release DLL to output directory
-
-
-
-
-
-
-
-
-
-
- {e89d61ac-55de-4482-afd4-df7242ebc859}
-
-
-
-
-
-
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {BCB71111-8505-4B35-8CEF-EC6115DC9D4D}
+ Win32Proj
+ core_highdpi_demo
+ 10.0
+ core_highdpi_demo
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\core
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
diff --git a/projects/VS2022/examples/shaders_game_of_life.vcxproj b/projects/VS2022/examples/shaders_game_of_life.vcxproj
new file mode 100644
index 000000000..0ede87cda
--- /dev/null
+++ b/projects/VS2022/examples/shaders_game_of_life.vcxproj
@@ -0,0 +1,569 @@
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {071E64F3-1396-4A97-97CA-98CAC059B168}
+ Win32Proj
+ shaders_game_of_life
+ 10.0
+ shaders_game_of_life
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shapes_ball_physics.vcxproj b/projects/VS2022/examples/shapes_ball_physics.vcxproj
new file mode 100644
index 000000000..9b7e98658
--- /dev/null
+++ b/projects/VS2022/examples/shapes_ball_physics.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
+
+
+
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}
+ Win32Proj
+ shapes_ball_physics
+ 10.0
+ shapes_ball_physics
+
+
+
+ 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_penrose_tile.vcxproj b/projects/VS2022/examples/shapes_penrose_tile.vcxproj
new file mode 100644
index 000000000..bde99f8c1
--- /dev/null
+++ b/projects/VS2022/examples/shapes_penrose_tile.vcxproj
@@ -0,0 +1,569 @@
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}
+ Win32Proj
+ shapes_penrose_tile
+ 10.0
+ shapes_penrose_tile
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shapes_triangle_strip.vcxproj b/projects/VS2022/examples/shapes_triangle_strip.vcxproj
index b128c0ff6..eb4e200dd 100644
--- a/projects/VS2022/examples/shapes_triangle_strip.vcxproj
+++ b/projects/VS2022/examples/shapes_triangle_strip.vcxproj
@@ -553,7 +553,7 @@
-
+
diff --git a/projects/VS2022/examples/text_strings_management.vcxproj b/projects/VS2022/examples/text_strings_management.vcxproj
new file mode 100644
index 000000000..41b9b3ac0
--- /dev/null
+++ b/projects/VS2022/examples/text_strings_management.vcxproj
@@ -0,0 +1,569 @@
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {1F4722E7-F78E-413F-A106-D3490211EA57}
+ Win32Proj
+ text_strings_management
+ 10.0
+ text_strings_management
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\text
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/textures_cellular_automata.vcxproj b/projects/VS2022/examples/textures_cellular_automata.vcxproj
new file mode 100644
index 000000000..f8b434a6d
--- /dev/null
+++ b/projects/VS2022/examples/textures_cellular_automata.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
+
+
+
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}
+ Win32Proj
+ textures_cellular_automata
+ 10.0
+ textures_cellular_automata
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\textures
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln
index 07068d34c..50fef1cf5 100644
--- a/projects/VS2022/raylib.sln
+++ b/projects/VS2022/raylib.sln
@@ -57,7 +57,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_custom_logging", "exam
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_drop_files", "examples\core_drop_files.vcxproj", "{0199E349-0701-40BC-8A7F-06A54FFA3E7C}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_high_dpi", "examples\core_high_dpi.vcxproj", "{BCB71111-8505-4B35-8CEF-EC6115DC9D4D}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_highdpi_demo", "examples\core_highdpi_demo.vcxproj", "{BCB71111-8505-4B35-8CEF-EC6115DC9D4D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_input_gamepad", "examples\core_input_gamepad.vcxproj", "{8F19E3DA-8929-4000-87B5-3CA6929636CC}"
EndProject
@@ -421,6 +421,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_rlgl_triangle", "exa
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_sprite_stacking", "examples\textures_sprite_stacking.vcxproj", "{FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_ball_physics", "examples\shapes_ball_physics.vcxproj", "{0653AFAF-5578-4C02-AF29-0C873E7634AE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_game_of_life", "examples\shaders_game_of_life.vcxproj", "{071E64F3-1396-4A97-97CA-98CAC059B168}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_penrose_tile", "examples\shapes_penrose_tile.vcxproj", "{7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "text_strings_management", "examples\text_strings_management.vcxproj", "{1F4722E7-F78E-413F-A106-D3490211EA57}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_cellular_automata", "examples\textures_cellular_automata.vcxproj", "{0A0FC982-6E31-401F-BA77-3C5E8AB02C68}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug.DLL|ARM64 = Debug.DLL|ARM64
@@ -5235,6 +5245,126 @@ Global
{FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|x64.Build.0 = Release|x64
{FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|x86.ActiveCfg = Release|Win32
{FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F}.Release|x86.Build.0 = Release|Win32
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|ARM64.Build.0 = Debug|ARM64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|x64.ActiveCfg = Debug|x64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|x64.Build.0 = Debug|x64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|x86.ActiveCfg = Debug|Win32
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Debug|x86.Build.0 = Debug|Win32
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|ARM64.ActiveCfg = Release|ARM64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|ARM64.Build.0 = Release|ARM64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|x64.ActiveCfg = Release|x64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|x64.Build.0 = Release|x64
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|x86.ActiveCfg = Release|Win32
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE}.Release|x86.Build.0 = Release|Win32
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|ARM64.Build.0 = Debug|ARM64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|x64.ActiveCfg = Debug|x64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|x64.Build.0 = Debug|x64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|x86.ActiveCfg = Debug|Win32
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Debug|x86.Build.0 = Debug|Win32
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|ARM64.ActiveCfg = Release|ARM64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|ARM64.Build.0 = Release|ARM64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|x64.ActiveCfg = Release|x64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|x64.Build.0 = Release|x64
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|x86.ActiveCfg = Release|Win32
+ {071E64F3-1396-4A97-97CA-98CAC059B168}.Release|x86.Build.0 = Release|Win32
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|ARM64.Build.0 = Debug|ARM64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|x64.ActiveCfg = Debug|x64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|x64.Build.0 = Debug|x64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|x86.ActiveCfg = Debug|Win32
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Debug|x86.Build.0 = Debug|Win32
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|ARM64.ActiveCfg = Release|ARM64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|ARM64.Build.0 = Release|ARM64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|x64.ActiveCfg = Release|x64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|x64.Build.0 = Release|x64
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|x86.ActiveCfg = Release|Win32
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC}.Release|x86.Build.0 = Release|Win32
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|ARM64.Build.0 = Debug|ARM64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|x64.ActiveCfg = Debug|x64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|x64.Build.0 = Debug|x64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|x86.ActiveCfg = Debug|Win32
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Debug|x86.Build.0 = Debug|Win32
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|ARM64.ActiveCfg = Release|ARM64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|ARM64.Build.0 = Release|ARM64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|x64.ActiveCfg = Release|x64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|x64.Build.0 = Release|x64
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|x86.ActiveCfg = Release|Win32
+ {1F4722E7-F78E-413F-A106-D3490211EA57}.Release|x86.Build.0 = Release|Win32
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|ARM64.Build.0 = Debug|ARM64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|x64.ActiveCfg = Debug|x64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|x64.Build.0 = Debug|x64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|x86.ActiveCfg = Debug|Win32
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Debug|x86.Build.0 = Debug|Win32
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|ARM64.ActiveCfg = Release|ARM64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|ARM64.Build.0 = Release|ARM64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|x64.ActiveCfg = Release|x64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|x64.Build.0 = Release|x64
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|x86.ActiveCfg = Release|Win32
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -5402,7 +5532,7 @@ Global
{C54703BF-D68A-480D-BE27-49B62E45D582} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
{9CD8BCAD-F212-4BCC-BA98-899743CE3279} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}
{0981CA28-E4A5-4DF1-987F-A41D09131EFC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
- {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}
+ {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
{6BFF72EA-7362-4A3B-B6E5-9A3655BBBDA3} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
{6777EC3C-077C-42FC-B4AD-B799CE55CCE4} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A}
{A61DAD9C-271C-4E95-81AA-DB4CD58564D4} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
@@ -5411,9 +5541,9 @@ Global
{3B27F358-2679-4F38-B297-17B536F580BB} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{718FCBD0-591D-448C-B7D5-9F1CA8544E7B} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{19CA0070-B4B2-4394-90B7-D0C259AA35BA} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
- {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
- {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {278D8859-20B1-428F-8448-064F46E1F021}
- {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A}
+ {52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
{8E132D5A-2C00-48D0-8747-97E41356F26F} = {278D8859-20B1-428F-8448-064F46E1F021}
{A4662163-83E7-4309-8CAA-B0BF13655FE6} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
{5F4B766F-DD52-4B53-B6C3-BC7611E17F20} = {278D8859-20B1-428F-8448-064F46E1F021}
@@ -5429,7 +5559,7 @@ Global
{124935CC-73BB-489E-92E8-4F922A85DB5D} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{AC215730-2B5F-4498-B7F5-5DB80AEFCA5F} = {278D8859-20B1-428F-8448-064F46E1F021}
{0835E6BF-0170-4E99-A55C-E06E1EF4C3B2} = {278D8859-20B1-428F-8448-064F46E1F021}
- {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}
+ {EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} = {278D8859-20B1-428F-8448-064F46E1F021}
{1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{9DE2FC01-A839-4F89-8319-9071D4C54821} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{2F578155-D51F-4C03-AB7F-5C5122CA46CC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
@@ -5447,6 +5577,11 @@ Global
{32FE2658-1D70-442E-8672-0AC5C6F0BD7B} = {278D8859-20B1-428F-8448-064F46E1F021}
{842B6472-4AA6-4C2B-A5E5-A62F80DE2C4F} = {278D8859-20B1-428F-8448-064F46E1F021}
{FC4DEBD2-4B17-4534-8EEA-BB24A2DBEB5F} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}
+ {0653AFAF-5578-4C02-AF29-0C873E7634AE} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {071E64F3-1396-4A97-97CA-98CAC059B168} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
+ {7883D076-CA8F-4FF7-8B5D-0DFF41CEF8FC} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {1F4722E7-F78E-413F-A106-D3490211EA57} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A}
+ {0A0FC982-6E31-401F-BA77-3C5E8AB02C68} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29}
diff --git a/projects/VSCode/Makefile.Android b/projects/VSCode/Makefile.Android
index 7e41ea52f..279790d2a 100644
--- a/projects/VSCode/Makefile.Android
+++ b/projects/VSCode/Makefile.Android
@@ -96,7 +96,7 @@ ifeq ($(ANDROID_ARCH),ARM)
CFLAGS = -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16
endif
ifeq ($(ANDROID_ARCH),ARM64)
- CFLAGS = -std=c99 -target aarch64 -mfix-cortex-a53-835769
+ CFLAGS = -std=c99 -mfix-cortex-a53-835769
endif
# Compilation functions attributes options
CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC
diff --git a/src/Makefile b/src/Makefile
index 41867da1c..bc84abece 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -406,7 +406,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16
endif
ifeq ($(ANDROID_ARCH),arm64)
- CFLAGS += -target aarch64 -mfix-cortex-a53-835769
+ CFLAGS += -mfix-cortex-a53-835769
endif
ifeq ($(ANDROID_ARCH),x86)
CFLAGS += -march=i686
diff --git a/src/external/rlsw.h b/src/external/rlsw.h
index 025216e39..80fb02c4f 100644
--- a/src/external/rlsw.h
+++ b/src/external/rlsw.h
@@ -2217,7 +2217,7 @@ static inline bool sw_triangle_face_culling(void)
const float *h2 = RLSW.vertexBuffer[2].homogeneous;
// Compute a value proportional to the signed area in the projected 2D plane,
- // calculated directly using homogeneous coordinates BEFORE division by w.
+ // calculated directly using homogeneous coordinates BEFORE division by w
// This is the determinant of the matrix formed by the (x, y, w) components
// of the vertices, which correctly captures the winding order in homogeneous
// space and its relationship to the projected 2D winding order, even with
@@ -2235,13 +2235,13 @@ static inline bool sw_triangle_face_culling(void)
// Discard the triangle if its winding order (determined by the sign
// of the homogeneous area/determinant) matches the culled direction
// A positive hSgnArea typically corresponds to a counter-clockwise
- // winding in the projected space when all w > 0.
+ // winding in the projected space when all w > 0
// This test is robust for points with w > 0 or w < 0, correctly
// capturing the change in orientation when crossing the w=0 plane
// The culling logic remains the same based on the signed area/determinant
// A value of 0 for hSgnArea means the points are collinear in (x, y, w)
- // space, which corresponds to a degenerate triangle projection.
+ // space, which corresponds to a degenerate triangle projection
// Such triangles are typically not culled by this test (0 < 0 is false, 0 > 0 is false)
// and should be handled by the clipper if necessary
return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0) : (hSgnArea > 0); // Cull if winding is "clockwise" : "counter-clockwise"
@@ -2602,7 +2602,7 @@ static inline bool sw_quad_face_culling(void)
// space, which corresponds to a degenerate triangle projection
// Such quads might also be degenerate or non-planar. They are typically
// not culled by this test (0 < 0 is false, 0 > 0 is false)
- // and should be handled by the clipper if necessary.
+ // and should be handled by the clipper if necessary
return (RLSW.cullFace == SW_FRONT)? (hSgnArea < 0.0f) : (hSgnArea > 0.0f); // Cull if winding is "clockwise" : "counter-clockwise"
}
diff --git a/src/external/sdefl.h b/src/external/sdefl.h
index 36015b95b..bdc45b7eb 100644
--- a/src/external/sdefl.h
+++ b/src/external/sdefl.h
@@ -198,7 +198,7 @@ extern int zsdeflate(struct sdefl *s, void *o, const void *i, int n, int lvl);
static int
sdefl_ilog2(int n) {
if (!n) return 0;
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__llvm__) && !defined(__INTEL_COMPILER) // @raysan5, address PR #5367
unsigned long msbp = 0;
_BitScanReverse(&msbp, (unsigned long)n);
return (int)msbp;
diff --git a/src/external/sinfl.h b/src/external/sinfl.h
index a749501ca..c8d0f96d0 100644
--- a/src/external/sinfl.h
+++ b/src/external/sinfl.h
@@ -171,7 +171,7 @@ extern int zsinflate(void *out, int cap, const void *in, int size);
static int
sinfl_bsr(unsigned n) {
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__llvm__) && !defined(__INTEL_COMPILER) // @raysan5, address PR #5367
unsigned long uln = 0;
_BitScanReverse(&uln, n);
return (int)(uln);
diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c
index 88b3b4bba..7b8d3e052 100644
--- a/src/platforms/rcore_android.c
+++ b/src/platforms/rcore_android.c
@@ -84,7 +84,6 @@ typedef struct {
// Global Variables Definition
//----------------------------------------------------------------------------------
extern CoreData CORE; // Global CORE state context
-extern bool isGpuReady; // Flag to note GPU has been initialized successfully
static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
@@ -358,13 +357,17 @@ void RestoreWindow(void)
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
- TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform");
+ if (!CORE.Window.ready) TRACELOG(LOG_WARNING, "WINDOW: SetWindowState does nothing before window initialization, Use \"SetConfigFlags\" instead");
+
+ // State change: FLAG_WINDOW_ALWAYS_RUN
+ if (!FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
}
// Clear window configuration state flags
void ClearWindowState(unsigned int flags)
{
- TRACELOG(LOG_WARNING, "ClearWindowState() not available on target platform");
+ // State change: FLAG_WINDOW_ALWAYS_RUN
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_ALWAYS_RUN)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN);
}
// Set icon for window
@@ -602,7 +605,7 @@ void DisableCursor(void)
// Swap back buffer with front buffer (screen drawing)
void SwapScreenBuffer(void)
{
- eglSwapBuffers(platform.device, platform.surface);
+ if (platform.surface != EGL_NO_SURFACE) eglSwapBuffers(platform.device, platform.surface);
}
//----------------------------------------------------------------------------------
@@ -741,8 +744,8 @@ void PollInputEvents(void)
int pollEvents = 0;
// Poll Events (registered events) until we reach TIMEOUT which indicates there are no events left to poll
- // NOTE: Activity is paused if not enabled (platform.appEnabled)
- while ((pollResult = ALooper_pollOnce(platform.appEnabled? 0 : -1, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT))
+ // NOTE: Activity is paused if not enabled (platform.appEnabled) and always run flag is not set (FLAG_WINDOW_ALWAYS_RUN)
+ while ((pollResult = ALooper_pollOnce((platform.appEnabled || FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN))? 0 : -1, NULL, &pollEvents, ((void **)&platform.source)) > ALOOPER_POLL_TIMEOUT))
{
// Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
@@ -1042,7 +1045,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
- isGpuReady = true;
// Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
@@ -1164,8 +1166,8 @@ static GamepadButton AndroidTranslateGamepadButton(int button)
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
{
// If additional inputs are required check:
- // Ref: https://developer.android.com/ndk/reference/group/input
- // Ref: https://developer.android.com/training/game-controllers/controller-input
+ // REF: https://developer.android.com/ndk/reference/group/input
+ // REF: https://developer.android.com/training/game-controllers/controller-input
int type = AInputEvent_getType(event);
int source = AInputEvent_getSource(event);
diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c
index a56e1c683..efa146fd0 100644
--- a/src/platforms/rcore_desktop_glfw.c
+++ b/src/platforms/rcore_desktop_glfw.c
@@ -130,16 +130,17 @@ int InitPlatform(void); // Initialize platform (graphics, inputs and mo
void ClosePlatform(void); // Close platform
// Error callback event
-static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
+static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
// Window callbacks events
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
-static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved
+static void FramebufferSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 FramebufferSize Callback, runs when window is resized
+static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale
+static void WindowPosCallback(GLFWwindow *window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
-static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
+static void WindowMaximizeCallback(GLFWwindow *window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window
-static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale
// Input callbacks events
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
@@ -155,8 +156,6 @@ static void *AllocateWrapper(size_t size, void *user);
static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_REALLOC macro
static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro
-static void SetDimensionsFromMonitor(GLFWmonitor *monitor); // Set screen dimensions from monitor/display dimensions
-
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
@@ -205,7 +204,6 @@ void ToggleFullscreen(void)
glfwSetWindowMonitor(platform.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
}
-
}
else
{
@@ -231,22 +229,22 @@ void ToggleBorderlessWindowed(void)
bool wasOnFullscreen = false;
if (CORE.Window.fullscreen)
{
- // fullscreen already saves the previous position so it does not need to be set here again
+ // Fullscreen already saves the previous position so it does not need to be set here again
ToggleFullscreen();
wasOnFullscreen = true;
}
- const int monitor = GetCurrentMonitor();
- int monitorCount;
+ int monitorCount = 0;
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
+ const int monitor = GetCurrentMonitor();
if ((monitor >= 0) && (monitor < monitorCount))
{
const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
- if (mode)
+ if (mode != NULL)
{
- if (!IsWindowState(FLAG_BORDERLESS_WINDOWED_MODE))
+ if (!FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE))
{
// Store screen position and size
// NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here
@@ -265,8 +263,15 @@ void ToggleBorderlessWindowed(void)
const int monitorHeight = mode->height;
// Set screen position and size
- glfwSetWindowPos(platform.handle, monitorPosX, monitorPosY);
- glfwSetWindowSize(platform.handle, monitorWidth, monitorHeight);
+ glfwSetWindowMonitor(
+ platform.handle,
+ monitors[monitor],
+ monitorPosX,
+ monitorPosY,
+ monitorWidth,
+ monitorHeight,
+ mode->refreshRate
+ );
// Refocus window
glfwFocusWindow(platform.handle);
@@ -279,10 +284,27 @@ void ToggleBorderlessWindowed(void)
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNDECORATED);
+ #if !defined(__APPLE__)
+ // Make sure to restore size to HighDPI
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
+ {
+ Vector2 scaleDpi = GetWindowScaleDPI();
+ CORE.Window.previousScreen.width *= scaleDpi.x;
+ CORE.Window.previousScreen.height *= scaleDpi.y;
+ }
+ #endif
+
// Return previous screen size and position
// NOTE: The order matters here, it must set size first, then set position, otherwise the screen will be positioned incorrectly
- glfwSetWindowSize(platform.handle, CORE.Window.previousScreen.width, CORE.Window.previousScreen.height);
- glfwSetWindowPos(platform.handle, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y);
+ glfwSetWindowMonitor(
+ platform.handle,
+ NULL,
+ CORE.Window.previousPosition.x,
+ CORE.Window.previousPosition.y,
+ CORE.Window.previousScreen.width,
+ CORE.Window.previousScreen.height,
+ mode->refreshRate
+ );
// Refocus window
glfwFocusWindow(platform.handle);
@@ -461,13 +483,13 @@ void ClearWindowState(unsigned int flags)
// NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running
if ((FLAG_IS_SET(CORE.Window.flags, FLAG_BORDERLESS_WINDOWED_MODE)) && (FLAG_IS_SET(flags, FLAG_BORDERLESS_WINDOWED_MODE)))
{
- ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function
+ ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function
}
// State change: FLAG_FULLSCREEN_MODE
if ((FLAG_IS_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE)) && (FLAG_IS_SET(flags, FLAG_FULLSCREEN_MODE)))
{
- ToggleFullscreen(); // NOTE: Window state flag updated inside function
+ ToggleFullscreen(); // NOTE: Window state flag updated inside function
}
// State change: FLAG_WINDOW_RESIZABLE
@@ -880,7 +902,8 @@ Vector2 GetMonitorPosition(int monitor)
if ((monitor >= 0) && (monitor < monitorCount))
{
- int x, y;
+ int x = 0;
+ int y = 0;
glfwGetMonitorPos(monitors[monitor], &x, &y);
return (Vector2){ (float)x, (float)y };
@@ -1001,8 +1024,8 @@ Vector2 GetWindowPosition(void)
// Get window scale DPI factor for current monitor
Vector2 GetWindowScaleDPI(void)
{
- Vector2 scale = { 0 };
- glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y);
+ Vector2 scale = { 1.0f, 1.0f };
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y);
return scale;
}
@@ -1108,7 +1131,7 @@ double GetTime(void)
// NOTE: This function is only safe to use if you control the URL given
// A user could craft a malicious string performing another action
// Only call this function yourself not with user input or make sure to check the string yourself
-// Ref: https://github.com/raysan5/raylib/issues/686
+// REF: https://github.com/raysan5/raylib/issues/686
void OpenURL(const char *url)
{
// Security check to (partially) avoid malicious code
@@ -1220,8 +1243,8 @@ void PollInputEvents(void)
// Map touch position to mouse position for convenience
// WARNING: If the target desktop device supports touch screen, this behaviour should be reviewed!
// TODO: GLFW does not support multi-touch input yet
- // Ref: https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch
- // Ref: https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages
+ // REF: https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch
+ // REF: https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
// Check if gamepads are ready
@@ -1314,7 +1337,8 @@ void PollInputEvents(void)
CORE.Window.resizedLastFrame = false;
- if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)))
+ if ((CORE.Window.eventWaiting) ||
+ (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) && !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN)))
{
glfwWaitEvents(); // Wait for in input events before continue (drawing is paused)
CORE.Time.previous = GetTime();
@@ -1333,7 +1357,7 @@ void PollInputEvents(void)
// Function wrappers around RL_*alloc macros, used by glfwInitAllocator() inside of InitPlatform()
// We need to provide these because GLFWallocator expects function pointers with specific signatures
// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch
-// Ref: https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
+// REF: https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
static void *AllocateWrapper(size_t size, void *user)
{
(void)user;
@@ -1419,31 +1443,27 @@ int InitPlatform(void)
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_TRANSPARENT)) glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); // Transparent framebuffer
else glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE); // Opaque framebuffer
- // HACK: Most of this was written before GLFW_SCALE_FRAMEBUFFER existed and
- // was enabled by default. Disabling it gets back the old behavior. A
- // complete fix will require removing a lot of CORE.Window.render
- // manipulation code
- // NOTE: This currently doesn't work on macOS(see #5185), so we skip it there
- // when FLAG_WINDOW_HIGHDPI is *unset*
-#if !defined(__APPLE__)
- glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
-#endif
-
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
- // since we skipped it before, now make sure to set this on macOS
#if defined(__APPLE__)
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
#endif
// Resize window content area based on the monitor content scale
- // NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11
+ // NOTE: This hint only has an effect on platforms where screen coordinates and
+ // pixels always map 1:1 such as Windows and X11
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size
- glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on
+ glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
#if defined(__APPLE__)
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
#endif
}
- else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
+ else
+ {
+ glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
+#if defined(__APPLE__)
+ glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
+#endif
+ }
// Mouse passthrough
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
@@ -1513,17 +1533,24 @@ int InitPlatform(void)
GLFWmonitor *monitor = NULL;
if (CORE.Window.fullscreen)
{
- // According to glfwCreateWindow(), if the user does not have a choice, fullscreen applications
- // should default to the primary monitor
-
+ // NOTE: Fullscreen applications default to the primary monitor
monitor = glfwGetPrimaryMonitor();
if (!monitor)
{
- TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor");
- return -1;
+ TRACELOG(LOG_WARNING, "GLFW: Failed to get primary monitor");
+ return -1;
}
- SetDimensionsFromMonitor(monitor);
+ // Set dimensions from monitor
+ const GLFWvidmode *mode = glfwGetVideoMode(monitor);
+
+ // Default display resolution to that of the current mode
+ CORE.Window.display.width = mode->width;
+ CORE.Window.display.height = mode->height;
+
+ // Set screen width/height to the display width/height if they are 0
+ if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
+ if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
// Remember center for switching from fullscreen to window
if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width))
@@ -1612,7 +1639,15 @@ int InitPlatform(void)
if (monitorIndex < monitorCount)
{
monitor = monitors[monitorIndex];
- SetDimensionsFromMonitor(monitor);
+ const GLFWvidmode *mode = glfwGetVideoMode(monitor);
+
+ // Default display resolution to that of the current mode
+ CORE.Window.display.width = mode->width;
+ CORE.Window.display.height = mode->height;
+
+ // Set screen width/height to the display width/height if they are 0
+ if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
+ if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
if (requestWindowedFullscreen) glfwSetWindowSize(platform.handle, CORE.Window.screen.width, CORE.Window.screen.height);
}
@@ -1624,6 +1659,7 @@ int InitPlatform(void)
return -1;
}
+ // NOTE: Not considering scale factor now, considered below
CORE.Window.render.width = CORE.Window.screen.width;
CORE.Window.render.height = CORE.Window.screen.height;
}
@@ -1654,16 +1690,15 @@ int InitPlatform(void)
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling
- // Framebuffer scaling should be activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
- #if !defined(__APPLE__)
+ // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);
// Screen scaling matrix is required in case desired screen area is different from display area
CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f);
-
+#if !defined(__APPLE__)
// Mouse input scaling for the new screen size
SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight);
- #endif
+#endif
}
CORE.Window.render.width = fbWidth;
@@ -1720,28 +1755,24 @@ int InitPlatform(void)
// Initialize input events callbacks
//----------------------------------------------------------------------------
// Set window callback events
- glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default!
+ glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing is not enabled by default
+ glfwSetFramebufferSizeCallback(platform.handle, FramebufferSizeCallback);
glfwSetWindowPosCallback(platform.handle, WindowPosCallback);
glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback);
glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback);
glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);
glfwSetDropCallback(platform.handle, WindowDropCallback);
-
- if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
- {
- glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
- }
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) glfwSetWindowContentScaleCallback(platform.handle, WindowContentScaleCallback);
// Set input callback events
glfwSetKeyCallback(platform.handle, KeyCallback);
glfwSetCharCallback(platform.handle, CharCallback);
glfwSetMouseButtonCallback(platform.handle, MouseButtonCallback);
- glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback); // Track mouse position changes
+ glfwSetCursorPosCallback(platform.handle, MouseCursorPosCallback); // Track mouse position changes
glfwSetScrollCallback(platform.handle, MouseScrollCallback);
glfwSetCursorEnterCallback(platform.handle, CursorEnterCallback);
glfwSetJoystickCallback(JoystickCallback);
-
- glfwSetInputMode(platform.handle, GLFW_LOCK_KEY_MODS, GLFW_TRUE); // Enable lock keys modifiers (CAPS, NUM)
+ glfwSetInputMode(platform.handle, GLFW_LOCK_KEY_MODS, GLFW_TRUE); // Enable lock keys modifiers (CAPS, NUM)
// Retrieve gamepad names
for (int i = 0; i < MAX_GAMEPADS; i++)
@@ -1799,79 +1830,116 @@ void ClosePlatform(void)
#endif
}
-// GLFW3 Error Callback, runs on GLFW3 error
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+// NOTE: Those functions are only required for current platform
+//----------------------------------------------------------------------------------
+
+// GLFW3: Error callback, runs on GLFW3 error
static void ErrorCallback(int error, const char *description)
{
TRACELOG(LOG_WARNING, "GLFW: Error: %i Description: %s", error, description);
}
-// GLFW3 WindowSize Callback, runs when window is resizedLastFrame
+// GLFW3: Window size change callback, runs when window is resized
// NOTE: Window resizing not enabled by default, use SetConfigFlags()
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
{
+ // Nothing to do for now on window resize...
+ //TRACELOG(LOG_INFO, "GLFW3: Window size callback called [%i,%i]", width, height);
+}
+
+// GLFW3: Framebuffer size change callback, runs when framebuffer is resized
+// WARNING: If FLAG_WINDOW_HIGHDPI is set, WindowContentScaleCallback() is called before this function
+static void FramebufferSizeCallback(GLFWwindow *window, int width, int height)
+{
+ //TRACELOG(LOG_INFO, "GLFW3: Window framebuffer size callback called [%i,%i]", width, height);
+
// WARNING: On window minimization, callback is called,
// but we don't want to change internal screen values, it breaks things
if ((width == 0) || (height == 0)) return;
// Reset viewport and projection matrix for new size
+ // NOTE: Stores current render size: CORE.Window.render
SetupViewport(width, height);
+ // Set render size
CORE.Window.currentFbo.width = width;
CORE.Window.currentFbo.height = height;
CORE.Window.resizedLastFrame = true;
- if (IsWindowFullscreen()) return;
-
- // if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
- if (IsWindowState(FLAG_WINDOW_HIGHDPI))
+ // Check if render size was actually scaled for high-dpi
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
- width = (int)(width/GetWindowScaleDPI().x);
- height = (int)(height/GetWindowScaleDPI().y);
+ // Set screen size to logical pixel size, considering content scaling
+ Vector2 scaleDpi = GetWindowScaleDPI();
+ CORE.Window.screen.width = (int)((float)width/scaleDpi.x);
+ CORE.Window.screen.height = (int)((float)height/scaleDpi.y);
+ }
+ else
+ {
+ // Set screen size to render size (physical pixel size)
+ CORE.Window.screen.width = width;
+ CORE.Window.screen.height = height;
}
-
- // Set render size
- CORE.Window.render.width = width;
- CORE.Window.render.height = height;
-
- // Set current screen size
- CORE.Window.screen.width = width;
- CORE.Window.screen.height = height;
// WARNING: If using a render texture, it is not scaled to new size
}
-static void WindowPosCallback(GLFWwindow* window, int x, int y)
+
+// GLFW3: Window content scale callback, runs on monitor content scale change detected
+// WARNING: If FLAG_WINDOW_HIGHDPI is not set, this function is not called
+static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley)
+{
+ TRACELOG(LOG_INFO, "GLFW3: Window content scale changed, scale: [%.2f,%.2f]", scalex, scaley);
+
+ float fbWidth = (float)CORE.Window.screen.width*scalex;
+ float fbHeight = (float)CORE.Window.screen.height*scaley;
+
+ // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling
+ // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
+ CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
+
+#if !defined(__APPLE__)
+ // Mouse input scaling for the new screen size
+ SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight);
+#endif
+
+ CORE.Window.render.width = (int)fbWidth;
+ CORE.Window.render.height = (int)fbHeight;
+ CORE.Window.currentFbo.width = (int)fbWidth;
+ CORE.Window.currentFbo.height = (int)fbHeight;
+}
+
+// GLFW3: Window position callback, runs when window position changes
+static void WindowPosCallback(GLFWwindow *window, int x, int y)
{
// Set current window position
CORE.Window.position.x = x;
CORE.Window.position.y = y;
}
-static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley)
-{
- CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
-}
-// GLFW3 WindowIconify Callback, runs when window is minimized/restored
+// GLFW3: Window iconify callback, runs when window is minimized/restored
static void WindowIconifyCallback(GLFWwindow *window, int iconified)
{
if (iconified) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was iconified
else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was restored
}
-// GLFW3 WindowMaximize Callback, runs when window is maximized/restored
+// GLFW3: Window maximize callback, runs when window is maximized/restored
static void WindowMaximizeCallback(GLFWwindow *window, int maximized)
{
if (maximized) FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was maximized
else FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was restored
}
-// GLFW3 WindowFocus Callback, runs when window get/lose focus
+// GLFW3: Window focus callback, runs when window get/lose focus
static void WindowFocusCallback(GLFWwindow *window, int focused)
{
if (focused) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // The window was focused
else FLAG_SET(CORE.Window.flags, FLAG_WINDOW_UNFOCUSED); // The window lost focus
}
-// GLFW3 Window Drop Callback, runs when drop files into window
+// GLFW3: Window drop callback, runs when files are dropped into window
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths)
{
if (count > 0)
@@ -1899,7 +1967,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
}
}
-// GLFW3 Keyboard Callback, runs on key pressed
+// GLFW3: Keyboard callback, runs on key pressed
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
{
if (key < 0) return; // Security check, macOS fn key generates -1
@@ -1926,13 +1994,13 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
if ((key == CORE.Input.Keyboard.exitKey) && (action == GLFW_PRESS)) glfwSetWindowShouldClose(platform.handle, GLFW_TRUE);
}
-// GLFW3 Char Callback, get unicode codepoint value
+// GLFW3: Char callback, runs on key pressed to get unicode codepoint value
static void CharCallback(GLFWwindow *window, unsigned int codepoint)
{
// NOTE: Registers any key down considering OS keyboard layout but
// does not detect action events, those should be managed by user...
- // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
- // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char
+ // REF: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
+ // REF: https://www.glfw.org/docs/latest/input_guide.html#input_char
// Check if there is space available in the queue
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
@@ -1943,7 +2011,7 @@ static void CharCallback(GLFWwindow *window, unsigned int codepoint)
}
}
-// GLFW3 Mouse Button Callback, runs on mouse button pressed
+// GLFW3: Mouse button callback, runs on mouse button pressed
static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
{
// WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now,
@@ -1979,7 +2047,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
#endif
}
-// GLFW3 Cursor Position Callback, runs on mouse move
+// GLFW3: Cursor position callback, runs on mouse movement
static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
{
CORE.Input.Mouse.currentPosition.x = (float)x;
@@ -2010,20 +2078,20 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
#endif
}
-// GLFW3 Scrolling Callback, runs on mouse wheel
+// GLFW3: Mouse wheel scroll callback, runs on mouse wheel changes
static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset)
{
CORE.Input.Mouse.currentWheelMove = (Vector2){ (float)xoffset, (float)yoffset };
}
-// GLFW3 CursorEnter Callback, when cursor enters the window
+// GLFW3: Cursor ennter callback, when cursor enters the window
static void CursorEnterCallback(GLFWwindow *window, int enter)
{
if (enter) CORE.Input.Mouse.cursorOnScreen = true;
else CORE.Input.Mouse.cursorOnScreen = false;
}
-// GLFW3 Joystick Connected/Disconnected Callback
+// GLFW3: Joystick connected/disconnected callback
static void JoystickCallback(int jid, int event)
{
if (event == GLFW_CONNECTED)
@@ -2039,20 +2107,6 @@ static void JoystickCallback(int jid, int event)
}
}
-// Set screen dimensions from monitor/display dimensions
-static void SetDimensionsFromMonitor(GLFWmonitor *monitor)
-{
- const GLFWvidmode *mode = glfwGetVideoMode(monitor);
-
- // Default display resolution to that of the current mode
- CORE.Window.display.width = mode->width;
- CORE.Window.display.height = mode->height;
-
- // Set screen width/height to the display width/height if they are 0
- if (CORE.Window.screen.width == 0) CORE.Window.screen.width = CORE.Window.display.width;
- if (CORE.Window.screen.height == 0) CORE.Window.screen.height = CORE.Window.display.height;
-}
-
#ifdef _WIN32
# define WIN32_CLIPBOARD_IMPLEMENTATION
# include "../external/win32_clipboard.h"
diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c
index a1b13856b..2671538d8 100644
--- a/src/platforms/rcore_desktop_rgfw.c
+++ b/src/platforms/rcore_desktop_rgfw.c
@@ -48,11 +48,6 @@
*
**********************************************************************************************/
-#ifndef RAYLIB_H /* this should never actually happen, it's only here for IDEs */
-#include "raylib.h"
-#include "../rcore.c"
-#endif
-
#if defined(PLATFORM_WEB_RGFW)
#define RGFW_NO_GL_HEADER
#endif
diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c
index 36235a6c8..add1de6ad 100644
--- a/src/platforms/rcore_desktop_sdl.c
+++ b/src/platforms/rcore_desktop_sdl.c
@@ -57,7 +57,7 @@
// SDL base library (window/rendered, input, timing... functionality)
#ifdef USING_SDL3_PROJECT
#include "SDL3/SDL.h"
-#elif USING_SDL2_PROJECT
+#elif defined(USING_SDL2_PROJECT)
#include "SDL2/SDL.h"
#else
#include "SDL.h"
@@ -71,7 +71,7 @@
// SDL OpenGL functionality (if required, instead of internal renderer)
#ifdef USING_SDL3_PROJECT
#include "SDL3/SDL_opengl.h"
- #elif USING_SDL2_PROJECT
+ #elif defined(USING_SDL2_PROJECT)
#include "SDL2/SDL_opengl.h"
#else
#include "SDL_opengl.h"
@@ -679,6 +679,7 @@ void ClearWindowState(unsigned int flags)
{
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_TRANSPARENT is not supported on PLATFORM_DESKTOP_SDL");
}
+ if (FLAG_IS_SET(flags, FLAG_WINDOW_HIGHDPI))
{
// NOTE: There also doesn't seem to be a feature to disable high DPI once enabled
TRACELOG(LOG_WARNING, "ClearWindowState() - FLAG_WINDOW_HIGHDPI is not supported on PLATFORM_DESKTOP_SDL");
@@ -1041,7 +1042,7 @@ int GetMonitorPhysicalWidth(int monitor)
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
// Calculate size on inches, then convert to millimeter
- if (ddpi > 0.0f) width = (mode.w/ddpi)*25.4f;
+ if (ddpi > 0.0f) width = (int)((mode.w/ddpi)*25.4f);
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
@@ -1065,7 +1066,7 @@ int GetMonitorPhysicalHeight(int monitor)
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
// Calculate size on inches, then convert to millimeter
- if (ddpi > 0.0f) height = (mode.h/ddpi)*25.4f;
+ if (ddpi > 0.0f) height = (int)((mode.h/ddpi)*25.4f);
}
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
@@ -1127,14 +1128,15 @@ Vector2 GetWindowScaleDPI(void)
{
Vector2 scale = { 1.0f, 1.0f };
-#ifndef USING_VERSION_SDL3
- // NOTE: SDL_GetWindowDisplayScale was only added on SDL3
- // Ref: https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
- // TODO: Implement the window scale factor calculation manually
- TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
-#else
+#if defined(USING_VERSION_SDL3)
+ // NOTE: SDL_GetWindowDisplayScale added on SDL3
+ // REF: https://wiki.libsdl.org/SDL3/SDL_GetWindowDisplayScale
scale.x = SDL_GetWindowDisplayScale(platform.window);
scale.y = scale.x;
+#else
+ // NOTE: SDL_GetWindowDisplayScale not available on SDL2
+ // TODO: Implement the window scale factor calculation manually
+ TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform");
#endif
return scale;
@@ -1195,7 +1197,7 @@ Image GetClipboardImage(void)
if (fileData)
{
- image = LoadImageFromMemory(imageExtensions[i], fileData, dataSize);
+ image = LoadImageFromMemory(imageExtensions[i], fileData, (int)dataSize);
if (IsImageValid(image))
{
TRACELOG(LOG_INFO, "Clipboard: Got image from clipboard successfully: %s", imageExtensions[i]);
@@ -1279,7 +1281,7 @@ double GetTime(void)
// NOTE: This function is only safe to use if you control the URL given
// A user could craft a malicious string performing another action
// Only call this function yourself not with user input or make sure to check the string yourself
-// Ref: https://github.com/raysan5/raylib/issues/686
+// REF: https://github.com/raysan5/raylib/issues/686
void OpenURL(const char *url)
{
// Security check to (partially) avoid malicious code
@@ -1454,7 +1456,7 @@ void PollInputEvents(void)
} break;
- // Window events are also polled (Minimized, maximized, close...)
+ // Window events are also polled (minimized, maximized, close...)
#ifndef USING_VERSION_SDL3
// SDL3 states:
@@ -1473,7 +1475,7 @@ void PollInputEvents(void)
const int height = event.window.data2;
SetupViewport(width, height);
// if we are doing automatic DPI scaling, then the "screen" size is divided by the window scale
- if (IsWindowState(FLAG_WINDOW_HIGHDPI))
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{
CORE.Window.screen.width = (int)(width/GetWindowScaleDPI().x);
CORE.Window.screen.height = (int)(height/GetWindowScaleDPI().y);
@@ -1488,7 +1490,8 @@ void PollInputEvents(void)
CORE.Window.resizedLastFrame = true;
#ifndef USING_VERSION_SDL3
- // Manually detect if the window was maximized (due to SDL2 restore being unreliable on some platforms) to remove the FLAG_WINDOW_MAXIMIZED accordingly
+ // Manually detect if the window was maximized (due to SDL2 restore being unreliable on some platforms)
+ // to remove the FLAG_WINDOW_MAXIMIZED accordingly
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED))
{
int borderTop = 0;
@@ -1504,14 +1507,8 @@ void PollInputEvents(void)
#endif
} break;
- case SDL_WINDOWEVENT_ENTER:
- {
- CORE.Input.Mouse.cursorOnScreen = true;
- } break;
- case SDL_WINDOWEVENT_LEAVE:
- {
- CORE.Input.Mouse.cursorOnScreen = false;
- } break;
+ case SDL_WINDOWEVENT_ENTER: CORE.Input.Mouse.cursorOnScreen = true; break;
+ case SDL_WINDOWEVENT_LEAVE: CORE.Input.Mouse.cursorOnScreen = false; break;
case SDL_WINDOWEVENT_MINIMIZED:
{
@@ -1750,7 +1747,11 @@ void PollInputEvents(void)
{
int button = -1;
+ #if defined(USING_VERSION_SDL3)
switch (event.gbutton.button)
+ #else
+ switch (event.jbutton.button)
+ #endif
{
case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
@@ -1778,7 +1779,11 @@ void PollInputEvents(void)
{
for (int i = 0; i < MAX_GAMEPADS; i++)
{
+ #if defined(USING_VERSION_SDL3)
if (platform.gamepadId[i] == event.gbutton.which)
+ #else
+ if (platform.gamepadId[i] == event.jbutton.which)
+ #endif
{
CORE.Input.Gamepad.currentButtonState[i][button] = 1;
CORE.Input.Gamepad.lastButtonPressed = button;
@@ -1791,7 +1796,11 @@ void PollInputEvents(void)
{
int button = -1;
+ #if defined(USING_VERSION_SDL3)
switch (event.gbutton.button)
+ #else
+ switch (event.jbutton.button)
+ #endif
{
case SDL_CONTROLLER_BUTTON_Y: button = GAMEPAD_BUTTON_RIGHT_FACE_UP; break;
case SDL_CONTROLLER_BUTTON_B: button = GAMEPAD_BUTTON_RIGHT_FACE_RIGHT; break;
@@ -1819,7 +1828,11 @@ void PollInputEvents(void)
{
for (int i = 0; i < MAX_GAMEPADS; i++)
{
+ #if defined(USING_VERSION_SDL3)
if (platform.gamepadId[i] == event.gbutton.which)
+ #else
+ if (platform.gamepadId[i] == event.jbutton.which)
+ #endif
{
CORE.Input.Gamepad.currentButtonState[i][button] = 0;
if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
@@ -2054,28 +2067,23 @@ int InitPlatform(void)
platform.gamepadId[i] = -1; // Set all gamepad initial instance ids as invalid to not conflict with instance id zero
}
- int numJoysticks = 0;
- SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks); // array of joystick IDs, they do not start from 0
+ int numJoysticks = SDL_NumJoysticks();
- if (joysticks)
+ for (int i = 0; (i < numJoysticks) && (i < MAX_GAMEPADS); i++)
{
- for (int i = 0; (i < numJoysticks) && (i < MAX_GAMEPADS); i++)
- {
- platform.gamepad[i] = SDL_GameControllerOpen(joysticks[i]);
- platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i]));
+ platform.gamepad[i] = SDL_GameControllerOpen(i);
+ platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i]));
- if (platform.gamepad[i])
- {
- CORE.Input.Gamepad.ready[i] = true;
- CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i]));
- CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
- CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
- strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), MAX_GAMEPAD_NAME_LENGTH - 1);
- CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
- }
- else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
+ if (platform.gamepad[i])
+ {
+ CORE.Input.Gamepad.ready[i] = true;
+ CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i]));
+ CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
+ CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
+ strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), MAX_GAMEPAD_NAME_LENGTH - 1);
+ CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
}
- SDL_free(joysticks);
+ else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError());
}
// Disable mouse events being interpreted as touch events
@@ -2196,7 +2204,7 @@ static void UpdateTouchPointsSDL(SDL_TouchFingerEvent event)
for (int i = 0; i < CORE.Input.Touch.pointCount; i++)
{
SDL_Finger *finger = SDL_GetTouchFinger(event.touchId, i);
- CORE.Input.Touch.pointId[i] = finger->id;
+ CORE.Input.Touch.pointId[i] = (int)finger->id;
CORE.Input.Touch.position[i].x = finger->x*CORE.Window.screen.width;
CORE.Input.Touch.position[i].y = finger->y*CORE.Window.screen.height;
CORE.Input.Touch.currentTouchState[i] = 1;
diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c
index 8a4050332..29702921f 100644
--- a/src/platforms/rcore_desktop_win32.c
+++ b/src/platforms/rcore_desktop_win32.c
@@ -1239,7 +1239,7 @@ double GetTime(void)
// NOTE: This function is only safe to use if you control the URL given
// A user could craft a malicious string performing another action
// Only call this function yourself not with user input or make sure to check the string yourself
-// Ref: https://github.com/raysan5/raylib/issues/686
+// REF: https://github.com/raysan5/raylib/issues/686
void OpenURL(const char *url)
{
// Security check to (partially) avoid malicious code on target platform
diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c
index 881f96034..640799b0a 100644
--- a/src/platforms/rcore_drm.c
+++ b/src/platforms/rcore_drm.c
@@ -220,7 +220,7 @@ static const short linuxToRaylibMap[KEYMAP_SIZE] = {
248, 0, 0, 0, 0, 0, 0, 0,
// Gamepads are mapped according to:
- // Ref: https://www.kernel.org/doc/html/next/input/gamepad.html
+ // REF: https://www.kernel.org/doc/html/next/input/gamepad.html
// Those mappings are standardized, but that doesn't mean people follow
// the standards, so this is more of an approximation
[BTN_DPAD_UP] = GAMEPAD_BUTTON_LEFT_FACE_UP,
@@ -1013,7 +1013,7 @@ double GetTime(void)
// NOTE: This function is only safe to use if you control the URL given
// A user could craft a malicious string performing another action
// Only call this function yourself not with user input or make sure to check the string yourself
-// Ref: https://github.com/raysan5/raylib/issues/686
+// REF: https://github.com/raysan5/raylib/issues/686
void OpenURL(const char *url)
{
TRACELOG(LOG_WARNING, "OpenURL() not implemented on target platform");
@@ -1865,7 +1865,7 @@ static void ProcessKeyboard(void)
}
#endif // SUPPORT_SSH_KEYBOARD_RPI
-// Initialise user input from evdev(/dev/input/event)
+// Initialize user input from evdev(/dev/input/event)
// this means mouse, keyboard or gamepad devices
static void InitEvdevInput(void)
{
@@ -1873,7 +1873,7 @@ static void InitEvdevInput(void)
DIR *directory = NULL;
struct dirent *entity = NULL;
- // Initialise keyboard file descriptor
+ // Initialize keyboard file descriptor
platform.keyboardFd = -1;
platform.mouseFd = -1;
diff --git a/src/platforms/rcore_memory.c b/src/platforms/rcore_memory.c
index e49159a85..1b7a55fd8 100644
--- a/src/platforms/rcore_memory.c
+++ b/src/platforms/rcore_memory.c
@@ -371,7 +371,6 @@ double GetTime(void)
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;
@@ -384,7 +383,7 @@ double GetTime(void)
// NOTE: This function is only safe to use if you control the URL given.
// A user could craft a malicious string performing another action.
// Only call this function yourself not with user input or make sure to check the string yourself.
-// Ref: https://github.com/raysan5/raylib/issues/686
+// REF: https://github.com/raysan5/raylib/issues/686
void OpenURL(const char *url)
{
// Security check to (partially) avoid malicious code on target platform
@@ -429,7 +428,7 @@ void SetMouseCursor(int cursor)
TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform");
}
-// Get physical key name.
+// Get physical key name
const char *GetKeyName(int key)
{
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c
index bc03a3cdb..1f8c5242b 100644
--- a/src/platforms/rcore_template.c
+++ b/src/platforms/rcore_template.c
@@ -54,11 +54,6 @@
typedef struct {
// TODO: Define the platform specific variables required
- // Display data
- EGLDisplay device; // Native display device (physical screen connection)
- EGLSurface surface; // Surface to draw on, framebuffers (connected to context)
- EGLContext context; // Graphic context, mode in which drawing can be done
- EGLConfig config; // Graphic config
} PlatformData;
//----------------------------------------------------------------------------------
@@ -346,10 +341,10 @@ void SwapScreenBuffer(void)
double GetTime(void)
{
double time = 0.0;
+
struct timespec ts = { 0 };
clock_gettime(CLOCK_MONOTONIC, &ts);
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
-
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
return time;
@@ -366,7 +361,7 @@ void OpenURL(const char *url)
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
else
{
- // TODO:
+ // TODO: Load url using default browser
}
}
@@ -462,86 +457,18 @@ int InitPlatform(void)
CORE.Window.fullscreen = true;
FLAG_SET(CORE.Window.flags, FLAG_FULLSCREEN_MODE);
- EGLint samples = 0;
- EGLint sampleBuffer = 0;
if (FLAG_IS_SET(CORE.Window.flags, FLAG_MSAA_4X_HINT))
{
- samples = 4;
- sampleBuffer = 1;
+ // TODO: Enable MSAA
+
TRACELOG(LOG_INFO, "DISPLAY: Trying to enable MSAA x4");
}
- const EGLint framebufferAttribs[] =
- {
- EGL_RENDERABLE_TYPE, (rlGetVersion() == RL_OPENGL_ES_30)? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT, // Type of context support
- EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5)
- EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6)
- EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5)
- //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI)
- EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!)
- //EGL_STENCIL_SIZE, 8, // Stencil buffer size
- EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA
- EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs)
- EGL_NONE
- };
+ // TODO: Init display and graphic device
- const EGLint contextAttribs[] =
- {
- EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL_NONE
- };
-
- EGLint numConfigs = 0;
-
- // Get an EGL device connection
- platform.device = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (platform.device == EGL_NO_DISPLAY)
- {
- TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
- return false;
- }
-
- // Initialize the EGL device connection
- if (eglInitialize(platform.device, NULL, NULL) == EGL_FALSE)
- {
- // If all of the calls to eglInitialize returned EGL_FALSE then an error has occurred.
- TRACELOG(LOG_WARNING, "DISPLAY: Failed to initialize EGL device");
- return false;
- }
-
- // Get an appropriate EGL framebuffer configuration
- eglChooseConfig(platform.device, framebufferAttribs, &platform.config, 1, &numConfigs);
-
- // Set rendering API
- eglBindAPI(EGL_OPENGL_ES_API);
-
- // Create an EGL rendering context
- platform.context = eglCreateContext(platform.device, platform.config, EGL_NO_CONTEXT, contextAttribs);
- if (platform.context == EGL_NO_CONTEXT)
- {
- TRACELOG(LOG_WARNING, "DISPLAY: Failed to create EGL context");
- return -1;
- }
-
- // Create an EGL window surface
- EGLint displayFormat = 0;
-
- // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is guaranteed to be accepted by ANativeWindow_setBuffersGeometry()
- // As soon as we picked a EGLConfig, we can safely reconfigure the ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID
- eglGetConfigAttrib(platform.device, platform.config, EGL_NATIVE_VISUAL_ID, &displayFormat);
-
- // Android specific call
- ANativeWindow_setBuffersGeometry(platform.app->window, 0, 0, displayFormat); // Force use of native display size
-
- platform.surface = eglCreateWindowSurface(platform.device, platform.config, platform.app->window, NULL);
-
- // There must be at least one frame displayed before the buffers are swapped
- eglSwapInterval(platform.device, 1);
-
- EGLBoolean result = eglMakeCurrent(platform.device, platform.surface, platform.surface, platform.context);
-
- // Check surface and context activation
- if (result != EGL_FALSE)
+ // TODO: Check display, device and context activation
+ bool result = true;
+ if (result)
{
CORE.Window.ready = true;
diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c
index 2d2f8d1c0..934f778c3 100644
--- a/src/platforms/rcore_web.c
+++ b/src/platforms/rcore_web.c
@@ -76,6 +76,13 @@ typedef struct {
bool ourFullscreen; // Internal var to filter our handling of fullscreen vs the user handling of fullscreen
int unmaximizedWidth; // Internal var to store the unmaximized window (canvas) width
int unmaximizedHeight; // Internal var to store the unmaximized window (canvas) height
+
+ char canvasId[64]; // Keep current canvas id where wasm app is running
+ // NOTE: Useful when trying to run multiple wasms in different canvases in same webpage
+
+#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+ unsigned int *pixels; // Pointer to pixel data buffer (RGBA 32bit format)
+#endif
} PlatformData;
//----------------------------------------------------------------------------------
@@ -129,7 +136,7 @@ static void MouseEnterCallback(GLFWwindow *window, int enter);
// Emscripten window callback events
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *event, void *userData);
-// static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
+//static EM_BOOL EmscriptenWindowResizedCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *event, void *userData);
static EM_BOOL EmscriptenFocusCallback(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData);
static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData);
@@ -142,7 +149,11 @@ static EM_BOOL EmscriptenPointerlockCallback(int eventType, const EmscriptenPoin
static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
-static const char *GetCanvasId(void);
+// JS: Set the canvas id provided by the module configuration
+EM_JS(void, SetCanvasIdJs, (char *out, int outSize), {
+ var canvasId = "#" + Module.canvas.id;
+ stringToUTF8(canvasId, out, outSize);
+});
//----------------------------------------------------------------------------------
// Module Functions Declaration
@@ -159,7 +170,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,
@@ -233,11 +244,11 @@ void ToggleFullscreen(void)
// This option does not seem to work at all:
// emscripten_request_pointerlock() and emscripten_request_fullscreen() are affected by web security,
// the user must click once on the canvas to hide the pointer or transition to full screen
- //emscripten_request_fullscreen("#canvas", false);
+ //emscripten_request_fullscreen(platform.canvasId, false);
// Option 2: Request fullscreen for the canvas element with strategy
// This option does not seem to work at all
- // Ref: https://github.com/emscripten-core/emscripten/issues/5124
+ // REF: https://github.com/emscripten-core/emscripten/issues/5124
// EmscriptenFullscreenStrategy strategy = {
// .scaleMode = EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH, //EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT,
// .canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF,
@@ -245,7 +256,7 @@ void ToggleFullscreen(void)
// .canvasResizedCallback = EmscriptenWindowResizedCallback,
// .canvasResizedCallbackUserData = NULL
// };
- //emscripten_request_fullscreen_strategy("#canvas", EM_FALSE, &strategy);
+ //emscripten_request_fullscreen_strategy(platform.canvasId, EM_FALSE, &strategy);
// Option 3: Request fullscreen for the canvas element with strategy
// It works as expected but only inside the browser (client area)
@@ -256,10 +267,11 @@ void ToggleFullscreen(void)
.canvasResizedCallback = EmscriptenWindowResizedCallback,
.canvasResizedCallbackUserData = NULL
};
- emscripten_enter_soft_fullscreen("#canvas", &strategy);
+ emscripten_enter_soft_fullscreen(platform.canvasId, &strategy);
- int width, height;
- emscripten_get_canvas_element_size("#canvas", &width, &height);
+ int width = 0;
+ int height = 0;
+ emscripten_get_canvas_element_size(platform.canvasId, &width, &height);
TRACELOG(LOG_WARNING, "Emscripten: Enter fullscreen: Canvas size: %i x %i", width, height);
CORE.Window.fullscreen = true; // Toggle fullscreen flag
@@ -271,7 +283,7 @@ void ToggleFullscreen(void)
//emscripten_exit_soft_fullscreen();
int width, height;
- emscripten_get_canvas_element_size("#canvas", &width, &height);
+ emscripten_get_canvas_element_size(platform.canvasId, &width, &height);
TRACELOG(LOG_WARNING, "Emscripten: Exit fullscreen: Canvas size: %i x %i", width, height);
CORE.Window.fullscreen = false; // Toggle fullscreen flag
@@ -866,7 +878,7 @@ void EnableCursor(void)
// Disables cursor (lock cursor)
void DisableCursor(void)
{
- emscripten_request_pointerlock(GetCanvasId(), 1);
+ emscripten_request_pointerlock(platform.canvasId, 1);
// Set cursor position in the middle
SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
@@ -877,7 +889,32 @@ void DisableCursor(void)
// Swap back buffer with front buffer (screen drawing)
void SwapScreenBuffer(void)
{
+#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+ // Update framebuffer
+ rlCopyFramebuffer(0, 0, CORE.Window.render.width, CORE.Window.render.height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, platform.pixels);
+
+ // Copy framebuffer data into canvas
+ EM_ASM({
+ const width = $0;
+ const height = $1;
+ const ptr = $2;
+
+ // Get canvas and 2d context created
+ const canvas = Module.canvas;
+ const ctx = canvas.getContext('2d');
+
+ if (!Module.__img || (Module.__img.width !== width) || (Module.__img.height !== height)) {
+ Module.__img = ctx.createImageData(width, height);
+ }
+
+ const src = HEAPU8.subarray(ptr, ptr + width*height*4); // RGBA (4 bytes)
+ Module.__img.data.set(src);
+ ctx.putImageData(Module.__img, 0, 0);
+
+ }, CORE.Window.screen.width, CORE.Window.screen.height, platform.pixels);
+#else
glfwSwapBuffers(platform.handle);
+#endif
}
//----------------------------------------------------------------------------------
@@ -968,7 +1005,7 @@ void SetMouseCursor(int cursor)
}
}
-// Get physical key name.
+// Get physical key name
const char *GetKeyName(int key)
{
TRACELOG(LOG_WARNING, "GetKeyName() not implemented on target platform");
@@ -1097,6 +1134,8 @@ void PollInputEvents(void)
// Initialize platform: graphics, inputs and more
int InitPlatform(void)
{
+ SetCanvasIdJs(platform.canvasId, 64); // Get the current canvas id
+
glfwSetErrorCallback(ErrorCallback);
// Initialize GLFW internal global state
@@ -1206,7 +1245,21 @@ int InitPlatform(void)
// Init fullscreen toggle required var:
platform.ourFullscreen = false;
-
+
+#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+ // Avoid creating a WebGL canvas, avoid calling glfwCreateWindow()
+ emscripten_set_canvas_element_size(platform.canvasId, CORE.Window.screen.width, CORE.Window.screen.height);
+ EM_ASM({
+ const canvas = document.getElementById("canvas");
+ Module.canvas = canvas;
+ });
+
+ // Load memory framebuffer with desired screen size
+ // NOTE: Despite using a software framebuffer for blitting, GLFW still creates a WebGL canvas,
+ // but it is not being used, on SwapScreenBuffer() the pure software renderer is used
+ // TODO: Consider requesting another type of canvas, not a WebGL one --> Replace GLFW-web by Emscripten?
+ platform.pixels = (unsigned int *)RL_CALLOC(CORE.Window.screen.width*CORE.Window.screen.height, sizeof(unsigned int));
+#else
if (CORE.Window.fullscreen)
{
// remember center for switchinging from fullscreen to window
@@ -1281,6 +1334,7 @@ int InitPlatform(void)
TRACELOG(LOG_WARNING, "GLFW: Failed to initialize Window");
return -1;
}
+#endif
// WARNING: glfwCreateWindow() title doesn't work with emscripten
emscripten_set_window_title((CORE.Window.title != 0)? CORE.Window.title : " ");
@@ -1347,14 +1401,14 @@ int InitPlatform(void)
//----------------------------------------------------------------------------
// Setup window events callbacks
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenFullscreenChangeCallback);
- emscripten_set_blur_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
- emscripten_set_focus_callback(GetCanvasId(), platform.handle, 1, EmscriptenFocusCallback);
+ emscripten_set_blur_callback(platform.canvasId, platform.handle, 1, EmscriptenFocusCallback);
+ emscripten_set_focus_callback(platform.canvasId, platform.handle, 1, EmscriptenFocusCallback);
emscripten_set_visibilitychange_callback(NULL, 1, EmscriptenVisibilityChangeCallback);
// WARNING: Below resize code was breaking fullscreen mode for sample games and examples, it needs review
- // Check fullscreen change events(note this is done on the window since most browsers don't support this on #canvas)
+ // Check fullscreen change events(note this is done on the window since most browsers don't support this on canvas)
// emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
- // Check Resize event (note this is done on the window since most browsers don't support this on #canvas)
+ // Check Resize event (note this is done on the window since most browsers don't support this on canvas)
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenResizeCallback);
// Trigger resize callback to force initial size
@@ -1362,15 +1416,15 @@ int InitPlatform(void)
// Setup input events
// NOTE: Keyboard callbacks only used to consume some events, libglfw.js takes care of the actual input
- //emscripten_set_keypress_callback(GetCanvasId(), NULL, 1, EmscriptenKeyboardCallback); // WRNING: Breaks input
- //emscripten_set_keydown_callback(GetCanvasId(), NULL, 1, EmscriptenKeyboardCallback);
- emscripten_set_click_callback(GetCanvasId(), NULL, 1, EmscriptenMouseCallback);
+ //emscripten_set_keypress_callback(platform.canvasId, NULL, 1, EmscriptenKeyboardCallback); // WRNING: Breaks input
+ //emscripten_set_keydown_callback(platform.canvasId, NULL, 1, EmscriptenKeyboardCallback);
+ emscripten_set_click_callback(platform.canvasId, NULL, 1, EmscriptenMouseCallback);
emscripten_set_pointerlockchange_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, 1, EmscriptenPointerlockCallback);
- emscripten_set_mousemove_callback(GetCanvasId(), NULL, 1, EmscriptenMouseMoveCallback);
- emscripten_set_touchstart_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
- emscripten_set_touchend_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
- emscripten_set_touchmove_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
- emscripten_set_touchcancel_callback(GetCanvasId(), NULL, 1, EmscriptenTouchCallback);
+ emscripten_set_mousemove_callback(platform.canvasId, NULL, 1, EmscriptenMouseMoveCallback);
+ emscripten_set_touchstart_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback);
+ emscripten_set_touchend_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback);
+ emscripten_set_touchmove_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback);
+ emscripten_set_touchcancel_callback(platform.canvasId, NULL, 1, EmscriptenTouchCallback);
emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
//----------------------------------------------------------------------------
@@ -1512,8 +1566,8 @@ static void CharCallback(GLFWwindow *window, unsigned int key)
// NOTE: Registers any key down considering OS keyboard layout but
// does not detect action events, those should be managed by user...
- // Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
- // Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char
+ // REF: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
+ // REF: https://www.glfw.org/docs/latest/input_guide.html#input_char
// Check if there is space available in the queue
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
@@ -1691,7 +1745,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
// NOTE: emscripten_get_canvas_element_size() returns canvas.width and canvas.height but
// we are looking for actual CSS size: canvas.style.width and canvas.style.height
// EMSCRIPTEN_RESULT res = emscripten_get_canvas_element_size("#canvas", &canvasWidth, &canvasHeight);
- emscripten_get_element_css_size(GetCanvasId(), &canvasWidth, &canvasHeight);
+ emscripten_get_element_css_size(platform.canvasId, &canvasWidth, &canvasHeight);
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
{
@@ -1802,7 +1856,7 @@ static EM_BOOL EmscriptenResizeCallback(int eventType, const EmscriptenUiEvent *
if (height < (int)CORE.Window.screenMin.height) height = CORE.Window.screenMin.height;
else if ((height > (int)CORE.Window.screenMax.height) && (CORE.Window.screenMax.height > 0)) height = CORE.Window.screenMax.height;
- emscripten_set_canvas_element_size(GetCanvasId(), width, height);
+ emscripten_set_canvas_element_size(platform.canvasId, width, height);
SetupViewport(width, height); // Reset viewport and projection matrix for new size
@@ -1845,21 +1899,4 @@ static EM_BOOL EmscriptenVisibilityChangeCallback(int eventType, const Emscripte
}
//-------------------------------------------------------------------------------------------------------
-// JS: Get the canvas id provided by the module configuration
-EM_JS(char *, GetCanvasIdJs, (), {
- var canvasId = "#" + Module.canvas.id;
- var lengthBytes = lengthBytesUTF8(canvasId) + 1;
- var stringOnWasmHeap = _malloc(lengthBytes);
- stringToUTF8(canvasId, stringOnWasmHeap, lengthBytes);
- return stringOnWasmHeap;
-});
-
-// Get canvas id (using embedded JS function)
-static const char *GetCanvasId(void)
-{
- static char *canvasId = NULL;
- if (canvasId == NULL) canvasId = GetCanvasIdJs();
- return canvasId;
-}
-
// EOF
diff --git a/src/raudio.c b/src/raudio.c
index 2416f0849..c65aaa134 100644
--- a/src/raudio.c
+++ b/src/raudio.c
@@ -1040,8 +1040,8 @@ void UnloadSoundAlias(Sound alias)
}
// Update sound buffer with new data
-// NOTE 1: data format must match sound.stream.sampleSize
-// NOTE 2: frameCount must not exceed sound.frameCount
+// PARAMS: [data], format must match sound.stream.sampleSize, default 32 bit float - stereo
+// PARAMS: [frameCount] must not exceed sound.frameCount
void UpdateSound(Sound sound, const void *data, int frameCount)
{
if (sound.stream.buffer != NULL)
@@ -1140,7 +1140,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName)
// Get file name from path and convert variable name to uppercase
char varFileName[256] = { 0 };
- strcpy(varFileName, GetFileNameWithoutExt(fileName));
+ strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1);
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
// Add wave information
@@ -2739,11 +2739,13 @@ static const char *GetFileExtension(const char *fileName)
return dot;
}
-// String pointer reverse break: returns right-most occurrence of charset in s
-static const char *strprbrk(const char *s, const char *charset)
+// String pointer reverse break: returns right-most occurrence of charset in text
+static const char *strprbrk(const char *text, const char *charset)
{
const char *latestMatch = NULL;
- for (; s = strpbrk(s, charset), s != NULL; latestMatch = s++) { }
+
+ for (; (text != NULL) && (text = strpbrk(text, charset)); latestMatch = text++) { }
+
return latestMatch;
}
@@ -2766,11 +2768,11 @@ static const char *GetFileNameWithoutExt(const char *filePath)
static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH] = { 0 };
memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH);
- if (filePath != NULL) strcpy(fileName, GetFileName(filePath)); // Get filename with extension
+ if (filePath != NULL) strncpy(fileName, GetFileName(filePath), MAX_FILENAMEWITHOUTEXT_LENGTH - 1); // Get filename with extension
- int size = (int)strlen(fileName); // Get size in bytes
+ int fileNameLength = (int)strlen(fileName); // Get size in bytes
- for (int i = 0; (i < size) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++)
+ for (int i = 0; (i < fileNameLength) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++)
{
if (fileName[i] == '.')
{
@@ -2864,7 +2866,8 @@ static bool SaveFileText(const char *fileName, char *text)
if (file != NULL)
{
- int count = fprintf(file, "%s", text);
+ int count = 0;
+ if (text != NULL) count = fprintf(file, "%s", text);
if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName);
else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName);
diff --git a/src/raylib.h b/src/raylib.h
index ece2e6aab..ba80e40c7 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -334,10 +334,10 @@ typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D
// Camera2D, defines position/orientation in 2d space
typedef struct Camera2D {
- Vector2 offset; // Camera offset (displacement from target)
- Vector2 target; // Camera target (rotation and zoom origin)
- float rotation; // Camera rotation in degrees
- float zoom; // Camera zoom (scaling), should be 1.0f by default
+ Vector2 offset; // Camera offset (screen space offset from window origin)
+ Vector2 target; // Camera target (world space target point that is mapped to screen space offset)
+ float rotation; // Camera rotation in degrees (pivots around target)
+ float zoom; // Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale
} Camera2D;
// Mesh, vertex data and vao/vbo
@@ -1145,7 +1145,7 @@ RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previ
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string)
RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success
-RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success
+RLAPI bool ChangeDirectory(const char *dirPath); // Change working directory, return true on success
RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory
RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths
@@ -1657,7 +1657,7 @@ RLAPI Sound LoadSound(const char *fileName); // Load so
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
RLAPI Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data
RLAPI bool IsSoundValid(Sound sound); // Checks if a sound is valid (data loaded and buffers initialized)
-RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (data and frame count should fit in sound)
+RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (default data format: 32 bit float, stereo)
RLAPI void UnloadWave(Wave wave); // Unload wave data
RLAPI void UnloadSound(Sound sound); // Unload sound
RLAPI void UnloadSoundAlias(Sound alias); // Unload a sound alias (does not deallocate sample data)
diff --git a/src/rcore.c b/src/rcore.c
index 88448bdfe..1f47efcb9 100644
--- a/src/rcore.c
+++ b/src/rcore.c
@@ -113,11 +113,11 @@
#include // Required for: srand(), rand(), atexit()
#include // Required for: sprintf() [Used in OpenURL()]
-#include // Required for: strlen(), strcpy(), strcmp(), strrchr(), memset()
+#include // Required for: strlen(), strncpy(), strcmp(), strrchr(), memset()
#include // Required for: time() [Used in InitTimer()]
#include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
-#if defined(PLATFORM_MEMORY)
+#if defined(PLATFORM_MEMORY) || defined(PLATFORM_WEB)
#define SW_GL_FRAMEBUFFER_COPY_BGRA false
#endif
#define RLGL_IMPLEMENTATION
@@ -387,11 +387,6 @@ RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported s
CoreData CORE = { 0 }; // Global CORE state context
-// Flag to note GPU acceleration is available,
-// referenced from other modules to support GPU data loading
-// NOTE: Useful to allow Texture, RenderTexture, Font.texture, Mesh.vaoId/vboId, Shader loading
-bool isGpuReady = false;
-
#if defined(SUPPORT_SCREEN_CAPTURE)
static int screenshotCounter = 0; // Screenshots counter
#endif
@@ -697,7 +692,6 @@ void InitWindow(int width, int height, const char *title)
// Initialize rlgl default data (buffers and shaders)
// NOTE: Current fbo size stored as globals in rlgl for convenience
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
- isGpuReady = true; // Flag to note GPU has been initialized successfully
// Setup default viewport
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
@@ -822,30 +816,22 @@ int GetScreenHeight(void)
// Get current render width which is equal to screen width*dpi scale
int GetRenderWidth(void)
{
- if (CORE.Window.usingFbo) return CORE.Window.currentFbo.width;
-
int width = 0;
-#if defined(__APPLE__)
- Vector2 scale = GetWindowScaleDPI();
- width = (int)((float)CORE.Window.render.width*scale.x);
-#else
- width = CORE.Window.render.width;
-#endif
+
+ if (CORE.Window.usingFbo) return CORE.Window.currentFbo.width;
+ else width = CORE.Window.render.width;
+
return width;
}
// Get current screen height which is equal to screen height*dpi scale
int GetRenderHeight(void)
{
- if (CORE.Window.usingFbo) return CORE.Window.currentFbo.height;
-
int height = 0;
-#if defined(__APPLE__)
- Vector2 scale = GetWindowScaleDPI();
- height = (int)((float)CORE.Window.render.height*scale.y);
-#else
- height = CORE.Window.render.height;
-#endif
+
+ if (CORE.Window.usingFbo) return CORE.Window.currentFbo.height;
+ else height = CORE.Window.render.height;
+
return height;
}
@@ -1266,7 +1252,14 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
shader.id = rlLoadShaderCode(vsCode, fsCode);
- if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault();
+ if (shader.id == 0)
+ {
+ // Shader could not be loaded but we still load the location points to avoid potential crashes
+ // NOTE: All locations set to -1 (no location)
+ shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
+ for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
+ }
+ else if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault();
else if (shader.id > 0)
{
// After custom shader loading, we TRY to set default location names
@@ -1282,9 +1275,9 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
// NOTE: If any location is not found, loc point becomes -1
+ // Load shader locations array
+ // NOTE: All locations set to -1 (no location)
shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
-
- // All locations reset to -1 (no location)
for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
// Get handles to GLSL input attribute locations
@@ -1659,8 +1652,8 @@ float GetFrameTime(void)
// Wait for some time (stop program execution)
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
// take longer than expected... for that reason we use the busy wait loop
-// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
-// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32!
+// REF: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
+// REF: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32!
void WaitTime(double seconds)
{
if (seconds < 0) return; // Security check
@@ -1742,8 +1735,33 @@ int GetRandomValue(int min, int max)
{
TRACELOG(LOG_WARNING, "Invalid GetRandomValue() arguments, range should not be higher than %i", RAND_MAX);
}
+
+ // NOTE: This one-line approach produces a non-uniform distribution,
+ // as stated by Donald Knuth in the book The Art of Programming, so
+ // using below approach for more uniform results
+ //value = (rand()%(abs(max - min) + 1) + min);
- value = (rand()%(abs(max - min) + 1) + min);
+ // More uniform range solution
+ int range = (max - min) + 1;
+
+ // Degenerate/overflow case: fall back to min (same behavior as "always min" instead of UB)
+ if (range <= 0) value = min;
+ else
+ {
+ // Rejection sampling to get a uniform integer in [min, max]
+ unsigned long c = (unsigned long)RAND_MAX + 1UL; // number of possible rand() results
+ unsigned long m = (unsigned long)range; // size of the target interval
+ unsigned long t = c - (c%m); // largest multiple of m <= c
+ unsigned long r = 0;
+
+ for (;;)
+ {
+ r = (unsigned long)rand();
+ if (r < t) break; // Only accept values within the fair region
+ }
+
+ value = min + (int)(r%m);
+ }
#endif
return value;
}
@@ -1765,7 +1783,7 @@ int *LoadRandomSequence(unsigned int count, int min, int max)
for (int i = 0; i < (int)count;)
{
- value = (rand()%(abs(max - min) + 1) + min);
+ value = GetRandomValue(min, max);
dupValue = false;
for (int j = 0; j < i; j++)
@@ -1807,13 +1825,13 @@ void TakeScreenshot(const char *fileName)
// Apply a scale if we are doing HIGHDPI auto-scaling
Vector2 scale = { 1.0f, 1.0f };
- if (IsWindowState(FLAG_WINDOW_HIGHDPI)) scale = GetWindowScaleDPI();
+ if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) scale = GetWindowScaleDPI();
unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
- char path[512] = { 0 };
- strcpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName));
+ char path[MAX_FILEPATH_LENGTH] = { 0 };
+ strncpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName), MAX_FILEPATH_LENGTH - 1);
ExportImage(image, path); // WARNING: Module required: rtextures
RL_FREE(imgData);
@@ -1983,10 +2001,10 @@ bool IsFileExtension(const char *fileName, const char *ext)
if (fileExt != NULL)
{
- int fileExtLen = (int)strlen(fileExt);
+ int fileExtLength = (int)strlen(fileExt);
char fileExtLower[16] = { 0 };
char *fileExtLowerPtr = fileExtLower;
- for (int i = 0; (i < fileExtLen) && (i < 16); i++)
+ for (int i = 0; (i < fileExtLength) && (i < 16); i++)
{
// Copy and convert to lower-case
if ((fileExt[i] >= 'A') && (fileExt[i] <= 'Z')) fileExtLower[i] = fileExt[i] + 32;
@@ -1994,13 +2012,13 @@ bool IsFileExtension(const char *fileName, const char *ext)
}
int extCount = 1;
- int extLen = (int)strlen(ext);
- char *extList = (char *)RL_CALLOC(extLen + 1, 1);
+ int extLength = (int)strlen(ext);
+ char *extList = (char *)RL_CALLOC(extLength + 1, 1);
char *extListPtrs[MAX_FILE_EXTENSIONS] = { 0 };
- strcpy(extList, ext);
+ strncpy(extList, ext, extLength);
extListPtrs[0] = extList;
- for (int i = 0; i < extLen; i++)
+ for (int i = 0; i < extLength; i++)
{
// Convert to lower-case if extension is upper-case
if ((extList[i] >= 'A') && (extList[i] <= 'Z')) extList[i] += 32;
@@ -2105,11 +2123,11 @@ const char *GetFileExtension(const char *fileName)
}
// String pointer reverse break: returns right-most occurrence of charset in s
-static const char *strprbrk(const char *s, const char *charset)
+static const char *strprbrk(const char *text, const char *charset)
{
const char *latestMatch = NULL;
- for (; s = strpbrk(s, charset), s != NULL; latestMatch = s++) { }
+ for (; (text != NULL) && (text = strpbrk(text, charset)); latestMatch = text++) { }
return latestMatch;
}
@@ -2136,10 +2154,10 @@ const char *GetFileNameWithoutExt(const char *filePath)
if (filePath != NULL)
{
- strcpy(fileName, GetFileName(filePath)); // Get filename.ext without path
- int size = (int)strlen(fileName); // Get size in bytes
+ strncpy(fileName, GetFileName(filePath), MAX_FILENAME_LENGTH - 1); // Get filename.ext without path
+ int fileNameLenght = (int)strlen(fileName); // Get size in bytes
- for (int i = size; i > 0; i--) // Reverse search '.'
+ for (int i = fileNameLenght; i > 0; i--) // Reverse search '.'
{
if (fileName[i] == '.')
{
@@ -2206,11 +2224,11 @@ const char *GetPrevDirectoryPath(const char *dirPath)
{
static char prevDirPath[MAX_FILEPATH_LENGTH] = { 0 };
memset(prevDirPath, 0, MAX_FILEPATH_LENGTH);
- int pathLen = (int)strlen(dirPath);
+ int dirPathLength = (int)strlen(dirPath);
- if (pathLen <= 3) strcpy(prevDirPath, dirPath);
+ if (dirPathLength <= 3) strncpy(prevDirPath, dirPath, MAX_FILEPATH_LENGTH - 1);
- for (int i = (pathLen - 1); (i >= 0) && (pathLen > 3); i--)
+ for (int i = (dirPathLength - 1); (i >= 0) && (dirPathLength > 3); i--)
{
if ((dirPath[i] == '\\') || (dirPath[i] == '/'))
{
@@ -2297,8 +2315,8 @@ const char *GetApplicationDirectory(void)
if (_NSGetExecutablePath(appDir, &size) == 0)
{
- int len = strlen(appDir);
- for (int i = len; i >= 0; --i)
+ int appDirLength = (int)strlen(appDir);
+ for (int i = appDirLength; i >= 0; --i)
{
if (appDir[i] == '/')
{
@@ -2320,8 +2338,8 @@ const char *GetApplicationDirectory(void)
if (sysctl(mib, 4, appDir, &size, NULL, 0) == 0)
{
- int len = strlen(appDir);
- for (int i = len; i >= 0; --i)
+ int appDirLength = (int)strlen(appDir);
+ for (int i = appDirLength; i >= 0; --i)
{
if (appDir[i] == '/')
{
@@ -2416,12 +2434,12 @@ int MakeDirectory(const char *dirPath)
if (DirectoryExists(dirPath)) return 0; // Path already exists (is valid)
// Copy path string to avoid modifying original
- int len = (int)strlen(dirPath) + 1;
- char *pathcpy = (char *)RL_CALLOC(len, 1);
- memcpy(pathcpy, dirPath, len);
+ int dirPathLength = (int)strlen(dirPath) + 1;
+ char *pathcpy = (char *)RL_CALLOC(dirPathLength, 1);
+ memcpy(pathcpy, dirPath, dirPathLength);
// Iterate over pathcpy, create each subdirectory as needed
- for (int i = 0; (i < len) && (pathcpy[i] != '\0'); i++)
+ for (int i = 0; (i < dirPathLength) && (pathcpy[i] != '\0'); i++)
{
if (pathcpy[i] == ':') i++;
else
@@ -2447,12 +2465,12 @@ int MakeDirectory(const char *dirPath)
}
// Change working directory, returns true on success
-bool ChangeDirectory(const char *dir)
+bool ChangeDirectory(const char *dirPath)
{
- bool result = CHDIR(dir);
+ bool result = CHDIR(dirPath);
- if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dir);
- else TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", dir);
+ if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dirPath);
+ else TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", dirPath);
return (result == 0);
}
@@ -2473,10 +2491,10 @@ bool IsFileNameValid(const char *fileName)
if ((fileName != NULL) && (fileName[0] != '\0'))
{
- int length = (int)strlen(fileName);
+ int fileNameLength = (int)strlen(fileName);
bool allPeriods = true;
- for (int i = 0; i < length; i++)
+ for (int i = 0; i < fileNameLength; i++)
{
// Check invalid characters
if ((fileName[i] == '<') ||
@@ -2502,7 +2520,7 @@ bool IsFileNameValid(const char *fileName)
if (valid)
{
// Check invalid DOS names
- if (length >= 3)
+ if (fileNameLength >= 3)
{
if (((fileName[0] == 'C') && (fileName[1] == 'O') && (fileName[2] == 'N')) || // CON
((fileName[0] == 'P') && (fileName[1] == 'R') && (fileName[2] == 'N')) || // PRN
@@ -2510,7 +2528,7 @@ bool IsFileNameValid(const char *fileName)
((fileName[0] == 'N') && (fileName[1] == 'U') && (fileName[2] == 'L'))) valid = false; // NUL
}
- if (length >= 4)
+ if (fileNameLength >= 4)
{
if (((fileName[0] == 'C') && (fileName[1] == 'O') && (fileName[2] == 'M') && ((fileName[3] >= '0') && (fileName[3] <= '9'))) || // COM0-9
((fileName[0] == 'L') && (fileName[1] == 'P') && (fileName[2] == 'T') && ((fileName[3] >= '0') && (fileName[3] <= '9')))) valid = false; // LPT0-9
@@ -2683,6 +2701,9 @@ unsigned char *DecodeDataBase64(const char *text, int *outputSize)
['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
};
+
+ *outputSize = 0;
+ if (text == NULL) return NULL;
// Compute expected size and padding
int dataSize = (int)strlen(text); // WARNING: Expecting NULL terminated strings!
@@ -2926,8 +2947,15 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
memcpy(msg, data, dataSize);
msg[dataSize] = 128; // Write the '1' bit
- unsigned int bitsLen = 8*dataSize;
- msg[newDataSize-1] = bitsLen;
+ unsigned long long bitsLen = 8ULL * dataSize;
+ msg[newDataSize-1] = (unsigned char)(bitsLen);
+ msg[newDataSize-2] = (unsigned char)(bitsLen >> 8);
+ msg[newDataSize-3] = (unsigned char)(bitsLen >> 16);
+ msg[newDataSize-4] = (unsigned char)(bitsLen >> 24);
+ msg[newDataSize-5] = (unsigned char)(bitsLen >> 32);
+ msg[newDataSize-6] = (unsigned char)(bitsLen >> 40);
+ msg[newDataSize-7] = (unsigned char)(bitsLen >> 48);
+ msg[newDataSize-8] = (unsigned char)(bitsLen >> 56);
// Process the message in successive 512-bit chunks
for (int offset = 0; offset < newDataSize; offset += (512/8))
@@ -3787,14 +3815,7 @@ void SetupViewport(int width, int height)
CORE.Window.render.height = height;
// Set viewport width and height
- // NOTE: We consider render size (scaled) and offset in case black bars are required and
- // render area does not match full display area (this situation is only applicable on fullscreen mode)
-#if defined(__APPLE__)
- Vector2 scale = GetWindowScaleDPI();
- rlViewport(CORE.Window.renderOffset.x/2*scale.x, CORE.Window.renderOffset.y/2*scale.y, (CORE.Window.render.width)*scale.x, (CORE.Window.render.height)*scale.y);
-#else
rlViewport(CORE.Window.renderOffset.x/2, CORE.Window.renderOffset.y/2, CORE.Window.render.width, CORE.Window.render.height);
-#endif
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
rlLoadIdentity(); // Reset current matrix (projection)
@@ -3920,7 +3941,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
{
if (IsFileExtension(path, filter))
{
- strcpy(files->paths[files->count], path);
+ strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++;
}
}
@@ -3928,14 +3949,14 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
{
if (strstr(filter, DIRECTORY_FILTER_TAG) != NULL)
{
- strcpy(files->paths[files->count], path);
+ strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++;
}
}
}
else
{
- strcpy(files->paths[files->count], path);
+ strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++;
}
}
@@ -3979,13 +4000,13 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
{
if (IsFileExtension(path, filter))
{
- strcpy(files->paths[files->count], path);
+ strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++;
}
}
else
{
- strcpy(files->paths[files->count], path);
+ strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++;
}
@@ -3999,7 +4020,7 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
{
if ((filter != NULL) && (strstr(filter, DIRECTORY_FILTER_TAG) != NULL))
{
- strcpy(files->paths[files->count], path);
+ strncpy(files->paths[files->count], path, MAX_FILEPATH_LENGTH - 1);
files->count++;
}
@@ -4302,22 +4323,25 @@ const char *TextFormat(const char *text, ...)
char *currentBuffer = buffers[index];
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
-
- va_list args;
- va_start(args, text);
- int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
- va_end(args);
-
- // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occured
- if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH)
+
+ if (text != NULL)
{
- // Inserting "..." at the end of the string to mark as truncated
- char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0"
- sprintf(truncBuffer, "...");
- }
+ va_list args;
+ va_start(args, text);
+ int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
+ va_end(args);
- index += 1; // Move to next buffer for next function call
- if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
+ // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occurred
+ if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH)
+ {
+ // Inserting "..." at the end of the string to mark as truncated
+ char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0"
+ snprintf(truncBuffer, 4, "...");
+ }
+
+ index += 1; // Move to next buffer for next function call
+ if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
+ }
return currentBuffer;
}
diff --git a/src/rlgl.h b/src/rlgl.h
index 6884ad183..cda64896c 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -1153,6 +1153,7 @@ static double rlCullDistanceFar = RL_CULL_DISTANCE_FAR;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
static rlglData RLGL = { 0 };
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
+static bool isGpuReady = false;
#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(GRAPHICS_API_OPENGL_ES3)
// NOTE: VAO functionality is exposed through extensions (OES)
@@ -1761,11 +1762,6 @@ void rlTextureParameters(unsigned int id, int param, int value)
{
glBindTexture(GL_TEXTURE_2D, id);
-#if !defined(GRAPHICS_API_OPENGL_11)
- // Reset anisotropy filter, in case it was set
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
-#endif
-
switch (param)
{
case RL_TEXTURE_WRAP_S:
@@ -1785,6 +1781,9 @@ void rlTextureParameters(unsigned int id, int param, int value)
case RL_TEXTURE_FILTER_ANISOTROPIC:
{
#if !defined(GRAPHICS_API_OPENGL_11)
+ // Reset anisotropy filter, in case it was set
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
+
if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f)
{
@@ -2283,6 +2282,8 @@ static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint
// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states
void rlglInit(int width, int height)
{
+ isGpuReady = true;
+
// Enable OpenGL debug context if required
#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43)
if ((glDebugMessageCallback != NULL) && (glDebugMessageControl != NULL))
@@ -2395,6 +2396,7 @@ void rlglClose(void)
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
swClose(); // Unload sofware renderer resources
#endif
+ isGpuReady = false;
}
// Load OpenGL extensions
@@ -2492,12 +2494,12 @@ void rlLoadExtensions(void *loader)
const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
// NOTE: We have to duplicate string because glGetString() returns a const string
- int size = strlen(extensions) + 1; // Get extensions string size in bytes
- char *extensionsDup = (char *)RL_CALLOC(size, sizeof(char));
- strcpy(extensionsDup, extensions);
+ int extensionsLength = (int)strlen(extensions); // Get extensions string size in bytes
+ char *extensionsDup = (char *)RL_CALLOC(extensionsLength + 1, sizeof(char)); // Allocate space for copy with additional EOL byte
+ strncpy(extensionsDup, extensions, extensionsLength);
extList[numExt] = extensionsDup;
- for (int i = 0; i < size; i++)
+ for (int i = 0; i < extensionsLength; i++)
{
if (extensionsDup[i] == ' ')
{
@@ -2799,6 +2801,7 @@ int *rlGetShaderLocsDefault(void)
rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
{
rlRenderBatch batch = { 0 };
+ if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return batch; }
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes)
@@ -3253,6 +3256,7 @@ bool rlCheckRenderBatchLimit(int vCount)
unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount)
{
unsigned int id = 0;
+ if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding
@@ -3349,8 +3353,8 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
mipWidth /= 2;
mipHeight /= 2;
- mipOffset += mipSize; // Increment offset position to next mipmap
- if (data != NULL) dataPtr += mipSize; // Increment data pointer to next mipmap
+ mipOffset += mipSize; // Increment offset position to next mipmap
+ if (data != NULL) dataPtr += mipSize; // Increment data pointer to next mipmap
// Security check for NPOT textures
if (mipWidth < 1) mipWidth = 1;
@@ -3384,10 +3388,18 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
#if defined(GRAPHICS_API_OPENGL_33)
if (mipmapCount > 1)
{
- // Activate Trilinear filtering if mipmaps are available
+ // Activate trilinear filtering if mipmaps are available
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount); // Required for user-defined mip count
+
+ // Define the maximum number of mipmap levels to be used, 0 is base texture size
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount - 1);
+
+ // Check if the loaded texture with mipmaps is complete,
+ // uncomplete textures will draw in black if mipmap filtering is required
+ //GLint complete = 0;
+ //glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_FORMAT, &complete);
}
#endif
@@ -3409,6 +3421,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer)
{
unsigned int id = 0;
+ if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// In case depth textures not supported, we force renderbuffer usage
@@ -3467,6 +3480,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer)
unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mipmapCount)
{
unsigned int id = 0;
+ if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
int mipSize = size;
@@ -3811,6 +3825,7 @@ unsigned char *rlReadScreenPixels(int width, int height)
unsigned int rlLoadFramebuffer(void)
{
unsigned int fboId = 0;
+ if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return fboId; }
#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT)
glGenFramebuffers(1, &fboId); // Create the framebuffer object
@@ -3903,7 +3918,7 @@ void rlUnloadFramebuffer(unsigned int id)
// TODO: Review warning retrieving object name in WebGL
// WARNING: WebGL: INVALID_ENUM: getFramebufferAttachmentParameter: invalid parameter name
- // Ref: https://registry.khronos.org/webgl/specs/latest/1.0/
+ // REF: https://registry.khronos.org/webgl/specs/latest/1.0/
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthId);
unsigned int depthIdU = (unsigned int)depthId;
@@ -3926,6 +3941,7 @@ void rlUnloadFramebuffer(unsigned int id)
unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic)
{
unsigned int id = 0;
+ if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glGenBuffers(1, &id);
@@ -3940,6 +3956,7 @@ unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic)
unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic)
{
unsigned int id = 0;
+ if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glGenBuffers(1, &id);
@@ -4105,12 +4122,12 @@ void rlDisableStatePointer(int vertexAttribType)
unsigned int rlLoadVertexArray(void)
{
unsigned int vaoId = 0;
+ if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return vaoId; }
+
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
- if (RLGL.ExtSupported.vao)
- {
- glGenVertexArrays(1, &vaoId);
- }
+ if (RLGL.ExtSupported.vao) glGenVertexArrays(1, &vaoId);
#endif
+
return vaoId;
}
@@ -4165,6 +4182,7 @@ void rlUnloadVertexBuffer(unsigned int vboId)
unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
{
unsigned int id = 0;
+ if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
unsigned int vertexShaderId = 0;
@@ -4307,6 +4325,7 @@ unsigned int rlCompileShader(const char *shaderCode, int type)
unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
{
unsigned int programId = 0;
+ if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return programId; }
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
GLint success = 0;
@@ -4470,7 +4489,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
}
@@ -5205,24 +5224,36 @@ static int rlGetPixelDataSize(int width, int height, int format)
case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB:
case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB:
case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB:
- case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
+ case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: // 8 bytes per each 4x4 block
+ {
+ int blockWidth = (width + 3)/4;
+ int blockHeight = (height + 3)/4;
+ dataSize = blockWidth*blockHeight*8;
+ } break;
case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA:
case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA:
case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA:
- case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break;
- case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
+ case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: // 16 bytes per each 4x4 block
+ {
+ int blockWidth = (width + 3)/4;
+ int blockHeight = (height + 3)/4;
+ dataSize = blockWidth*blockHeight*16;
+ } break;
+ case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 4 bytes per each 4x4 block
+ {
+ int blockWidth = (width + 3)/4;
+ int blockHeight = (height + 3)/4;
+ dataSize = blockWidth*blockHeight*4;
+ } break;
default: break;
}
- double bytesPerPixel = (double)bpp/8.0;
- dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes
-
- // Most compressed formats works on 4x4 blocks,
- // if texture is smaller, minimum dataSize is 8 or 16
- if ((width < 4) && (height < 4))
+ // Compute dataSize for uncompressed texture data (no blocks)
+ if ((format >= RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) &&
+ (format <= RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16))
{
- if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8;
- else if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16;
+ double bytesPerPixel = (double)bpp/8.0;
+ dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes
}
return dataSize;
diff --git a/src/rmodels.c b/src/rmodels.c
index fad6ae78b..40af4afc4 100644
--- a/src/rmodels.c
+++ b/src/rmodels.c
@@ -127,10 +127,13 @@
// Defines and Macros
//----------------------------------------------------------------------------------
#ifndef MAX_MATERIAL_MAPS
- #define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported
+ #define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported
#endif
#ifndef MAX_MESH_VERTEX_BUFFERS
- #define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh
+ #define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh
+#endif
+#ifndef MAX_FILEPATH_LENGTH
+ #define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
#endif
//----------------------------------------------------------------------------------
@@ -1282,6 +1285,8 @@ void UploadMesh(Mesh *mesh, bool dynamic)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
mesh->vaoId = rlLoadVertexArray();
+ if (mesh->vaoId == 0) return;
+
rlEnableVertexArray(mesh->vaoId);
// NOTE: Vertex attributes must be uploaded considering default locations points and available vertex data
@@ -1470,6 +1475,8 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
// Bind shader program
rlEnableShader(material.shader.id);
+ if (material.shader.locs == NULL) return;
+
// Send required data to shader (matrices, values)
//-----------------------------------------------------
// Upload to shader material.colDiffuse
@@ -2060,7 +2067,7 @@ bool ExportMeshAsCode(Mesh mesh, const char *fileName)
// Get file name from path and convert variable name to uppercase
char varFileName[256] = { 0 };
- strcpy(varFileName, GetFileNameWithoutExt(fileName));
+ strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module
for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
// Add image information
@@ -3651,7 +3658,7 @@ void GenMeshTangents(Mesh *mesh)
for (int t = 0; t < mesh->triangleCount; t++)
{
// Get triangle vertex indices
- int i0, i1, i2;
+ int i0 = 0, i1 = 0, i2 = 0;
if (mesh->indices != NULL)
{
@@ -4146,7 +4153,9 @@ RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform)
// Test against all triangles in mesh
for (int i = 0; i < triangleCount; i++)
{
- Vector3 a, b, c;
+ Vector3 a = { 0 };
+ Vector3 b = { 0 };
+ Vector3 c = { 0 };
Vector3 *vertdata = (Vector3 *)mesh.vertices;
if (mesh.indices)
@@ -4189,8 +4198,10 @@ RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3
RayCollision collision = { 0 };
Vector3 edge1 = { 0 };
Vector3 edge2 = { 0 };
- Vector3 p, q, tv;
- float det, invDet, u, v, t;
+ Vector3 p = { 0 };
+ Vector3 q = { 0 };
+ Vector3 tv = { 0 };
+ float det = 0.0f, invDet = 0.0f, u = 0.0f, v = 0.0f, t = 0.0f;
// Find vectors for two edges sharing V1
edge1 = Vector3Subtract(p2, p1);
@@ -4306,8 +4317,8 @@ static Model LoadOBJ(const char *fileName)
return model;
}
- char currentDir[1024] = { 0 };
- strcpy(currentDir, GetWorkingDirectory()); // Save current working directory
+ char currentDir[MAX_FILEPATH_LENGTH] = { 0 };
+ strncpy(currentDir, GetWorkingDirectory(), MAX_FILEPATH_LENGTH - 1); // Save current working directory
const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness
if (CHDIR(workingDir) != 0) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);
@@ -5025,10 +5036,8 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
for (unsigned int j = 0; j < iqmHeader->num_poses; j++)
{
// If animations and skeleton are in the same file, copy bone names to anim
- if (iqmHeader->num_joints > 0)
- memcpy(animations[a].bones[j].name, fileDataPtr + iqmHeader->ofs_text + joints[j].name, BONE_NAME_LENGTH*sizeof(char));
- else
- strcpy(animations[a].bones[j].name, "ANIMJOINTNAME"); // Default bone name otherwise
+ if (iqmHeader->num_joints > 0) memcpy(animations[a].bones[j].name, fileDataPtr + iqmHeader->ofs_text + joints[j].name, BONE_NAME_LENGTH*sizeof(char));
+ else memcpy(animations[a].bones[j].name, "ANIMJOINTNAME", 13); // Default bone name otherwise
animations[a].bones[j].parent = poses[j].parent;
}
@@ -5578,6 +5587,56 @@ static Model LoadGLTF(const char *fileName)
vertices[3*k+2] = vt.z;
}
}
+ else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16u))
+ {
+ // Init raylib mesh vertices to copy glTF attribute data
+ model.meshes[meshIndex].vertexCount = (int)attribute->count;
+ model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+ // Load data into a temp buffer to be converted to raylib data type
+ unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*3*sizeof(unsigned short));
+ LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp);
+
+ // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float
+ for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t];
+
+ RL_FREE(temp);
+
+ // Transform the vertices
+ float *vertices = model.meshes[meshIndex].vertices;
+ for (unsigned int k = 0; k < attribute->count; k++)
+ {
+ Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k + 1], vertices[3*k + 2] }, worldMatrix);
+ vertices[3*k] = vt.x;
+ vertices[3*k + 1] = vt.y;
+ vertices[3*k + 2] = vt.z;
+ }
+ }
+ else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16))
+ {
+ // Init raylib mesh vertices to copy glTF attribute data
+ model.meshes[meshIndex].vertexCount = (int)attribute->count;
+ model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+ // Load data into a temp buffer to be converted to raylib data type
+ short *temp = (short *)RL_MALLOC(attribute->count*3*sizeof(short));
+ LOAD_ATTRIBUTE(attribute, 3, short, temp);
+
+ // Convert data to raylib vertex data type (float) the matrix will scale it to the correct size as a float
+ for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].vertices[t] = (float)temp[t];
+
+ RL_FREE(temp);
+
+ // Transform the vertices
+ float *vertices = model.meshes[meshIndex].vertices;
+ for (unsigned int k = 0; k < attribute->count; k++)
+ {
+ Vector3 vt = Vector3Transform((Vector3){ vertices[3*k], vertices[3*k + 1], vertices[3*k + 2] }, worldMatrix);
+ vertices[3*k] = vt.x;
+ vertices[3*k + 1] = vt.y;
+ vertices[3*k + 2] = vt.z;
+ }
+ }
else TRACELOG(LOG_WARNING, "MODEL: [%s] Vertices attribute data format not supported, use vec3 float", fileName);
}
}
@@ -5606,6 +5665,78 @@ static Model LoadGLTF(const char *fileName)
normals[3*k+2] = nt.z;
}
}
+ else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_16))
+ {
+ // Init raylib mesh normals to copy glTF attribute data
+ model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+ // Load data into a temp buffer to be converted to raylib data type
+ short *temp = (short *)RL_MALLOC(attribute->count*3*sizeof(short));
+ LOAD_ATTRIBUTE(attribute, 3, short, temp);
+
+ // Convert data to raylib normal data type (float)
+ for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t];
+
+ RL_FREE(temp);
+
+ // Transform the normals
+ float *normals = model.meshes[meshIndex].normals;
+ for (unsigned int k = 0; k < attribute->count; k++)
+ {
+ Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals));
+ normals[3*k] = nt.x;
+ normals[3*k + 1] = nt.y;
+ normals[3*k + 2] = nt.z;
+ }
+ }
+ else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_8u))
+ {
+ // Init raylib mesh normals to copy glTF attribute data
+ model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+ // Load data into a temp buffer to be converted to raylib data type
+ unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*3*sizeof(unsigned char));
+ LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp);
+
+ // Convert data to raylib normal data type (float)
+ for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t];
+
+ RL_FREE(temp);
+
+ // Transform the normals
+ float *normals = model.meshes[meshIndex].normals;
+ for (unsigned int k = 0; k < attribute->count; k++)
+ {
+ Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals));
+ normals[3*k] = nt.x;
+ normals[3*k + 1] = nt.y;
+ normals[3*k + 2] = nt.z;
+ }
+ }
+ else if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_8))
+ {
+ // Init raylib mesh normals to copy glTF attribute data
+ model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
+
+ // Load data into a temp buffer to be converted to raylib data type
+ char *temp = (char *)RL_MALLOC(attribute->count*3*sizeof(char));
+ LOAD_ATTRIBUTE(attribute, 3, char, temp);
+
+ // Convert data to raylib normal data type (float)
+ for (unsigned int t = 0; t < attribute->count*3; t++) model.meshes[meshIndex].normals[t] = (float)temp[t];
+
+ RL_FREE(temp);
+
+ // Transform the normals
+ float *normals = model.meshes[meshIndex].normals;
+ for (unsigned int k = 0; k < attribute->count; k++)
+ {
+ Vector3 nt = Vector3Normalize(Vector3Transform((Vector3){ normals[3*k], normals[3*k + 1], normals[3*k + 2] }, worldMatrixNormals));
+ normals[3*k] = nt.x;
+ normals[3*k + 1] = nt.y;
+ normals[3*k + 2] = nt.z;
+ }
+ }
else TRACELOG(LOG_WARNING, "MODEL: [%s] Normals attribute data format not supported, use vec3 float", fileName);
}
}
@@ -5874,8 +6005,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
@@ -6848,7 +6979,7 @@ static Model LoadM3D(const char *fileName)
// Add a special "no bone" bone
model.bones[i].parent = -1;
- strcpy(model.bones[i].name, "NO BONE");
+ memcpy(model.bones[i].name, "NO BONE", 7);
model.bindPose[i].translation.x = 0.0f;
model.bindPose[i].translation.y = 0.0f;
model.bindPose[i].translation.z = 0.0f;
@@ -6940,7 +7071,7 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
// A special, never transformed "no bone" bone, used for boneless vertices
animations[a].bones[i].parent = -1;
- strcpy(animations[a].bones[i].name, "NO BONE");
+ memcpy(animations[a].bones[i].name, "NO BONE", 7);
// M3D stores frames at arbitrary intervals with sparse skeletons. We need full skeletons at
// regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
diff --git a/src/rtext.c b/src/rtext.c
index 8a3961a00..7c25fde0b 100644
--- a/src/rtext.c
+++ b/src/rtext.c
@@ -67,7 +67,7 @@
#include // Required for: malloc(), free()
#include // Required for: vsprintf()
-#include // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
+#include // Required for: strcmp(), strstr(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
#include // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
#include // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
@@ -127,13 +127,12 @@
//----------------------------------------------------------------------------------
// Global variables
//----------------------------------------------------------------------------------
-extern bool isGpuReady;
#if defined(SUPPORT_DEFAULT_FONT)
// Default font provided by raylib
// NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
static Font defaultFont = { 0 };
#endif
-static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines)
+static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines)
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by text)
@@ -164,12 +163,11 @@ extern void LoadFontDefault(void)
{
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
- // check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return
- if (defaultFont.glyphs != NULL && !isGpuReady)
- return;
+ // Check to see if we have already allocated the font for an image, and if we don't need to upload, then just return
+ if (defaultFont.glyphs != NULL) return;
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
- // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
+ // REF: http://www.utf8-chartable.de/unicode-utf8-table.pl
defaultFont.glyphCount = 224; // Number of glyphs included in our default font
defaultFont.glyphPadding = 0; // Characters padding
@@ -264,17 +262,14 @@ extern void LoadFontDefault(void)
counter++;
}
- if (isGpuReady)
- {
- defaultFont.texture = LoadTextureFromImage(imFont);
+ defaultFont.texture = LoadTextureFromImage(imFont);
- // we have already loaded the font glyph data an image, and the GPU is ready, we are done
- // if we don't do this, we will leak memory by reallocating the glyphs and rects
- if (defaultFont.glyphs != NULL)
- {
- UnloadImage(imFont);
- return;
- }
+ // we have already loaded the font glyph data an image, and the GPU is ready, we are done
+ // if we don't do this, we will leak memory by reallocating the glyphs and rects
+ if (defaultFont.glyphs != NULL)
+ {
+ UnloadImage(imFont);
+ return;
}
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
@@ -331,7 +326,7 @@ extern void LoadFontDefault(void)
extern void UnloadFontDefault(void)
{
for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image);
- if (isGpuReady) UnloadTexture(defaultFont.texture);
+ UnloadTexture(defaultFont.texture);
RL_FREE(defaultFont.glyphs);
RL_FREE(defaultFont.recs);
defaultFont.glyphCount = 0;
@@ -385,17 +380,15 @@ Font LoadFont(const char *fileName)
{
Image image = LoadImage(fileName);
if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, FONT_TTF_DEFAULT_FIRST_CHAR);
+ else font = GetFontDefault();
UnloadImage(image);
}
- if (isGpuReady)
+ if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
+ else
{
- if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
- else
- {
- SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
- TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
- }
+ SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
+ TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
}
return font;
@@ -516,7 +509,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
};
// Set font with all data parsed from image
- if (isGpuReady) font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
+ font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
font.glyphCount = index;
font.glyphPadding = 0;
@@ -585,7 +578,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING;
Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0);
- if (isGpuReady) font.texture = LoadTextureFromImage(atlas);
+ font.texture = LoadTextureFromImage(atlas);
// Update glyphs[i].image to use alpha, required to be used on ImageDrawText()
for (int i = 0; i < font.glyphCount; i++)
@@ -656,7 +649,9 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
// Calculate font basic metrics
// NOTE: ascent is equivalent to font baseline
- int ascent, descent, lineGap;
+ int ascent = 0;
+ int descent = 0;
+ int lineGap = 0;
stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
// In case no chars count provided, default to 95
@@ -705,7 +700,11 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
switch (type)
{
case FONT_DEFAULT:
- case FONT_BITMAP: glyphs[k].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, cp, &cpWidth, &cpHeight, &glyphs[k].offsetX, &glyphs[k].offsetY); break;
+ case FONT_BITMAP:
+ {
+ glyphs[k].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, cp,
+ &cpWidth, &cpHeight, &glyphs[k].offsetX, &glyphs[k].offsetY);
+ } break;
case FONT_SDF:
{
if (cp != 32)
@@ -1009,7 +1008,7 @@ void UnloadFont(Font font)
if (font.texture.id != GetFontDefault().texture.id)
{
UnloadFontData(font.glyphs, font.glyphCount);
- if (isGpuReady) UnloadTexture(font.texture);
+ UnloadTexture(font.texture);
RL_FREE(font.recs);
TRACELOGD("FONT: Unloaded font data from RAM and VRAM");
@@ -1340,8 +1339,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
{
Vector2 textSize = { 0 };
- if ((isGpuReady && (font.texture.id == 0)) ||
- (text == NULL) || (text[0] == '\0')) return textSize; // Security check
+ if ((font.texture.id == 0) || (text == NULL) || (text[0] == '\0')) return textSize; // Security check
int size = TextLength(text); // Get size in bytes of text
int tempByteCounter = 0; // Used to count longer text line num chars
@@ -1453,29 +1451,31 @@ Rectangle GetGlyphAtlasRec(Font font, int codepoint)
char **LoadTextLines(const char *text, int *count)
{
char **lines = NULL;
+ int lineCount = 0;
- if (text == NULL) { *count = 0; return lines; }
-
- int lineCount = 1;
- int textSize = (int)strlen(text);
-
- // First text scan pass to get required line count
- for (int i = 0; i < textSize; i++)
+ if (text != NULL)
{
- if (text[i] == '\n') lineCount++;
- }
+ int textLength = TextLength(text);
+ lineCount = 1;
- lines = (char **)RL_CALLOC(lineCount, sizeof(char *));
- for (int i = 0, l = 0, lineLen = 0; i <= textSize; i++)
- {
- if ((text[i] == '\n') || (text[i] == '\0'))
+ // First text scan pass to get required line count
+ for (int i = 0; i < textLength; i++)
{
- lines[l] = (char *)RL_CALLOC(lineLen + 1, 1);
- strncpy(lines[l], &text[i - lineLen], lineLen);
- lineLen = 0;
- l++;
+ if (text[i] == '\n') lineCount++;
+ }
+
+ lines = (char **)RL_CALLOC(lineCount, sizeof(char *));
+ for (int i = 0, l = 0, lineLen = 0; i <= textLength; i++)
+ {
+ if ((text[i] == '\n') || (text[i] == '\0'))
+ {
+ lines[l] = (char *)RL_CALLOC(lineLen + 1, 1);
+ strncpy(lines[l], &text[i - lineLen], lineLen);
+ lineLen = 0;
+ l++;
+ }
+ else lineLen++;
}
- else lineLen++;
}
*count = lineCount;
@@ -1517,23 +1517,26 @@ const char *TextFormat(const char *text, ...)
static int index = 0;
char *currentBuffer = buffers[index];
- memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
-
- va_list args;
- va_start(args, text);
- int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
- va_end(args);
-
- // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occured
- if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH)
+ memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
+
+ if (text != NULL)
{
- // Inserting "..." at the end of the string to mark as truncated
- char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0"
- sprintf(truncBuffer, "...");
- }
+ va_list args;
+ va_start(args, text);
+ int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
+ va_end(args);
- index += 1; // Move to next buffer for next function call
- if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
+ // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occurred
+ if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH)
+ {
+ // Inserting "..." at the end of the string to mark as truncated
+ char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0"
+ snprintf(truncBuffer, 4, "...");
+ }
+
+ index += 1; // Move to next buffer for next function call
+ if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
+ }
return currentBuffer;
}
@@ -1545,13 +1548,16 @@ int TextToInteger(const char *text)
int value = 0;
int sign = 1;
- if ((text[0] == '+') || (text[0] == '-'))
+ if (text != NULL)
{
- if (text[0] == '-') sign = -1;
- text++;
- }
+ if ((text[0] == '+') || (text[0] == '-'))
+ {
+ if (text[0] == '-') sign = -1;
+ text++;
+ }
- for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0');
+ for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0');
+ }
return value*sign;
}
@@ -1564,22 +1570,25 @@ float TextToFloat(const char *text)
float value = 0.0f;
float sign = 1.0f;
- if ((text[0] == '+') || (text[0] == '-'))
+ if (text != NULL)
{
- if (text[0] == '-') sign = -1.0f;
- text++;
- }
-
- int i = 0;
- for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0');
-
- if (text[i++] == '.')
- {
- float divisor = 10.0f;
- for (; ((text[i] >= '0') && (text[i] <= '9')); i++)
+ if ((text[0] == '+') || (text[0] == '-'))
{
- value += ((float)(text[i] - '0'))/divisor;
- divisor = divisor*10.0f;
+ if (text[0] == '-') sign = -1.0f;
+ text++;
+ }
+
+ int i = 0;
+ for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0');
+
+ if (text[i++] == '.')
+ {
+ float divisor = 10.0f;
+ for (; ((text[i] >= '0') && (text[i] <= '9')); i++)
+ {
+ value += ((float)(text[i] - '0'))/divisor;
+ divisor = divisor*10.0f;
+ }
}
}
@@ -1631,26 +1640,23 @@ const char *TextSubtext(const char *text, int position, int length)
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
- int textLength = TextLength(text);
-
- if (position >= textLength)
+ if (text != NULL)
{
- return buffer; //First char is already '\0' by memset
+ int textLength = TextLength(text);
+
+ if (position >= textLength) return buffer; // First char is already '\0' by memset
+
+ int maxLength = textLength - position;
+ if (length > maxLength) length = maxLength;
+ if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1;
+
+ // NOTE: Alternative: memcpy(buffer, text + position, length)
+
+ for (int c = 0; c < length; c++) buffer[c] = text[position + c];
+
+ buffer[length] = '\0';
}
- int maxLength = textLength - position;
- if (length > maxLength) length = maxLength;
- if (length >= MAX_TEXT_BUFFER_LENGTH) length = MAX_TEXT_BUFFER_LENGTH - 1;
-
- // NOTE: Alternative: memcpy(buffer, text + position, length)
-
- for (int c = 0 ; c < length ; c++)
- {
- buffer[c] = text[position + c];
- }
-
- buffer[length] = '\0';
-
return buffer;
}
@@ -1684,7 +1690,7 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
if (beginIndex > -1)
{
- int beginLen = (int)strlen(begin);
+ int beginLen = TextLength(begin);
int endIndex = TextFindIndex(text + beginIndex + beginLen, end);
if (endIndex > -1)
@@ -1700,84 +1706,86 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
}
// Replace text string
-// REQUIRES: strstr(), strncpy(), strcpy()
+// REQUIRES: strstr(), strncpy()
// TODO: If (replacement == "") remove "search" text
// WARNING: Allocated memory must be manually freed
char *TextReplace(const char *text, const char *search, const char *replacement)
{
char *result = NULL;
- if (!text || !search) return NULL; // Sanity check
-
- char *insertPoint = NULL; // Next insert point
- char *temp = NULL; // Temp pointer
- int searchLen = 0; // Search string length of (the string to remove)
- int replaceLen = 0; // Replacement length (the string to replace by)
- int lastReplacePos = 0; // Distance between next search and end of last replace
- int count = 0; // Number of replacements
-
- searchLen = TextLength(search);
- if (searchLen == 0) return NULL; // Empty search causes infinite loop during count
-
- replaceLen = TextLength(replacement);
-
- // Count the number of replacements needed
- insertPoint = (char *)text;
- for (count = 0; (temp = strstr(insertPoint, search)); count++) insertPoint = temp + searchLen;
-
- // Allocate returning string and point temp to it
- temp = result = (char *)RL_MALLOC(TextLength(text) + (replaceLen - searchLen)*count + 1);
-
- if (!result) return NULL; // Memory could not be allocated
-
- // First time through the loop, all the variable are set correctly from here on,
- // - 'temp' points to the end of the result string
- // - 'insertPoint' points to the next occurrence of replace in text
- // - 'text' points to the remainder of text after "end of replace"
- while (count--)
+ if ((text != NULL) && (search != NULL))
{
- insertPoint = (char *)strstr(text, search);
- lastReplacePos = (int)(insertPoint - text);
- temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
- temp = strcpy(temp, replacement) + replaceLen;
- text += lastReplacePos + searchLen; // Move to next "end of replace"
- }
+ char *insertPoint = NULL; // Next insert point
+ char *temp = NULL; // Temp pointer
+ int searchLen = 0; // Search string length of (the string to remove)
+ int replaceLen = 0; // Replacement length (the string to replace by)
+ int lastReplacePos = 0; // Distance between next search and end of last replace
+ int count = 0; // Number of replacements
- // Copy remaind text part after replacement to result (pointed by moving temp)
- strcpy(temp, text);
+ searchLen = TextLength(search);
+ if (searchLen == 0) return NULL; // Empty search causes infinite loop during count
+
+ replaceLen = TextLength(replacement);
+
+ // Count the number of replacements needed
+ insertPoint = (char *)text;
+ for (count = 0; (temp = strstr(insertPoint, search)); count++) insertPoint = temp + searchLen;
+
+ // Allocate returning string and point temp to it
+ temp = result = (char *)RL_MALLOC(TextLength(text) + (replaceLen - searchLen)*count + 1);
+
+ if (!result) return NULL; // Memory could not be allocated
+
+ // First time through the loop, all the variable are set correctly from here on,
+ // - 'temp' points to the end of the result string
+ // - 'insertPoint' points to the next occurrence of replace in text
+ // - 'text' points to the remainder of text after "end of replace"
+ while (count--)
+ {
+ insertPoint = (char *)strstr(text, search);
+ lastReplacePos = (int)(insertPoint - text);
+ temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
+ temp = strcpy(temp, replacement) + replaceLen;
+ text += lastReplacePos + searchLen; // Move to next "end of replace"
+ }
+
+ // Copy remaind text part after replacement to result (pointed by moving temp)
+ strcpy(temp, text);
+ }
return result;
}
// Replace text between two specific strings
-// REQUIRES: strlen(), strncpy()
+// REQUIRES: strncpy()
// NOTE: If (replacement == NULL) remove "begin"[ ]"end" text
// WARNING: Returned string must be freed by user
char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement)
{
char *result = NULL;
- if (!text || !begin || !end) return NULL; // Sanity check
-
- int beginIndex = TextFindIndex(text, begin);
-
- if (beginIndex > -1)
+ if ((text != NULL) && (begin != NULL) && (end != NULL))
{
- int beginLen = (int)strlen(begin);
- int endIndex = TextFindIndex(text + beginIndex + beginLen, end);
+ int beginIndex = TextFindIndex(text, begin);
- if (endIndex > -1)
+ if (beginIndex > -1)
{
- endIndex += (beginIndex + beginLen);
+ int beginLen = TextLength(begin);
+ int endIndex = TextFindIndex(text + beginIndex + beginLen, end);
- int textLen = (int)strlen(text);
- int replaceLen = (replacement == NULL)? 0 : (int)strlen(replacement);
- int toreplaceLen = endIndex - beginIndex - beginLen;
- result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char));
+ if (endIndex > -1)
+ {
+ endIndex += (beginIndex + beginLen);
- strncpy(result, text, beginIndex + beginLen); // Copy first text part
- if (replacement != NULL) strncpy(result + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided)
- strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part
+ int textLen = TextLength(text);
+ int replaceLen = (replacement == NULL)? 0 : TextLength(replacement);
+ int toreplaceLen = endIndex - beginIndex - beginLen;
+ result = (char *)RL_CALLOC(textLen + replaceLen - toreplaceLen + 1, sizeof(char));
+
+ strncpy(result, text, beginIndex + beginLen); // Copy first text part
+ if (replacement != NULL) strncpy(result + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided)
+ strncpy(result + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part
+ }
}
}
@@ -1788,16 +1796,21 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c
// WARNING: Allocated memory must be manually freed
char *TextInsert(const char *text, const char *insert, int position)
{
- int textLen = TextLength(text);
- int insertLen = TextLength(insert);
+ char *result = NULL;
- char *result = (char *)RL_MALLOC(textLen + insertLen + 1);
+ if ((text != NULL) && (insert != NULL))
+ {
+ int textLen = TextLength(text);
+ int insertLen = TextLength(insert);
- for (int i = 0; i < position; i++) result[i] = text[i];
- for (int i = position; i < insertLen + position; i++) result[i] = insert[i];
- for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i];
+ result = (char *)RL_MALLOC(textLen + insertLen + 1);
- result[textLen + insertLen] = '\0'; // Make sure text string is valid!
+ for (int i = 0; i < position; i++) result[i] = text[i];
+ for (int i = position; i < insertLen + position; i++) result[i] = insert[i];
+ for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i];
+
+ result[textLen + insertLen] = '\0'; // Add EOL
+ }
return result;
}
@@ -1879,11 +1892,13 @@ char **TextSplit(const char *text, char delimiter, int *count)
// Append text at specific position and move cursor
// WARNING: It's up to the user to make sure appended text does not overflow the buffer!
-// REQUIRES: strcpy()
void TextAppend(char *text, const char *append, int *position)
{
- strcpy(text + *position, append);
- *position += TextLength(append);
+ if ((text != NULL) && (append != NULL))
+ {
+ TextCopy(text + *position, append);
+ *position += TextLength(append);
+ }
}
// Find first text occurrence within a string
@@ -1891,11 +1906,13 @@ void TextAppend(char *text, const char *append, int *position)
int TextFindIndex(const char *text, const char *search)
{
int position = -1;
- if (text == NULL) return position;
- char *ptr = (char *)strstr(text, search);
+ if (text != NULL)
+ {
+ char *ptr = (char *)strstr(text, search);
- if (ptr != NULL) position = (int)(ptr - text);
+ if (ptr != NULL) position = (int)(ptr - text);
+ }
return position;
}
@@ -2029,24 +2046,29 @@ char *TextToCamel(const char *text)
// WARNING: Allocated memory must be manually freed
char *LoadUTF8(const int *codepoints, int length)
{
- // We allocate enough memory to fit all possible codepoints
- // NOTE: 5 bytes for every codepoint should be enough
- char *text = (char *)RL_CALLOC(length*5, 1);
- const char *utf8 = NULL;
- int size = 0;
-
- for (int i = 0, bytes = 0; i < length; i++)
+ char *text = NULL;
+
+ if ((codepoints != NULL) && (length > 0))
{
- utf8 = CodepointToUTF8(codepoints[i], &bytes);
- memcpy(text + size, utf8, bytes);
- size += bytes;
- }
+ // We allocate enough memory to fit all possible codepoints
+ // NOTE: 5 bytes for every codepoint should be enough
+ text = (char *)RL_CALLOC(length*5, 1);
+ const char *utf8 = NULL;
+ int size = 0;
- // Create second buffer and copy data manually to it
- char *temp = (char *)RL_CALLOC(size + 1, 1);
- memcpy(temp, text, size);
- RL_FREE(text);
- text = temp;
+ for (int i = 0, bytes = 0; i < length; i++)
+ {
+ utf8 = CodepointToUTF8(codepoints[i], &bytes);
+ memcpy(text + size, utf8, bytes);
+ size += bytes;
+ }
+
+ // Create second buffer and copy data manually to it
+ char *temp = (char *)RL_CALLOC(size + 1, 1);
+ memcpy(temp, text, size);
+ RL_FREE(text);
+ text = temp;
+ }
return text;
}
@@ -2060,28 +2082,31 @@ void UnloadUTF8(char *text)
// Load all codepoints from a UTF-8 text string, codepoints count returned by parameter
int *LoadCodepoints(const char *text, int *count)
{
- int textLength = TextLength(text);
-
- int codepointSize = 0;
+ int *codepoints = NULL;
int codepointCount = 0;
-
- // Allocate a big enough buffer to store as many codepoints as text bytes
- int *codepoints = (int *)RL_CALLOC(textLength, sizeof(int));
-
- for (int i = 0; i < textLength; codepointCount++)
+
+ if (text != NULL)
{
- codepoints[codepointCount] = GetCodepointNext(text + i, &codepointSize);
- i += codepointSize;
+ int textLength = TextLength(text);
+
+ // Allocate a big enough buffer to store as many codepoints as text bytes
+ int *codepoints = (int *)RL_CALLOC(textLength, sizeof(int));
+
+ int codepointSize = 0;
+ for (int i = 0; i < textLength; codepointCount++)
+ {
+ codepoints[codepointCount] = GetCodepointNext(text + i, &codepointSize);
+ i += codepointSize;
+ }
+
+ // Create second buffer and copy data manually to it
+ int *temp = (int *)RL_CALLOC(codepointCount, sizeof(int));
+ for (int i = 0; i < codepointCount; i++) temp[i] = codepoints[i];
+ RL_FREE(codepoints);
+ codepoints = temp;
}
- // Create second buffer and copy data manually to it
- int *temp = (int *)RL_CALLOC(codepointCount, sizeof(int));
- for (int i = 0; i < codepointCount; i++) temp[i] = codepoints[i];
- RL_FREE(codepoints);
- codepoints = temp;
-
*count = codepointCount;
-
return codepoints;
}
@@ -2098,14 +2123,15 @@ int GetCodepointCount(const char *text)
unsigned int length = 0;
const char *ptr = text;
- while (*ptr != '\0')
+ if (ptr != NULL)
{
- int next = 0;
- GetCodepointNext(ptr, &next);
-
- ptr += next;
-
- length++;
+ while (*ptr != '\0')
+ {
+ int next = 0;
+ GetCodepointNext(ptr, &next);
+ ptr += next;
+ length++;
+ }
}
return length;
@@ -2170,11 +2196,14 @@ int GetCodepoint(const char *text, int *codepointSize)
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
- // NOTE: on decode errors we return as soon as possible
+
int codepoint = 0x3f; // Codepoint (defaults to '?')
- int octet = (unsigned char)(text[0]); // The first UTF8 octet
*codepointSize = 1;
+ if (text == NULL) return codepoint;
+
+ // NOTE: on decode errors we return as soon as possible
+ int octet = (unsigned char)(text[0]); // The first UTF8 octet
if (octet <= 0x7f)
{
@@ -2266,6 +2295,7 @@ int GetCodepointNext(const char *text, int *codepointSize)
const char *ptr = text;
int codepoint = 0x3f; // Codepoint (defaults to '?')
*codepointSize = 1;
+ if (text == NULL) return codepoint;
// Get current codepoint and bytes processed
if (0xf0 == (0xf8 & ptr[0]))
@@ -2304,15 +2334,15 @@ int GetCodepointPrevious(const char *text, int *codepointSize)
{
const char *ptr = text;
int codepoint = 0x3f; // Codepoint (defaults to '?')
- int cpSize = 0;
- *codepointSize = 0;
+ *codepointSize = 1;
+ if (text == NULL) return codepoint;
// Move to previous codepoint
do ptr--;
while (((0x80 & ptr[0]) != 0) && ((0xc0 & ptr[0]) == 0x80));
+ int cpSize = 0;
codepoint = GetCodepointNext(ptr, &cpSize);
-
if (codepoint != 0) *codepointSize = cpSize;
return codepoint;
@@ -2450,7 +2480,7 @@ static Font LoadBMFont(const char *fileName)
RL_FREE(imFonts);
- if (isGpuReady) font.texture = LoadTextureFromImage(fullFont);
+ font.texture = LoadTextureFromImage(fullFont);
// Fill font characters info data
font.baseSize = fontSize;
@@ -2459,7 +2489,15 @@ static Font LoadBMFont(const char *fileName)
font.glyphs = (GlyphInfo *)RL_MALLOC(glyphCount*sizeof(GlyphInfo));
font.recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle));
- int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX, pageID;
+ int charId = 0;
+ int charX = 0;
+ int charY = 0;
+ int charWidth = 0;
+ int charHeight = 0;
+ int charOffsetX = 0;
+ int charOffsetY = 0;
+ int charAdvanceX = 0;
+ int pageID = 0;
for (int i = 0; i < glyphCount; i++)
{
@@ -2492,7 +2530,7 @@ static Font LoadBMFont(const char *fileName)
UnloadImage(fullFont);
UnloadFileText(fileText);
- if (isGpuReady && (font.texture.id == 0))
+ if (font.texture.id == 0)
{
UnloadFont(font);
font = GetFontDefault();
diff --git a/src/rtextures.c b/src/rtextures.c
index 17065822a..4208b40bd 100644
--- a/src/rtextures.c
+++ b/src/rtextures.c
@@ -771,7 +771,7 @@ bool ExportImageAsCode(Image image, const char *fileName)
// Get file name from path and convert variable name to uppercase
char varFileName[256] = { 0 };
- strcpy(varFileName, GetFileNameWithoutExt(fileName));
+ strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module
for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
// Add image information
@@ -1125,17 +1125,19 @@ Image GenImageCellular(int width, int height, int tileSize)
Image GenImageText(int width, int height, const char *text)
{
Image image = { 0 };
-
- int textLength = (int)strlen(text);
- int imageViewSize = width*height;
-
+
+ int imageSize = width*height;
image.width = width;
image.height = height;
image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
- image.data = RL_CALLOC(imageViewSize, 1);
+ image.data = RL_CALLOC(imageSize, 1);
image.mipmaps = 1;
- memcpy(image.data, text, (textLength > imageViewSize)? imageViewSize : textLength);
+ if (text != NULL)
+ {
+ int textLength = (int)strlen(text);
+ memcpy(image.data, text, (textLength > imageSize)? imageSize : textLength);
+ }
return image;
}
@@ -1484,8 +1486,9 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
{
Image imText = { 0 };
#if defined(SUPPORT_MODULE_RTEXT)
- int size = (int)strlen(text); // Get size in bytes of text
-
+ if (text == NULL) return imText;
+
+ int textLength = (int)strlen(text); // Get length of text in bytes
int textOffsetX = 0; // Image drawing position X
int textOffsetY = 0; // Offset between lines (on linebreak '\n')
@@ -1496,7 +1499,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
// Create image to store text
imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK);
- for (int i = 0; i < size;)
+ for (int i = 0; i < textLength;)
{
// Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0;
@@ -1724,7 +1727,8 @@ void ImageResizeNN(Image *image, int newWidth, int newHeight)
int xRatio = (int)((image->width << 16)/newWidth) + 1;
int yRatio = (int)((image->height << 16)/newHeight) + 1;
- int x2, y2;
+ int x2 = 0;
+ int y2 = 0;
for (int y = 0; y < newHeight; y++)
{
for (int x = 0; x < newWidth; x++)
@@ -2485,8 +2489,13 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
Color oldPixel = WHITE;
Color newPixel = WHITE;
- int rError, gError, bError;
- unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition
+ int rError = 0;
+ int gError = 0;
+ int bError = 0;
+ unsigned short rPixel = 0; // Used for 16bit pixel composition
+ unsigned short gPixel = 0;
+ unsigned short bPixel = 0;
+ unsigned short aPixel = 0;
#define MIN(a,b) (((a)<(b))?(a):(b))
@@ -4003,7 +4012,9 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
// [-] GetPixelColor(): Get Vector4 instead of Color, easier for ColorAlphaBlend()
// [ ] TODO: Support 16bit and 32bit (float) channels drawing
- Color colSrc, colDst, blend;
+ Color colSrc = { 0 };
+ Color colDst = { 0 };
+ Color blend = { 0 };
bool blendRequired = true;
// Fast path: Avoid blend if source has no alpha to blend
@@ -4200,7 +4211,7 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
/*else if (layout == CUBEMAP_LAYOUT_PANORAMA)
{
// TODO: Implement panorama by converting image to square faces...
- // Ref: https://github.com/denivip/panorama/blob/master/panorama.cpp
+ // REF: https://github.com/denivip/panorama/blob/master/panorama.cpp
} */
else
{
@@ -4678,17 +4689,23 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest,
bottomBorder = patchHeight - topBorder;
}
- Vector2 vertA, vertB, vertC, vertD;
- vertA.x = 0.0f; // outer left
- vertA.y = 0.0f; // outer top
- vertB.x = leftBorder; // inner left
- vertB.y = topBorder; // inner top
- vertC.x = patchWidth - rightBorder; // inner right
- vertC.y = patchHeight - bottomBorder; // inner bottom
- vertD.x = patchWidth; // outer right
- vertD.y = patchHeight; // outer bottom
+ Vector2 vertA = { 0 };
+ Vector2 vertB = { 0 };
+ Vector2 vertC = { 0 };
+ Vector2 vertD = { 0 };
+ vertA.x = 0.0f; // Outer left
+ vertA.y = 0.0f; // Outer top
+ vertB.x = leftBorder; // Inner left
+ vertB.y = topBorder; // Inner top
+ vertC.x = patchWidth - rightBorder; // Inner right
+ vertC.y = patchHeight - bottomBorder; // Inner bottom
+ vertD.x = patchWidth; // Outer right
+ vertD.y = patchHeight; // Outer bottom
- Vector2 coordA, coordB, coordC, coordD;
+ Vector2 coordA = { 0 };
+ Vector2 coordB = { 0 };
+ Vector2 coordC = { 0 };
+ Vector2 coordD = { 0 };
coordA.x = nPatchInfo.source.x/width;
coordA.y = nPatchInfo.source.y/height;
coordB.x = (nPatchInfo.source.x + leftBorder)/width;
@@ -4904,7 +4921,9 @@ Vector3 ColorToHSV(Color color)
{
Vector3 hsv = { 0 };
Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f };
- float min, max, delta;
+ float min = 0.0f;
+ float max = 0.0f;
+ float delta = 0.0f;
min = rgb.x < rgb.y? rgb.x : rgb.y;
min = min < rgb.z? min : rgb.z;
@@ -5407,7 +5426,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 892f96cf4..09158893a 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -105,7 +105,7 @@ void TraceLog(int logType, const char *text, ...)
{
#if defined(SUPPORT_TRACELOG)
// Message has level below current threshold, don't emit
- if (logType < logTypeLevel) return;
+ if ((logType < logTypeLevel) || (text == NULL)) return;
va_list args;
va_start(args, text);
@@ -142,8 +142,8 @@ void TraceLog(int logType, const char *text, ...)
default: break;
}
- unsigned int textSize = (unsigned int)strlen(text);
- memcpy(buffer + strlen(buffer), text, (textSize < (MAX_TRACELOG_MSG_LENGTH - 12))? textSize : (MAX_TRACELOG_MSG_LENGTH - 12));
+ unsigned int textLength = (unsigned int)strlen(text);
+ memcpy(buffer + strlen(buffer), text, (textLength < (MAX_TRACELOG_MSG_LENGTH - 12))? textLength : (MAX_TRACELOG_MSG_LENGTH - 12));
strcat(buffer, "\n");
vprintf(buffer, args);
fflush(stdout);
@@ -313,7 +313,7 @@ bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileN
// Get file name from path
char varFileName[256] = { 0 };
- strcpy(varFileName, GetFileNameWithoutExt(fileName));
+ strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1);
for (int i = 0; varFileName[i] != '\0'; i++)
{
// Convert variable name to uppercase
@@ -446,7 +446,7 @@ void InitAssetManager(AAssetManager *manager, const char *dataPath)
}
// Replacement for fopen()
-// Ref: https://developer.android.com/ndk/reference/group/asset
+// REF: https://developer.android.com/ndk/reference/group/asset
FILE *android_fopen(const char *fileName, const char *mode)
{
if (mode[0] == 'w')
@@ -454,7 +454,7 @@ FILE *android_fopen(const char *fileName, const char *mode)
// NOTE: fopen() is mapped to android_fopen() that only grants read access to
// assets directory through AAssetManager but we want to also be able to
// write data when required using the standard stdio FILE access functions
- // Ref: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only
+ // REF: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only
#undef fopen
return fopen(TextFormat("%s/%s", internalDataPath, fileName), mode);
#define fopen(name, mode) android_fopen(name, mode)
diff --git a/tools/rexm/reports/examples_issues.md b/tools/rexm/reports/examples_issues.md
index 081170806..14e7a61c5 100644
--- a/tools/rexm/reports/examples_issues.md
+++ b/tools/rexm/reports/examples_issues.md
@@ -21,9 +21,10 @@ Example elements validated:
| **EXAMPLE NAME** | [C] | [CAT]| [INFO]|[PNG]|[WPNG]| [RES]| [MK] |[MKWEB]| [VCX]| [SOL]|[RDME]|[JS] | [WOUT]|[WMETA]|
|:---------------------------------|:---:|:----:|:-----:|:---:|:----:|:----:|:----:|:-----:|:----:|:----:|:----:|:---:|:-----:|:-----:|
| core_highdpi_testbed | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| rlgl_standalone | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| rlgl_compute_shader | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
-| embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ |
+| rlgl_standalone | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ |
+| rlgl_compute_shader | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ |
+| easings_testbed | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ❌ | ✔ | ❌ | ✔ | ✔ |
+| embedded_files_loading | ✔ | ❌ | ❌ | ✔ | ✔ | ❌ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ |
+| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
diff --git a/tools/rexm/reports/examples_validation.md b/tools/rexm/reports/examples_validation.md
index af3befad9..45c195415 100644
--- a/tools/rexm/reports/examples_validation.md
+++ b/tools/rexm/reports/examples_validation.md
@@ -103,6 +103,8 @@ Example elements validated:
| shapes_math_angle_rotation | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_rlgl_color_wheel | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_rlgl_triangle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_ball_physics | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_penrose_tile | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -131,6 +133,7 @@ Example elements validated:
| textures_screen_buffer | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_textured_curve | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_sprite_stacking | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| textures_cellular_automata | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_sprite_fonts | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_font_spritefont | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_font_filters | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -146,6 +149,7 @@ Example elements validated:
| text_codepoints_loading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_inline_styling | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_words_alignment | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| text_strings_management | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| models_animation_playing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| models_billboard_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| models_box_collisions | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -205,6 +209,7 @@ Example elements validated:
| shaders_lightmap_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_rounded_rectangle | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_depth_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shaders_game_of_life | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ |
| audio_module_playing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_music_stream | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_raw_stream | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -214,9 +219,9 @@ Example elements validated:
| audio_sound_multi | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_sound_positioning | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| audio_spectrum_visualizer | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| rlgl_standalone | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| rlgl_compute_shader | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
-| embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| rlgl_standalone | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ |
+| rlgl_compute_shader | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ |
+| easings_testbed | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ❌ | ✔ | ❌ | ✔ | ✔ |
+| embedded_files_loading | ✔ | ❌ | ❌ | ✔ | ✔ | ❌ | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ |
+| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c
index 72b962874..aa491ff23 100644
--- a/tools/rexm/rexm.c
+++ b/tools/rexm/rexm.c
@@ -72,6 +72,12 @@
// Create local commit with changes on example renaming
//#define RENAME_AUTO_COMMIT_CREATION
+#if defined(__GNUC__) // GCC and Clang
+ #pragma GCC diagnostic push
+ // Avoid GCC/Clang complaining about sprintf() second parameter not being a string literal (being TextFormat())
+ #pragma GCC diagnostic ignored "-Wformat-security"
+#endif
+
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
@@ -1002,6 +1008,7 @@ int main(int argc, char *argv[])
LOG("INFO: Scanning available example (.c) files to be added to collection...\n");
FilePathList clist = LoadDirectoryFilesEx(exBasePath, ".c", true);
+ // Load examples collection list file (raylib/examples/examples_list.txt)
char *exList = LoadFileText(exCollectionFilePath);
char *exListUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
bool listUpdated = false;
@@ -1018,7 +1025,7 @@ int main(int argc, char *argv[])
for (int i = 1; i < lineCount; i++)
{
- if ((TextFindIndex(exListUpdated, exListLines[i]) == -1) || (exListLines[i][0] == '#'))
+ if ((TextFindIndex(exListUpdated, exListLines[i]) == -1) || (exListLines[i][0] == '#'))
exListUpdatedOffset += sprintf(exListUpdated + exListUpdatedOffset, "%s\n", exListLines[i]);
else listUpdated = true;
}
@@ -2322,7 +2329,7 @@ static rlExampleInfo *LoadExampleInfo(const char *exFileName)
// Example found in collection
exInfo = (rlExampleInfo *)RL_CALLOC(1, sizeof(rlExampleInfo));
- strcpy(exInfo->name, GetFileNameWithoutExt(exFileName));
+ strncpy(exInfo->name, GetFileNameWithoutExt(exFileName), 128 - 1);
strncpy(exInfo->category, exInfo->name, TextFindIndex(exInfo->name, "_"));
char *exText = LoadFileText(exFileName);
@@ -2505,7 +2512,7 @@ static char **LoadExampleResourcePaths(const char *filePath, int *resPathCount)
if (!end) break;
// WARNING: Some paths could be for saving files, not loading, those "resource" files must be omitted
- // HACK: Just check previous position from pointer for function name including the string and the index "distance"
+ // TODO: HACK: Just check previous position from pointer for function name including the string and the index "distance"
// This is a quick solution, the good one would be getting the data loading function names...
int functionIndex01 = TextFindIndex(ptr - 40, "ExportImage"); // Check ExportImage()
int functionIndex02 = TextFindIndex(ptr - 10, "TraceLog"); // Check TraceLog()
@@ -2863,8 +2870,8 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath)
char exTitle[64] = { 0 }; // Example title: fileName without extension, replacing underscores by spaces
// Get example name: replace underscore by spaces
- strcpy(exName, GetFileNameWithoutExt(exHtmlPathCopy));
- strcpy(exTitle, exName);
+ strncpy(exName, GetFileNameWithoutExt(exHtmlPathCopy), 64 - 1);
+ strncpy(exTitle, exName, 64 - 1);
for (int i = 0; (i < 256) && (exTitle[i] != '\0'); i++) { if (exTitle[i] == '_') exTitle[i] = ' '; }
// Get example category from exName: copy until first underscore
@@ -2917,3 +2924,6 @@ static bool TextInList(const char *text, const char **list, int listCount)
return result;
}
+#if defined(__GNUC__) // GCC and Clang
+ #pragma GCC diagnostic pop
+#endif
diff --git a/tools/rlparser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json
index b3d02a928..66d8e9f30 100644
--- a/tools/rlparser/output/raylib_api.json
+++ b/tools/rlparser/output/raylib_api.json
@@ -769,22 +769,22 @@
{
"type": "Vector2",
"name": "offset",
- "description": "Camera offset (displacement from target)"
+ "description": "Camera offset (screen space offset from window origin)"
},
{
"type": "Vector2",
"name": "target",
- "description": "Camera target (rotation and zoom origin)"
+ "description": "Camera target (world space target point that is mapped to screen space offset)"
},
{
"type": "float",
"name": "rotation",
- "description": "Camera rotation in degrees"
+ "description": "Camera rotation in degrees (pivots around target)"
},
{
"type": "float",
"name": "zoom",
- "description": "Camera zoom (scaling), should be 1.0f by default"
+ "description": "Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale"
}
]
},
@@ -4646,7 +4646,7 @@
"params": [
{
"type": "const char *",
- "name": "dir"
+ "name": "dirPath"
}
]
},
@@ -11730,7 +11730,7 @@
},
{
"name": "UpdateSound",
- "description": "Update sound buffer with new data (data and frame count should fit in sound)",
+ "description": "Update sound buffer with new data (default data format: 32 bit float, stereo)",
"returnType": "void",
"params": [
{
diff --git a/tools/rlparser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua
index e680a5acf..192ad963a 100644
--- a/tools/rlparser/output/raylib_api.lua
+++ b/tools/rlparser/output/raylib_api.lua
@@ -769,22 +769,22 @@ return {
{
type = "Vector2",
name = "offset",
- description = "Camera offset (displacement from target)"
+ description = "Camera offset (screen space offset from window origin)"
},
{
type = "Vector2",
name = "target",
- description = "Camera target (rotation and zoom origin)"
+ description = "Camera target (world space target point that is mapped to screen space offset)"
},
{
type = "float",
name = "rotation",
- description = "Camera rotation in degrees"
+ description = "Camera rotation in degrees (pivots around target)"
},
{
type = "float",
name = "zoom",
- description = "Camera zoom (scaling), should be 1.0f by default"
+ description = "Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale"
}
}
},
@@ -4167,7 +4167,7 @@ return {
description = "Change working directory, return true on success",
returnType = "bool",
params = {
- {type = "const char *", name = "dir"}
+ {type = "const char *", name = "dirPath"}
}
},
{
@@ -7995,7 +7995,7 @@ return {
},
{
name = "UpdateSound",
- description = "Update sound buffer with new data (data and frame count should fit in sound)",
+ description = "Update sound buffer with new data (default data format: 32 bit float, stereo)",
returnType = "void",
params = {
{type = "Sound", name = "sound"},
diff --git a/tools/rlparser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt
index e2edb8f3f..f60f8fc81 100644
--- a/tools/rlparser/output/raylib_api.txt
+++ b/tools/rlparser/output/raylib_api.txt
@@ -399,10 +399,10 @@ Struct 13: Camera3D (5 fields)
Struct 14: Camera2D (4 fields)
Name: Camera2D
Description: Camera2D, defines position/orientation in 2d space
- Field[1]: Vector2 offset // Camera offset (displacement from target)
- Field[2]: Vector2 target // Camera target (rotation and zoom origin)
- Field[3]: float rotation // Camera rotation in degrees
- Field[4]: float zoom // Camera zoom (scaling), should be 1.0f by default
+ Field[1]: Vector2 offset // Camera offset (screen space offset from window origin)
+ Field[2]: Vector2 target // Camera target (world space target point that is mapped to screen space offset)
+ Field[3]: float rotation // Camera rotation in degrees (pivots around target)
+ Field[4]: float zoom // Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale
Struct 15: Mesh (17 fields)
Name: Mesh
Description: Mesh, vertex data and vao/vbo
@@ -1763,7 +1763,7 @@ Function 143: ChangeDirectory() (1 input parameters)
Name: ChangeDirectory
Return type: bool
Description: Change working directory, return true on success
- Param[1]: dir (type: const char *)
+ Param[1]: dirPath (type: const char *)
Function 144: IsPathFile() (1 input parameters)
Name: IsPathFile
Return type: bool
@@ -4483,7 +4483,7 @@ Function 543: IsSoundValid() (1 input parameters)
Function 544: UpdateSound() (3 input parameters)
Name: UpdateSound
Return type: void
- Description: Update sound buffer with new data (data and frame count should fit in sound)
+ Description: Update sound buffer with new data (default data format: 32 bit float, stereo)
Param[1]: sound (type: Sound)
Param[2]: data (type: const void *)
Param[3]: sampleCount (type: int)
diff --git a/tools/rlparser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml
index 3d1892c7c..1bbeb175c 100644
--- a/tools/rlparser/output/raylib_api.xml
+++ b/tools/rlparser/output/raylib_api.xml
@@ -155,10 +155,10 @@
-
-
-
-
+
+
+
+
@@ -1111,7 +1111,7 @@
-
+
@@ -2998,7 +2998,7 @@
-
+