diff --git a/BINDINGS.md b/BINDINGS.md
index e79d39c36..576d9b463 100644
--- a/BINDINGS.md
+++ b/BINDINGS.md
@@ -31,7 +31,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [raylib-go](https://github.com/gen2brain/raylib-go) | **5.0** | [Go](https://golang.org) | Zlib |
| [raylib-guile](https://github.com/petelliott/raylib-guile) | **auto** | [Guile](https://www.gnu.org/software/guile) | Zlib |
| [gforth-raylib](https://github.com/ArnautDaniel/gforth-raylib) | 3.5 | [Gforth](https://gforth.org) | **???** |
-| [h-raylib](https://github.com/Anut-py/h-raylib) | **5.1-dev** | [Haskell](https://haskell.org) | Apache-2.0 |
+| [h-raylib](https://github.com/Anut-py/h-raylib) | **5.5-dev** | [Haskell](https://haskell.org) | Apache-2.0 |
| [raylib-hx](https://github.com/foreignsasquatch/raylib-hx) | 4.2 | [Haxe](https://haxe.org) | Zlib |
| [hb-raylib](https://github.com/MarcosLeonardoMendezGerencir/hb-raylib) | 3.5 | [Harbour](https://harbour.github.io) | MIT |
| [jaylib](https://github.com/janet-lang/jaylib) | **5.0** | [Janet](https://janet-lang.org) | MIT |
diff --git a/CHANGELOG b/CHANGELOG
index 2141926ce..b5b50e4d7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,17 @@ changelog
Current Release: raylib 5.0 (18 November 2023)
+-------------------------------------------------------------------------
+Release: raylib 5.5 - 11th Anniversary Edition? (18 November 2024?)
+-------------------------------------------------------------------------
+KEY CHANGES:
+ -
+ -
+ -
+
+Detailed changes:
+...
+
-------------------------------------------------------------------------
Release: raylib 5.0 - 10th Anniversary Edition (18 November 2023)
-------------------------------------------------------------------------
diff --git a/build.zig b/build.zig
index 01e7b49fb..029482608 100644
--- a/build.zig
+++ b/build.zig
@@ -9,3 +9,6 @@ pub fn build(b: *std.Build) !void {
// expose helper functions to user's build.zig
pub const addRaylib = raylib.addRaylib;
pub const addRaygui = raylib.addRaygui;
+
+// expose options for compiling
+pub const RaylibOptions = raylib.Options;
diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake
index 6d2250c71..fb7898306 100644
--- a/cmake/LibraryConfigurations.cmake
+++ b/cmake/LibraryConfigurations.cmake
@@ -100,9 +100,10 @@ elseif ("${PLATFORM}" MATCHES "SDL")
endif ()
if (NOT ${OPENGL_VERSION} MATCHES "OFF")
- set(${SUGGESTED_GRAPHICS} "${GRAPHICS}")
+ set(SUGGESTED_GRAPHICS "${GRAPHICS}")
+
if (${OPENGL_VERSION} MATCHES "4.3")
- set(GRAPHICS "GRAPHICS_API_OPENGL_43")
+ set(GRAPHICS "GRAPHICS_API_OPENGL_43")
elseif (${OPENGL_VERSION} MATCHES "3.3")
set(GRAPHICS "GRAPHICS_API_OPENGL_33")
elseif (${OPENGL_VERSION} MATCHES "2.1")
@@ -114,8 +115,8 @@ if (NOT ${OPENGL_VERSION} MATCHES "OFF")
elseif (${OPENGL_VERSION} MATCHES "ES 3.0")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES3")
endif ()
- if ("${SUGGESTED_GRAPHICS}" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}")
- message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail")
+ if (NOT "${SUGGESTED_GRAPHICS}" STREQUAL "" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}")
+ message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail.")
endif ()
endif ()
diff --git a/examples/Makefile b/examples/Makefile
index c17258427..65ee4fb80 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -492,6 +492,7 @@ CORE = \
core/core_input_mouse \
core/core_input_mouse_wheel \
core/core_input_multitouch \
+ core/core_input_virtual_controls \
core/core_loading_thread \
core/core_random_sequence \
core/core_random_values \
@@ -548,7 +549,6 @@ TEXTURES = \
textures/textures_sprite_button \
textures/textures_sprite_explosion \
textures/textures_srcrec_dstrec \
- textures/textures_svg_loading \
textures/textures_textured_curve \
textures/textures_to_image
diff --git a/examples/Makefile.Web b/examples/Makefile.Web
index bd48c2a4a..f6c8b785a 100644
--- a/examples/Makefile.Web
+++ b/examples/Makefile.Web
@@ -359,6 +359,7 @@ CORE = \
core/core_input_mouse \
core/core_input_mouse_wheel \
core/core_input_multitouch \
+ core/core_input_virtual_controls \
core/core_loading_thread \
core/core_random_sequence \
core/core_random_values \
@@ -414,7 +415,6 @@ TEXTURES = \
textures/textures_sprite_button \
textures/textures_sprite_explosion \
textures/textures_srcrec_dstrec \
- textures/textures_svg_loading \
textures/textures_textured_curve \
textures/textures_to_image
@@ -775,10 +775,6 @@ textures/textures_srcrec_dstrec: textures/textures_srcrec_dstrec.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/scarfy.png@resources/scarfy.png
-textures/textures_svg_loading: textures/textures_svg_loading.c
- $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
- --preload-file textures/resources/test.svg
-
textures/textures_textured_curve: textures/textures_textured_curve.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/road.png@resources/road.png
diff --git a/examples/README.md b/examples/README.md
index d573ff23e..ee528d049 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -31,31 +31,32 @@ Examples using raylib core platform functionality like window creation, inputs,
| 05 | [core_input_gamepad](core/core_input_gamepad.c) |
| ⭐️☆☆☆ | 1.1 | **4.2** | [Ray](https://github.com/raysan5) |
| 06 | [core_input_multitouch](core/core_input_multitouch.c) |
| ⭐️☆☆☆ | 2.1 | 2.5 | [Berni](https://github.com/Berni8k) |
| 07 | [core_input_gestures](core/core_input_gestures.c) |
| ⭐️⭐️☆☆ | 1.4 | **4.2** | [Ray](https://github.com/raysan5) |
-| 08 | [core_2d_camera](core/core_2d_camera.c) |
| ⭐️⭐️☆☆ | 1.5 | 3.0 | [Ray](https://github.com/raysan5) |
-| 09 | [core_2d_camera_mouse_zoom](core/core_2d_camera_mouse_zoom.c) |
| ⭐️⭐️☆☆ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) |
-| 10 | [core_2d_camera_platformer](core/core_2d_camera_platformer.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [avyy](https://github.com/avyy) |
-| 11 | [core_2d_camera_split_screen](core/core_2d_camera_split_screen.c) |
| ⭐️⭐️⭐️⭐️ | **4.5** | **4.5** | [Gabriel dos Santos Sanches](https://github.com/gabrielssanches) |
-| 12 | [core_3d_camera_mode](core/core_3d_camera_mode.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
-| 13 | [core_3d_camera_free](core/core_3d_camera_free.c) |
| ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
-| 14 | [core_3d_camera_first_person](core/core_3d_camera_first_person.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
-| 15 | [core_3d_camera:split_screen](core/core_3d_camera_split_screen.c) |
| ⭐️⭐️⭐️⭐️ | 3.7 | **4.0** | [Jeffery Myers](https://github.com/JeffM2501) |
-| 16 | [core_3d_picking](core/core_3d_picking.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 17 | [core_world_screen](core/core_world_screen.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.4 | [Ray](https://github.com/raysan5) |
-| 18 | [core_custom_logging](core/core_custom_logging.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Pablo Marcos Oltra](https://github.com/pamarcos) |
-| 19 | [core_window_flags](core/core_window_flags.c) |
| ⭐️⭐️⭐️☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 20 | [core_window_letterbox](core/core_window_letterbox.c) |
| ⭐️⭐️☆☆ | 2.5 | **4.0** | [Anata](https://github.com/anatagawa) |
-| 21 | [core_window_should_close](core/core_window_should_close.c) |
| ⭐️☆☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
-| 22 | [core_drop_files](core/core_drop_files.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
-| 23 | [core_random_values](core/core_random_values.c) |
| ⭐️☆☆☆ | 1.1 | 1.1 | [Ray](https://github.com/raysan5) |
-| 24 | [core_storage_values](core/core_storage_values.c) |
| ⭐️⭐️☆☆ | 1.4 | **4.2** | [Ray](https://github.com/raysan5) |
-| 25 | [core_vr_simulator](core/core_vr_simulator.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
-| 26 | [core_loading_thread](core/core_loading_thread.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [Ray](https://github.com/raysan5) |
-| 27 | [core_scissor_test](core/core_scissor_test.c) |
| ⭐️☆☆☆ | 2.5 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) |
-| 28 | [core_basic_screen_manager](core/core_basic_screen_manager.c) |
| ⭐️☆☆☆ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) |
-| 29 | [core_custom_frame_control](core/core_custom_frame_control.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) |
-| 30 | [core_smooth_pixelperfect](core/core_smooth_pixelperfect.c) |
| ⭐️⭐️⭐️☆ | 3.7 | **4.0** | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) |
-| 31 | [core_window_should_close](core/core_window_should_close.c) |
| ⭐️⭐️☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
-| 32 | [core_random_sequence](core/core_random_sequence.c) |
| ⭐️☆☆☆ | **5.0** | **5.0** | [REDl3east](https://github.com/REDl3east) |
+| 08 | [core_input_virtual_controls](core/core_input_virtual_controls.c) |
| ⭐️⭐️☆☆ | **5.0** | **5.0** | [oblerion](https://github.com/oblerion) |
+| 09 | [core_2d_camera](core/core_2d_camera.c) |
| ⭐️⭐️☆☆ | 1.5 | 3.0 | [Ray](https://github.com/raysan5) |
+| 10 | [core_2d_camera_mouse_zoom](core/core_2d_camera_mouse_zoom.c) |
| ⭐️⭐️☆☆ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) |
+| 11 | [core_2d_camera_platformer](core/core_2d_camera_platformer.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [avyy](https://github.com/avyy) |
+| 12 | [core_2d_camera_split_screen](core/core_2d_camera_split_screen.c) |
| ⭐️⭐️⭐️⭐️ | **4.5** | **4.5** | [Gabriel dos Santos Sanches](https://github.com/gabrielssanches) |
+| 13 | [core_3d_camera_mode](core/core_3d_camera_mode.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
+| 14 | [core_3d_camera_free](core/core_3d_camera_free.c) |
| ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
+| 15 | [core_3d_camera_first_person](core/core_3d_camera_first_person.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
+| 16 | [core_3d_camera:split_screen](core/core_3d_camera_split_screen.c) |
| ⭐️⭐️⭐️⭐️ | 3.7 | **4.0** | [Jeffery Myers](https://github.com/JeffM2501) |
+| 17 | [core_3d_picking](core/core_3d_picking.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 18 | [core_world_screen](core/core_world_screen.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.4 | [Ray](https://github.com/raysan5) |
+| 19 | [core_custom_logging](core/core_custom_logging.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Pablo Marcos Oltra](https://github.com/pamarcos) |
+| 20 | [core_window_flags](core/core_window_flags.c) |
| ⭐️⭐️⭐️☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 21 | [core_window_letterbox](core/core_window_letterbox.c) |
| ⭐️⭐️☆☆ | 2.5 | **4.0** | [Anata](https://github.com/anatagawa) |
+| 22 | [core_window_should_close](core/core_window_should_close.c) |
| ⭐️☆☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
+| 23 | [core_drop_files](core/core_drop_files.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
+| 24 | [core_random_values](core/core_random_values.c) |
| ⭐️☆☆☆ | 1.1 | 1.1 | [Ray](https://github.com/raysan5) |
+| 25 | [core_storage_values](core/core_storage_values.c) |
| ⭐️⭐️☆☆ | 1.4 | **4.2** | [Ray](https://github.com/raysan5) |
+| 26 | [core_vr_simulator](core/core_vr_simulator.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
+| 27 | [core_loading_thread](core/core_loading_thread.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [Ray](https://github.com/raysan5) |
+| 28 | [core_scissor_test](core/core_scissor_test.c) |
| ⭐️☆☆☆ | 2.5 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) |
+| 29 | [core_basic_screen_manager](core/core_basic_screen_manager.c) |
| ⭐️☆☆☆ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) |
+| 30 | [core_custom_frame_control](core/core_custom_frame_control.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) |
+| 31 | [core_smooth_pixelperfect](core/core_smooth_pixelperfect.c) |
| ⭐️⭐️⭐️☆ | 3.7 | **4.0** | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) |
+| 32 | [core_window_should_close](core/core_window_should_close.c) |
| ⭐️⭐️☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
+| 33 | [core_random_sequence](core/core_random_sequence.c) |
| ⭐️☆☆☆ | **5.0** | **5.0** | [REDl3east](https://github.com/REDl3east) |
### category: shapes
@@ -63,22 +64,22 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes](
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 31 | [shapes_basic_shapes](shapes/shapes_basic_shapes.c) |
| ⭐️☆☆☆ | 1.0 | **4.0** | [Ray](https://github.com/raysan5) |
-| 32 | [shapes_bouncing_ball](shapes/shapes_bouncing_ball.c) |
| ⭐️☆☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 33 | [shapes_colors_palette](shapes/shapes_colors_palette.c) |
| ⭐️⭐️☆☆ | 1.0 | 2.5 | [Ray](https://github.com/raysan5) |
-| 34 | [shapes_logo_raylib](shapes/shapes_logo_raylib.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
-| 35 | [shapes_logo_raylib_anim](shapes/shapes_logo_raylib_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
-| 36 | [shapes_rectangle_scaling](shapes/shapes_rectangle_scaling.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
-| 37 | [shapes_lines_bezier](shapes/shapes_lines_bezier.c) |
| ⭐️☆☆☆ | 1.7 | 1.7 | [Ray](https://github.com/raysan5) |
-| 38 | [shapes_collision_area](shapes/shapes_collision_area.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 39 | [shapes_following_eyes](shapes/shapes_following_eyes.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 40 | [shapes_easings_ball_anim](shapes/shapes_easings_ball_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 41 | [shapes_easings_box_anim](shapes/shapes_easings_box_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 42 | [shapes_easings_rectangle_array](shapes/shapes_easings_rectangle_array.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 43 | [shapes_draw_ring](shapes/shapes_draw_ring.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
-| 44 | [shapes_draw_circle_sector](shapes/shapes_draw_circle_sector.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
-| 45 | [shapes_draw_rectangle_rounded](shapes/shapes_draw_rectangle_rounded.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
-| 46 | [shapes_top_down_lights](shapes/shapes_top_down_lights.c) |
| ⭐️⭐️⭐️⭐️ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) |
+| 34 | [shapes_basic_shapes](shapes/shapes_basic_shapes.c) |
| ⭐️☆☆☆ | 1.0 | **4.0** | [Ray](https://github.com/raysan5) |
+| 35 | [shapes_bouncing_ball](shapes/shapes_bouncing_ball.c) |
| ⭐️☆☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 36 | [shapes_colors_palette](shapes/shapes_colors_palette.c) |
| ⭐️⭐️☆☆ | 1.0 | 2.5 | [Ray](https://github.com/raysan5) |
+| 37 | [shapes_logo_raylib](shapes/shapes_logo_raylib.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
+| 38 | [shapes_logo_raylib_anim](shapes/shapes_logo_raylib_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
+| 39 | [shapes_rectangle_scaling](shapes/shapes_rectangle_scaling.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
+| 40 | [shapes_lines_bezier](shapes/shapes_lines_bezier.c) |
| ⭐️☆☆☆ | 1.7 | 1.7 | [Ray](https://github.com/raysan5) |
+| 41 | [shapes_collision_area](shapes/shapes_collision_area.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 42 | [shapes_following_eyes](shapes/shapes_following_eyes.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 43 | [shapes_easings_ball_anim](shapes/shapes_easings_ball_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 44 | [shapes_easings_box_anim](shapes/shapes_easings_box_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 45 | [shapes_easings_rectangle_array](shapes/shapes_easings_rectangle_array.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 46 | [shapes_draw_ring](shapes/shapes_draw_ring.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
+| 47 | [shapes_draw_circle_sector](shapes/shapes_draw_circle_sector.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
+| 48 | [shapes_draw_rectangle_rounded](shapes/shapes_draw_rectangle_rounded.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
+| 49 | [shapes_top_down_lights](shapes/shapes_top_down_lights.c) |
| ⭐️⭐️⭐️⭐️ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) |
### category: textures
@@ -86,28 +87,28 @@ Examples using raylib textures functionality, including image/textures loading/g
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 47 | [textures_logo_raylib](textures/textures_logo_raylib.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
-| 48 | [textures_srcrec_dstrec](textures/textures_srcrec_dstrec.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
-| 49 | [textures_image_drawing](textures/textures_image_drawing.c) |
| ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
-| 50 | [textures_image_generation](textures/textures_image_generation.c) |
| ⭐️⭐️☆☆ | 1.8 | 1.8 | [Ray](https://github.com/raysan5) |
-| 51 | [textures_image_loading](textures/textures_image_loading.c) |
| ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
-| 52 | [textures_image_processing](textures/textures_image_processing.c) |
| ⭐️⭐️⭐️☆ | 1.4 | 3.5 | [Ray](https://github.com/raysan5) |
-| 53 | [textures_image_text](textures/textures_image_text.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
-| 54 | [textures_to_image](textures/textures_to_image.c) |
| ⭐️☆☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 55 | [textures_raw_data](textures/textures_raw_data.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
-| 56 | [textures_particles_blending](textures/textures_particles_blending.c) |
| ⭐️☆☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
-| 57 | [textures_npatch_drawing](textures/textures_npatch_drawing.c) |
| ⭐️⭐️⭐️☆ | 2.0 | 2.5 | [Jorge A. Gomes](https://github.com/overdev) |
-| 58 | [textures_background_scrolling](textures/textures_background_scrolling.c) |
| ⭐️☆☆☆ | 2.0 | 2.5 | [Ray](https://github.com/raysan5) |
-| 59 | [textures_sprite_anim](textures/textures_sprite_anim.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
-| 60 | [textures_sprite_button](textures/textures_sprite_button.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 61 | [textures_sprite_explosion](textures/textures_sprite_explosion.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 62 | [textures_bunnymark](textures/textures_bunnymark.c) |
| ⭐️⭐️⭐️☆ | 1.6 | 2.5 | [Ray](https://github.com/raysan5) |
-| 63 | [textures_mouse_painting](textures/textures_mouse_painting.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) |
-| 64 | [textures_blend_modes](textures/textures_blend_modes.c) |
| ⭐️☆☆☆ | 3.5 | 3.5 | [Karlo Licudine](https://github.com/accidentalrebel) |
-| 65 | [textures_draw_tiled](textures/textures_draw_tiled.c) |
| ⭐️⭐️⭐️☆ | 3.0 | **4.2** | [Vlad Adrian](https://github.com/demizdor) |
-| 66 | [textures_polygon](textures/textures_polygon.c) |
| ⭐️☆☆☆ | 3.7 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 67 | [textures_fog_of_war](textures/textures_fog_of_war.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
-| 68 | [textures_gif_player](textures/textures_gif_player.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
+| 50 | [textures_logo_raylib](textures/textures_logo_raylib.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
+| 51 | [textures_srcrec_dstrec](textures/textures_srcrec_dstrec.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
+| 52 | [textures_image_drawing](textures/textures_image_drawing.c) |
| ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
+| 53 | [textures_image_generation](textures/textures_image_generation.c) |
| ⭐️⭐️☆☆ | 1.8 | 1.8 | [Ray](https://github.com/raysan5) |
+| 54 | [textures_image_loading](textures/textures_image_loading.c) |
| ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
+| 55 | [textures_image_processing](textures/textures_image_processing.c) |
| ⭐️⭐️⭐️☆ | 1.4 | 3.5 | [Ray](https://github.com/raysan5) |
+| 56 | [textures_image_text](textures/textures_image_text.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
+| 57 | [textures_to_image](textures/textures_to_image.c) |
| ⭐️☆☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 58 | [textures_raw_data](textures/textures_raw_data.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
+| 59 | [textures_particles_blending](textures/textures_particles_blending.c) |
| ⭐️☆☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
+| 60 | [textures_npatch_drawing](textures/textures_npatch_drawing.c) |
| ⭐️⭐️⭐️☆ | 2.0 | 2.5 | [Jorge A. Gomes](https://github.com/overdev) |
+| 61 | [textures_background_scrolling](textures/textures_background_scrolling.c) |
| ⭐️☆☆☆ | 2.0 | 2.5 | [Ray](https://github.com/raysan5) |
+| 62 | [textures_sprite_anim](textures/textures_sprite_anim.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
+| 63 | [textures_sprite_button](textures/textures_sprite_button.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 64 | [textures_sprite_explosion](textures/textures_sprite_explosion.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 65 | [textures_bunnymark](textures/textures_bunnymark.c) |
| ⭐️⭐️⭐️☆ | 1.6 | 2.5 | [Ray](https://github.com/raysan5) |
+| 66 | [textures_mouse_painting](textures/textures_mouse_painting.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) |
+| 67 | [textures_blend_modes](textures/textures_blend_modes.c) |
| ⭐️☆☆☆ | 3.5 | 3.5 | [Karlo Licudine](https://github.com/accidentalrebel) |
+| 68 | [textures_draw_tiled](textures/textures_draw_tiled.c) |
| ⭐️⭐️⭐️☆ | 3.0 | **4.2** | [Vlad Adrian](https://github.com/demizdor) |
+| 69 | [textures_polygon](textures/textures_polygon.c) |
| ⭐️☆☆☆ | 3.7 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 70 | [textures_fog_of_war](textures/textures_fog_of_war.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
+| 71 | [textures_gif_player](textures/textures_gif_player.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
### category: text
@@ -115,18 +116,18 @@ Examples using raylib text functionality, including sprite fonts loading/generat
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 69 | [text_raylib_fonts](text/text_raylib_fonts.c) |
| ⭐️☆☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
-| 70 | [text_font_spritefont](text/text_font_spritefont.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
-| 71 | [text_font_filters](text/text_font_filters.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
-| 72 | [text_font_loading](text/text_font_loading.c) |
| ⭐️☆☆☆ | 1.4 | 3.0 | [Ray](https://github.com/raysan5) |
-| 73 | [text_font_sdf](text/text_font_sdf.c) |
| ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 74 | [text_format_text](text/text_format_text.c) |
| ⭐️☆☆☆ | 1.1 | 3.0 | [Ray](https://github.com/raysan5) |
-| 75 | [text_input_box](text/text_input_box.c) |
| ⭐️⭐️☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
-| 76 | [text_writing_anim](text/text_writing_anim.c) |
| ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
-| 77 | [text_rectangle_bounds](text/text_rectangle_bounds.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
-| 78 | [text_unicode](text/text_unicode.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
-| 79 | [text_draw_3d](text/text_draw_3d.c) |
| ⭐️⭐️⭐️⭐️ | 3.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
-| 80 | [text_codepoints_loading](text/text_codepoints_loading.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
+| 72 | [text_raylib_fonts](text/text_raylib_fonts.c) |
| ⭐️☆☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
+| 73 | [text_font_spritefont](text/text_font_spritefont.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
+| 74 | [text_font_filters](text/text_font_filters.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
+| 75 | [text_font_loading](text/text_font_loading.c) |
| ⭐️☆☆☆ | 1.4 | 3.0 | [Ray](https://github.com/raysan5) |
+| 76 | [text_font_sdf](text/text_font_sdf.c) |
| ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 77 | [text_format_text](text/text_format_text.c) |
| ⭐️☆☆☆ | 1.1 | 3.0 | [Ray](https://github.com/raysan5) |
+| 78 | [text_input_box](text/text_input_box.c) |
| ⭐️⭐️☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
+| 79 | [text_writing_anim](text/text_writing_anim.c) |
| ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
+| 80 | [text_rectangle_bounds](text/text_rectangle_bounds.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
+| 81 | [text_unicode](text/text_unicode.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
+| 82 | [text_draw_3d](text/text_draw_3d.c) |
| ⭐️⭐️⭐️⭐️ | 3.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
+| 83 | [text_codepoints_loading](text/text_codepoints_loading.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
### category: models
@@ -134,25 +135,25 @@ Examples using raylib models functionality, including models loading/generation
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 81 | [models_animation](models/models_animation.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [culacant](https://github.com/culacant) |
-| 82 | [models_billboard](models/models_billboard.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
-| 83 | [models_box_collisions](models/models_box_collisions.c) |
| ⭐️☆☆☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
-| 84 | [models_cubicmap](models/models_cubicmap.c) |
| ⭐️⭐️☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
-| 85 | [models_first_person_maze](models/models_first_person_maze.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 86 | [models_geometric_shapes](models/models_geometric_shapes.c) |
| ⭐️☆☆☆ | 1.0 | 3.5 | [Ray](https://github.com/raysan5) |
-| 87 | [models_mesh_generation](models/models_mesh_generation.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
-| 88 | [models_mesh_picking](models/models_mesh_picking.c) |
| ⭐️⭐️⭐️☆ | 1.7 | **4.0** | [Joel Davis](https://github.com/joeld42) |
-| 89 | [models_loading](models/models_loading.c) |
| ⭐️☆☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
-| 90 | [models_loading_gltf](models/models_loading_gltf.c) |
| ⭐️☆☆☆ | 3.7 | **4.2** | [Ray](https://github.com/raysan5) |
-| 91 | [models_loading_vox](models/models_loading_vox.c) |
| ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) |
-| 92 | [models_loading_m3d](models/models_loading_m3d.c) |
| ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) |
-| 93 | [models_orthographic_projection](models/models_orthographic_projection.c) |
| ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) |
-| 94 | [models_point_rendering](models/models_point_rendering.c) |
| ⭐️⭐️☆☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) |
-| 95 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
-| 96 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) |
-| 97 | [models_waving_cubes](models/models_waving_cubes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) |
-| 98 | [models_heightmap](models/models_heightmap.c) |
| ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
-| 99 | [models_skybox](models/models_skybox.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
+| 84 | [models_animation](models/models_animation.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [culacant](https://github.com/culacant) |
+| 85 | [models_billboard](models/models_billboard.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
+| 86 | [models_box_collisions](models/models_box_collisions.c) |
| ⭐️☆☆☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
+| 87 | [models_cubicmap](models/models_cubicmap.c) |
| ⭐️⭐️☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
+| 88 | [models_first_person_maze](models/models_first_person_maze.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 89 | [models_geometric_shapes](models/models_geometric_shapes.c) |
| ⭐️☆☆☆ | 1.0 | 3.5 | [Ray](https://github.com/raysan5) |
+| 90 | [models_mesh_generation](models/models_mesh_generation.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
+| 91 | [models_mesh_picking](models/models_mesh_picking.c) |
| ⭐️⭐️⭐️☆ | 1.7 | **4.0** | [Joel Davis](https://github.com/joeld42) |
+| 92 | [models_loading](models/models_loading.c) |
| ⭐️☆☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
+| 93 | [models_loading_gltf](models/models_loading_gltf.c) |
| ⭐️☆☆☆ | 3.7 | **4.2** | [Ray](https://github.com/raysan5) |
+| 94 | [models_loading_vox](models/models_loading_vox.c) |
| ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) |
+| 95 | [models_loading_m3d](models/models_loading_m3d.c) |
| ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) |
+| 96 | [models_orthographic_projection](models/models_orthographic_projection.c) |
| ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) |
+| 97 | [models_point_rendering](models/models_point_rendering.c) |
| ⭐️⭐️☆☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) |
+| 98 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
+| 99 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) |
+| 100 | [models_waving_cubes](models/models_waving_cubes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) |
+| 101 | [models_heightmap](models/models_heightmap.c) |
| ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
+| 102 | [models_skybox](models/models_skybox.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
### category: shaders
@@ -160,25 +161,25 @@ Examples using raylib shaders functionality, including shaders loading, paramete
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 100 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) |
| ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) |
-| 101 | [shaders_model_shader](shaders/shaders_model_shader.c) |
| ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) |
-| 102 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) |
| ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
-| 103 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 104 | [shaders_postprocessing](shaders/shaders_postprocessing.c) |
| ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 105 | [shaders_palette_switch](shaders/shaders_palette_switch.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) |
-| 106 | [shaders_raymarching](shaders/shaders_raymarching.c) |
| ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) |
-| 107 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) |
| ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) |
-| 108 | [shaders_texture_outline](shaders/shaders_texture_outline.c) |
| ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) |
-| 109 | [shaders_texture_waves](shaders/shaders_texture_waves.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) |
-| 110 | [shaders_julia_set](shaders/shaders_julia_set.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) |
-| 111 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) |
-| 112 | [shaders_fog](shaders/shaders_fog.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 113 | [shaders_simple_mask](shaders/shaders_simple_mask.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 114 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) |
-| 115 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) |
| ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) |
-| 116 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 117 | [shaders_spotlight](shaders/shaders_spotlight.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 118 | [shaders_deferred_render](shaders/shaders_deferred_render.c) |
| ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) |
+| 103 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) |
| ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) |
+| 104 | [shaders_model_shader](shaders/shaders_model_shader.c) |
| ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) |
+| 105 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) |
| ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
+| 106 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 107 | [shaders_postprocessing](shaders/shaders_postprocessing.c) |
| ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 108 | [shaders_palette_switch](shaders/shaders_palette_switch.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) |
+| 109 | [shaders_raymarching](shaders/shaders_raymarching.c) |
| ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) |
+| 110 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) |
| ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) |
+| 111 | [shaders_texture_outline](shaders/shaders_texture_outline.c) |
| ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) |
+| 112 | [shaders_texture_waves](shaders/shaders_texture_waves.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) |
+| 113 | [shaders_julia_set](shaders/shaders_julia_set.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) |
+| 114 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) |
+| 115 | [shaders_fog](shaders/shaders_fog.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 116 | [shaders_simple_mask](shaders/shaders_simple_mask.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 117 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) |
+| 118 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) |
| ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) |
+| 119 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 120 | [shaders_spotlight](shaders/shaders_spotlight.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 121 | [shaders_deferred_render](shaders/shaders_deferred_render.c) |
| ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) |
### category: audio
@@ -186,10 +187,10 @@ Examples using raylib audio functionality, including sound/music loading and pla
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 119 | [audio_module_playing](audio/audio_module_playing.c) |
| ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 120 | [audio_music_stream](audio/audio_music_stream.c) |
| ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
-| 121 | [audio_raw_stream](audio/audio_raw_stream.c) |
| ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) |
-| 122 | [audio_sound_loading](audio/audio_sound_loading.c) |
| ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) |
+| 122 | [audio_module_playing](audio/audio_module_playing.c) |
| ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 123 | [audio_music_stream](audio/audio_music_stream.c) |
| ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
+| 124 | [audio_raw_stream](audio/audio_raw_stream.c) |
| ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) |
+| 125 | [audio_sound_loading](audio/audio_sound_loading.c) |
| ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) |
### category: others
@@ -197,11 +198,11 @@ Examples showing raylib misc functionality that does not fit in other categories
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 123 | [rlgl_standalone](others/rlgl_standalone.c) |
| ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) |
-| 124 | [rlgl_compute_shader](others/rlgl_compute_shader.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) |
-| 125 | [easings_testbed](others/easings_testbed.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
-| 126 | [raylib_opengl_interop](others/raylib_opengl_interop.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) |
-| 127 | [embedded_files_loading](others/embedded_files_loading.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
+| 126 | [rlgl_standalone](others/rlgl_standalone.c) |
| ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) |
+| 127 | [rlgl_compute_shader](others/rlgl_compute_shader.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) |
+| 128 | [easings_testbed](others/easings_testbed.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
+| 129 | [raylib_opengl_interop](others/raylib_opengl_interop.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) |
+| 130 | [embedded_files_loading](others/embedded_files_loading.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
As always contributions are welcome, feel free to send new examples! Here is an [examples template](examples_template.c) to start with!
diff --git a/examples/core/core_input_virtual_controls.c b/examples/core/core_input_virtual_controls.c
new file mode 100644
index 000000000..ae7f770aa
--- /dev/null
+++ b/examples/core/core_input_virtual_controls.c
@@ -0,0 +1,123 @@
+/*******************************************************************************************
+*
+* raylib [core] example - input virtual controls
+*
+* Example originally created with raylib 5.0, last time updated with raylib 5.0
+*
+* Example create by GreenSnakeLinux (@GreenSnakeLinux),
+* lighter by oblerion (@oblerion) 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) 2024 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [core] example - input virtual controls");
+
+ const int dpadX = 90;
+ const int dpadY = 300;
+ const int dpadRad = 25;//radius of each pad
+ Color dpadColor = BLUE;
+ int dpadKeydown = -1;//-1 if not down, else 0,1,2,3
+
+
+ const float dpadCollider[4][2]= // collider array with x,y position
+ {
+ {dpadX,dpadY-dpadRad*1.5},//up
+ {dpadX-dpadRad*1.5,dpadY},//left
+ {dpadX+dpadRad*1.5,dpadY},//right
+ {dpadX,dpadY+dpadRad*1.5}//down
+ };
+ const char dpadLabel[4]="XYBA";//label of Dpad
+
+ float playerX=100;
+ float playerY=100;
+
+ SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //--------------------------------------------------------------------------
+ dpadKeydown = -1; //reset
+ float inputX=0;
+ float inputY=0;
+ if(GetTouchPointCount()>0)
+ {//use touch pos
+ inputX = GetTouchX();
+ inputY = GetTouchY();
+ }
+ else
+ {//use mouse pos
+ inputX = GetMouseX();
+ inputY = GetMouseY();
+ }
+ for(int i=0;i<4;i++)
+ {
+ //test distance each collider and input < radius
+ if( fabsf(dpadCollider[i][1]-inputY) + fabsf(dpadCollider[i][0]-inputX) < dpadRad)
+ {
+ dpadKeydown = i;
+ break;
+ }
+ }
+ // move player
+ switch(dpadKeydown){
+ case 0: playerY -= 50*GetFrameTime();
+ break;
+ case 1: playerX -= 50*GetFrameTime();
+ break;
+ case 2: playerX += 50*GetFrameTime();
+ break;
+ case 3: playerY += 50*GetFrameTime();
+ default:;
+ };
+ //--------------------------------------------------------------------------
+
+ // Draw
+ //--------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(RAYWHITE);
+ for(int i=0;i<4;i++)
+ {
+ //draw all pad
+ DrawCircle(dpadCollider[i][0],dpadCollider[i][1],dpadRad,dpadColor);
+ if(i!=dpadKeydown)
+ {
+ //draw label
+ DrawText(TextSubtext(dpadLabel,i,1),
+ dpadCollider[i][0]-5,
+ dpadCollider[i][1]-5,16,BLACK);
+ }
+
+ }
+ DrawText("Player",playerX,playerY,16,BLACK);
+ EndDrawing();
+ //--------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
diff --git a/examples/core/core_input_virtual_controls.png b/examples/core/core_input_virtual_controls.png
new file mode 100644
index 000000000..a9776e68a
Binary files /dev/null and b/examples/core/core_input_virtual_controls.png differ
diff --git a/examples/textures/resources/test.svg b/examples/textures/resources/test.svg
deleted file mode 100644
index 3d9bbb113..000000000
--- a/examples/textures/resources/test.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/examples/textures/textures_image_drawing.c b/examples/textures/textures_image_drawing.c
index f49bc9e77..d0eee999d 100644
--- a/examples/textures/textures_image_drawing.c
+++ b/examples/textures/textures_image_drawing.c
@@ -47,7 +47,7 @@ int main(void)
UnloadImage(cat); // Unload image from RAM
- // Load custom font for frawing on image
+ // Load custom font for drawing on image
Font font = LoadFont("resources/custom_jupiter_crash.png");
// Draw over image using custom font
@@ -93,4 +93,4 @@ int main(void)
//--------------------------------------------------------------------------------------
return 0;
-}
\ No newline at end of file
+}
diff --git a/examples/textures/textures_svg_loading.c b/examples/textures/textures_svg_loading.c
deleted file mode 100644
index 434ec7602..000000000
--- a/examples/textures/textures_svg_loading.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*******************************************************************************************
-*
-* raylib [textures] example - SVG loading and texture creation
-*
-* NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU memory (VRAM)
-*
-* Example originally created with raylib 4.2, last time updated with raylib 4.2
-*
-* 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) 2022 Dennis Meinen (@bixxy#4258 on Discord)
-*
-********************************************************************************************/
-
-#include "raylib.h"
-
-//------------------------------------------------------------------------------------
-// Program main entry point
-//------------------------------------------------------------------------------------
-int main(void)
-{
- // Initialization
- //--------------------------------------------------------------------------------------
- const int screenWidth = 800;
- const int screenHeight = 450;
-
- InitWindow(screenWidth, screenHeight, "raylib [textures] example - svg loading");
-
- // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
-
- Image image = LoadImageSvg("resources/test.svg", 400, 350); // Loaded in CPU memory (RAM)
- Texture2D texture = LoadTextureFromImage(image); // Image converted to texture, GPU memory (VRAM)
- UnloadImage(image); // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM
-
- 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
- //----------------------------------------------------------------------------------
- // TODO: Update your variables here
- //----------------------------------------------------------------------------------
-
- // Draw
- //----------------------------------------------------------------------------------
- BeginDrawing();
-
- ClearBackground(RAYWHITE);
-
- DrawTexture(texture, screenWidth/2 - texture.width/2, screenHeight/2 - texture.height/2, WHITE);
-
- //Red border to illustrate how the SVG is centered within the specified dimensions
- DrawRectangleLines((screenWidth / 2 - texture.width / 2) - 1, (screenHeight / 2 - texture.height / 2) - 1, texture.width + 2, texture.height + 2, RED);
-
- DrawText("this IS a texture loaded from an SVG file!", 300, 410, 10, GRAY);
-
- EndDrawing();
- //----------------------------------------------------------------------------------
- }
-
- // De-Initialization
- //--------------------------------------------------------------------------------------
- UnloadTexture(texture); // Texture unloading
-
- CloseWindow(); // Close window and OpenGL context
- //--------------------------------------------------------------------------------------
-
- return 0;
-}
\ No newline at end of file
diff --git a/examples/textures/textures_svg_loading.png b/examples/textures/textures_svg_loading.png
deleted file mode 100644
index fa98605fa..000000000
Binary files a/examples/textures/textures_svg_loading.png and /dev/null differ
diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json
index 58fb9d6a8..2c8fe31e9 100644
--- a/parser/output/raylib_api.json
+++ b/parser/output/raylib_api.json
@@ -6815,25 +6815,6 @@
}
]
},
- {
- "name": "LoadImageSvg",
- "description": "Load image from SVG file data or string with specified size",
- "returnType": "Image",
- "params": [
- {
- "type": "const char *",
- "name": "fileNameOrString"
- },
- {
- "type": "int",
- "name": "width"
- },
- {
- "type": "int",
- "name": "height"
- }
- ]
- },
{
"name": "LoadImageAnim",
"description": "Load image sequence from file (frames appended to image.data)",
diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua
index bea3813cf..6c287b7a4 100644
--- a/parser/output/raylib_api.lua
+++ b/parser/output/raylib_api.lua
@@ -5339,16 +5339,6 @@ return {
{type = "int", name = "headerSize"}
}
},
- {
- name = "LoadImageSvg",
- description = "Load image from SVG file data or string with specified size",
- returnType = "Image",
- params = {
- {type = "const char *", name = "fileNameOrString"},
- {type = "int", name = "width"},
- {type = "int", name = "height"}
- }
- },
{
name = "LoadImageAnim",
description = "Load image sequence from file (frames appended to image.data)",
diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt
index 9a953b768..9764769a7 100644
--- a/parser/output/raylib_api.txt
+++ b/parser/output/raylib_api.txt
@@ -989,7 +989,7 @@ Callback 006: AudioCallback() (2 input parameters)
Param[1]: bufferData (type: void *)
Param[2]: frames (type: unsigned int)
-Functions found: 578
+Functions found: 577
Function 001: InitWindow() (3 input parameters)
Name: InitWindow
@@ -2631,20 +2631,13 @@ Function 272: LoadImageRaw() (5 input parameters)
Param[3]: height (type: int)
Param[4]: format (type: int)
Param[5]: headerSize (type: int)
-Function 273: LoadImageSvg() (3 input parameters)
- Name: LoadImageSvg
- Return type: Image
- Description: Load image from SVG file data or string with specified size
- Param[1]: fileNameOrString (type: const char *)
- Param[2]: width (type: int)
- Param[3]: height (type: int)
-Function 274: LoadImageAnim() (2 input parameters)
+Function 273: LoadImageAnim() (2 input parameters)
Name: LoadImageAnim
Return type: Image
Description: Load image sequence from file (frames appended to image.data)
Param[1]: fileName (type: const char *)
Param[2]: frames (type: int *)
-Function 275: LoadImageAnimFromMemory() (4 input parameters)
+Function 274: LoadImageAnimFromMemory() (4 input parameters)
Name: LoadImageAnimFromMemory
Return type: Image
Description: Load image sequence from memory buffer
@@ -2652,60 +2645,60 @@ Function 275: LoadImageAnimFromMemory() (4 input parameters)
Param[2]: fileData (type: const unsigned char *)
Param[3]: dataSize (type: int)
Param[4]: frames (type: int *)
-Function 276: LoadImageFromMemory() (3 input parameters)
+Function 275: LoadImageFromMemory() (3 input parameters)
Name: LoadImageFromMemory
Return type: Image
Description: Load image from memory buffer, fileType refers to extension: i.e. '.png'
Param[1]: fileType (type: const char *)
Param[2]: fileData (type: const unsigned char *)
Param[3]: dataSize (type: int)
-Function 277: LoadImageFromTexture() (1 input parameters)
+Function 276: LoadImageFromTexture() (1 input parameters)
Name: LoadImageFromTexture
Return type: Image
Description: Load image from GPU texture data
Param[1]: texture (type: Texture2D)
-Function 278: LoadImageFromScreen() (0 input parameters)
+Function 277: LoadImageFromScreen() (0 input parameters)
Name: LoadImageFromScreen
Return type: Image
Description: Load image from screen buffer and (screenshot)
No input parameters
-Function 279: IsImageReady() (1 input parameters)
+Function 278: IsImageReady() (1 input parameters)
Name: IsImageReady
Return type: bool
Description: Check if an image is ready
Param[1]: image (type: Image)
-Function 280: UnloadImage() (1 input parameters)
+Function 279: UnloadImage() (1 input parameters)
Name: UnloadImage
Return type: void
Description: Unload image from CPU memory (RAM)
Param[1]: image (type: Image)
-Function 281: ExportImage() (2 input parameters)
+Function 280: ExportImage() (2 input parameters)
Name: ExportImage
Return type: bool
Description: Export image data to file, returns true on success
Param[1]: image (type: Image)
Param[2]: fileName (type: const char *)
-Function 282: ExportImageToMemory() (3 input parameters)
+Function 281: ExportImageToMemory() (3 input parameters)
Name: ExportImageToMemory
Return type: unsigned char *
Description: Export image to memory buffer
Param[1]: image (type: Image)
Param[2]: fileType (type: const char *)
Param[3]: fileSize (type: int *)
-Function 283: ExportImageAsCode() (2 input parameters)
+Function 282: ExportImageAsCode() (2 input parameters)
Name: ExportImageAsCode
Return type: bool
Description: Export image as code file defining an array of bytes, returns true on success
Param[1]: image (type: Image)
Param[2]: fileName (type: const char *)
-Function 284: GenImageColor() (3 input parameters)
+Function 283: GenImageColor() (3 input parameters)
Name: GenImageColor
Return type: Image
Description: Generate image: plain color
Param[1]: width (type: int)
Param[2]: height (type: int)
Param[3]: color (type: Color)
-Function 285: GenImageGradientLinear() (5 input parameters)
+Function 284: GenImageGradientLinear() (5 input parameters)
Name: GenImageGradientLinear
Return type: Image
Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient
@@ -2714,7 +2707,7 @@ Function 285: GenImageGradientLinear() (5 input parameters)
Param[3]: direction (type: int)
Param[4]: start (type: Color)
Param[5]: end (type: Color)
-Function 286: GenImageGradientRadial() (5 input parameters)
+Function 285: GenImageGradientRadial() (5 input parameters)
Name: GenImageGradientRadial
Return type: Image
Description: Generate image: radial gradient
@@ -2723,7 +2716,7 @@ Function 286: GenImageGradientRadial() (5 input parameters)
Param[3]: density (type: float)
Param[4]: inner (type: Color)
Param[5]: outer (type: Color)
-Function 287: GenImageGradientSquare() (5 input parameters)
+Function 286: GenImageGradientSquare() (5 input parameters)
Name: GenImageGradientSquare
Return type: Image
Description: Generate image: square gradient
@@ -2732,7 +2725,7 @@ Function 287: GenImageGradientSquare() (5 input parameters)
Param[3]: density (type: float)
Param[4]: inner (type: Color)
Param[5]: outer (type: Color)
-Function 288: GenImageChecked() (6 input parameters)
+Function 287: GenImageChecked() (6 input parameters)
Name: GenImageChecked
Return type: Image
Description: Generate image: checked
@@ -2742,14 +2735,14 @@ Function 288: GenImageChecked() (6 input parameters)
Param[4]: checksY (type: int)
Param[5]: col1 (type: Color)
Param[6]: col2 (type: Color)
-Function 289: GenImageWhiteNoise() (3 input parameters)
+Function 288: GenImageWhiteNoise() (3 input parameters)
Name: GenImageWhiteNoise
Return type: Image
Description: Generate image: white noise
Param[1]: width (type: int)
Param[2]: height (type: int)
Param[3]: factor (type: float)
-Function 290: GenImagePerlinNoise() (5 input parameters)
+Function 289: GenImagePerlinNoise() (5 input parameters)
Name: GenImagePerlinNoise
Return type: Image
Description: Generate image: perlin noise
@@ -2758,45 +2751,45 @@ Function 290: GenImagePerlinNoise() (5 input parameters)
Param[3]: offsetX (type: int)
Param[4]: offsetY (type: int)
Param[5]: scale (type: float)
-Function 291: GenImageCellular() (3 input parameters)
+Function 290: GenImageCellular() (3 input parameters)
Name: GenImageCellular
Return type: Image
Description: Generate image: cellular algorithm, bigger tileSize means bigger cells
Param[1]: width (type: int)
Param[2]: height (type: int)
Param[3]: tileSize (type: int)
-Function 292: GenImageText() (3 input parameters)
+Function 291: GenImageText() (3 input parameters)
Name: GenImageText
Return type: Image
Description: Generate image: grayscale image from text data
Param[1]: width (type: int)
Param[2]: height (type: int)
Param[3]: text (type: const char *)
-Function 293: ImageCopy() (1 input parameters)
+Function 292: ImageCopy() (1 input parameters)
Name: ImageCopy
Return type: Image
Description: Create an image duplicate (useful for transformations)
Param[1]: image (type: Image)
-Function 294: ImageFromImage() (2 input parameters)
+Function 293: ImageFromImage() (2 input parameters)
Name: ImageFromImage
Return type: Image
Description: Create an image from another image piece
Param[1]: image (type: Image)
Param[2]: rec (type: Rectangle)
-Function 295: ImageFromChannel() (2 input parameters)
+Function 294: ImageFromChannel() (2 input parameters)
Name: ImageFromChannel
Return type: Image
Description: Create an image from a selected channel of another image (GRAYSCALE)
Param[1]: image (type: Image)
Param[2]: selectedChannel (type: int)
-Function 296: ImageText() (3 input parameters)
+Function 295: ImageText() (3 input parameters)
Name: ImageText
Return type: Image
Description: Create an image from text (default font)
Param[1]: text (type: const char *)
Param[2]: fontSize (type: int)
Param[3]: color (type: Color)
-Function 297: ImageTextEx() (5 input parameters)
+Function 296: ImageTextEx() (5 input parameters)
Name: ImageTextEx
Return type: Image
Description: Create an image from text (custom sprite font)
@@ -2805,76 +2798,76 @@ Function 297: ImageTextEx() (5 input parameters)
Param[3]: fontSize (type: float)
Param[4]: spacing (type: float)
Param[5]: tint (type: Color)
-Function 298: ImageFormat() (2 input parameters)
+Function 297: ImageFormat() (2 input parameters)
Name: ImageFormat
Return type: void
Description: Convert image data to desired format
Param[1]: image (type: Image *)
Param[2]: newFormat (type: int)
-Function 299: ImageToPOT() (2 input parameters)
+Function 298: ImageToPOT() (2 input parameters)
Name: ImageToPOT
Return type: void
Description: Convert image to POT (power-of-two)
Param[1]: image (type: Image *)
Param[2]: fill (type: Color)
-Function 300: ImageCrop() (2 input parameters)
+Function 299: ImageCrop() (2 input parameters)
Name: ImageCrop
Return type: void
Description: Crop an image to a defined rectangle
Param[1]: image (type: Image *)
Param[2]: crop (type: Rectangle)
-Function 301: ImageAlphaCrop() (2 input parameters)
+Function 300: ImageAlphaCrop() (2 input parameters)
Name: ImageAlphaCrop
Return type: void
Description: Crop image depending on alpha value
Param[1]: image (type: Image *)
Param[2]: threshold (type: float)
-Function 302: ImageAlphaClear() (3 input parameters)
+Function 301: ImageAlphaClear() (3 input parameters)
Name: ImageAlphaClear
Return type: void
Description: Clear alpha channel to desired color
Param[1]: image (type: Image *)
Param[2]: color (type: Color)
Param[3]: threshold (type: float)
-Function 303: ImageAlphaMask() (2 input parameters)
+Function 302: ImageAlphaMask() (2 input parameters)
Name: ImageAlphaMask
Return type: void
Description: Apply alpha mask to image
Param[1]: image (type: Image *)
Param[2]: alphaMask (type: Image)
-Function 304: ImageAlphaPremultiply() (1 input parameters)
+Function 303: ImageAlphaPremultiply() (1 input parameters)
Name: ImageAlphaPremultiply
Return type: void
Description: Premultiply alpha channel
Param[1]: image (type: Image *)
-Function 305: ImageBlurGaussian() (2 input parameters)
+Function 304: ImageBlurGaussian() (2 input parameters)
Name: ImageBlurGaussian
Return type: void
Description: Apply Gaussian blur using a box blur approximation
Param[1]: image (type: Image *)
Param[2]: blurSize (type: int)
-Function 306: ImageKernelConvolution() (3 input parameters)
+Function 305: ImageKernelConvolution() (3 input parameters)
Name: ImageKernelConvolution
Return type: void
Description: Apply custom square convolution kernel to image
Param[1]: image (type: Image *)
Param[2]: kernel (type: const float *)
Param[3]: kernelSize (type: int)
-Function 307: ImageResize() (3 input parameters)
+Function 306: ImageResize() (3 input parameters)
Name: ImageResize
Return type: void
Description: Resize image (Bicubic scaling algorithm)
Param[1]: image (type: Image *)
Param[2]: newWidth (type: int)
Param[3]: newHeight (type: int)
-Function 308: ImageResizeNN() (3 input parameters)
+Function 307: ImageResizeNN() (3 input parameters)
Name: ImageResizeNN
Return type: void
Description: Resize image (Nearest-Neighbor scaling algorithm)
Param[1]: image (type: Image *)
Param[2]: newWidth (type: int)
Param[3]: newHeight (type: int)
-Function 309: ImageResizeCanvas() (6 input parameters)
+Function 308: ImageResizeCanvas() (6 input parameters)
Name: ImageResizeCanvas
Return type: void
Description: Resize canvas and fill with color
@@ -2884,12 +2877,12 @@ Function 309: ImageResizeCanvas() (6 input parameters)
Param[4]: offsetX (type: int)
Param[5]: offsetY (type: int)
Param[6]: fill (type: Color)
-Function 310: ImageMipmaps() (1 input parameters)
+Function 309: ImageMipmaps() (1 input parameters)
Name: ImageMipmaps
Return type: void
Description: Compute all mipmap levels for a provided image
Param[1]: image (type: Image *)
-Function 311: ImageDither() (5 input parameters)
+Function 310: ImageDither() (5 input parameters)
Name: ImageDither
Return type: void
Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
@@ -2898,109 +2891,109 @@ Function 311: ImageDither() (5 input parameters)
Param[3]: gBpp (type: int)
Param[4]: bBpp (type: int)
Param[5]: aBpp (type: int)
-Function 312: ImageFlipVertical() (1 input parameters)
+Function 311: ImageFlipVertical() (1 input parameters)
Name: ImageFlipVertical
Return type: void
Description: Flip image vertically
Param[1]: image (type: Image *)
-Function 313: ImageFlipHorizontal() (1 input parameters)
+Function 312: ImageFlipHorizontal() (1 input parameters)
Name: ImageFlipHorizontal
Return type: void
Description: Flip image horizontally
Param[1]: image (type: Image *)
-Function 314: ImageRotate() (2 input parameters)
+Function 313: ImageRotate() (2 input parameters)
Name: ImageRotate
Return type: void
Description: Rotate image by input angle in degrees (-359 to 359)
Param[1]: image (type: Image *)
Param[2]: degrees (type: int)
-Function 315: ImageRotateCW() (1 input parameters)
+Function 314: ImageRotateCW() (1 input parameters)
Name: ImageRotateCW
Return type: void
Description: Rotate image clockwise 90deg
Param[1]: image (type: Image *)
-Function 316: ImageRotateCCW() (1 input parameters)
+Function 315: ImageRotateCCW() (1 input parameters)
Name: ImageRotateCCW
Return type: void
Description: Rotate image counter-clockwise 90deg
Param[1]: image (type: Image *)
-Function 317: ImageColorTint() (2 input parameters)
+Function 316: ImageColorTint() (2 input parameters)
Name: ImageColorTint
Return type: void
Description: Modify image color: tint
Param[1]: image (type: Image *)
Param[2]: color (type: Color)
-Function 318: ImageColorInvert() (1 input parameters)
+Function 317: ImageColorInvert() (1 input parameters)
Name: ImageColorInvert
Return type: void
Description: Modify image color: invert
Param[1]: image (type: Image *)
-Function 319: ImageColorGrayscale() (1 input parameters)
+Function 318: ImageColorGrayscale() (1 input parameters)
Name: ImageColorGrayscale
Return type: void
Description: Modify image color: grayscale
Param[1]: image (type: Image *)
-Function 320: ImageColorContrast() (2 input parameters)
+Function 319: ImageColorContrast() (2 input parameters)
Name: ImageColorContrast
Return type: void
Description: Modify image color: contrast (-100 to 100)
Param[1]: image (type: Image *)
Param[2]: contrast (type: float)
-Function 321: ImageColorBrightness() (2 input parameters)
+Function 320: ImageColorBrightness() (2 input parameters)
Name: ImageColorBrightness
Return type: void
Description: Modify image color: brightness (-255 to 255)
Param[1]: image (type: Image *)
Param[2]: brightness (type: int)
-Function 322: ImageColorReplace() (3 input parameters)
+Function 321: ImageColorReplace() (3 input parameters)
Name: ImageColorReplace
Return type: void
Description: Modify image color: replace color
Param[1]: image (type: Image *)
Param[2]: color (type: Color)
Param[3]: replace (type: Color)
-Function 323: LoadImageColors() (1 input parameters)
+Function 322: LoadImageColors() (1 input parameters)
Name: LoadImageColors
Return type: Color *
Description: Load color data from image as a Color array (RGBA - 32bit)
Param[1]: image (type: Image)
-Function 324: LoadImagePalette() (3 input parameters)
+Function 323: LoadImagePalette() (3 input parameters)
Name: LoadImagePalette
Return type: Color *
Description: Load colors palette from image as a Color array (RGBA - 32bit)
Param[1]: image (type: Image)
Param[2]: maxPaletteSize (type: int)
Param[3]: colorCount (type: int *)
-Function 325: UnloadImageColors() (1 input parameters)
+Function 324: UnloadImageColors() (1 input parameters)
Name: UnloadImageColors
Return type: void
Description: Unload color data loaded with LoadImageColors()
Param[1]: colors (type: Color *)
-Function 326: UnloadImagePalette() (1 input parameters)
+Function 325: UnloadImagePalette() (1 input parameters)
Name: UnloadImagePalette
Return type: void
Description: Unload colors palette loaded with LoadImagePalette()
Param[1]: colors (type: Color *)
-Function 327: GetImageAlphaBorder() (2 input parameters)
+Function 326: GetImageAlphaBorder() (2 input parameters)
Name: GetImageAlphaBorder
Return type: Rectangle
Description: Get image alpha border rectangle
Param[1]: image (type: Image)
Param[2]: threshold (type: float)
-Function 328: GetImageColor() (3 input parameters)
+Function 327: GetImageColor() (3 input parameters)
Name: GetImageColor
Return type: Color
Description: Get image pixel color at (x, y) position
Param[1]: image (type: Image)
Param[2]: x (type: int)
Param[3]: y (type: int)
-Function 329: ImageClearBackground() (2 input parameters)
+Function 328: ImageClearBackground() (2 input parameters)
Name: ImageClearBackground
Return type: void
Description: Clear image background with given color
Param[1]: dst (type: Image *)
Param[2]: color (type: Color)
-Function 330: ImageDrawPixel() (4 input parameters)
+Function 329: ImageDrawPixel() (4 input parameters)
Name: ImageDrawPixel
Return type: void
Description: Draw pixel within an image
@@ -3008,14 +3001,14 @@ Function 330: ImageDrawPixel() (4 input parameters)
Param[2]: posX (type: int)
Param[3]: posY (type: int)
Param[4]: color (type: Color)
-Function 331: ImageDrawPixelV() (3 input parameters)
+Function 330: ImageDrawPixelV() (3 input parameters)
Name: ImageDrawPixelV
Return type: void
Description: Draw pixel within an image (Vector version)
Param[1]: dst (type: Image *)
Param[2]: position (type: Vector2)
Param[3]: color (type: Color)
-Function 332: ImageDrawLine() (6 input parameters)
+Function 331: ImageDrawLine() (6 input parameters)
Name: ImageDrawLine
Return type: void
Description: Draw line within an image
@@ -3025,7 +3018,7 @@ Function 332: ImageDrawLine() (6 input parameters)
Param[4]: endPosX (type: int)
Param[5]: endPosY (type: int)
Param[6]: color (type: Color)
-Function 333: ImageDrawLineV() (4 input parameters)
+Function 332: ImageDrawLineV() (4 input parameters)
Name: ImageDrawLineV
Return type: void
Description: Draw line within an image (Vector version)
@@ -3033,7 +3026,7 @@ Function 333: ImageDrawLineV() (4 input parameters)
Param[2]: start (type: Vector2)
Param[3]: end (type: Vector2)
Param[4]: color (type: Color)
-Function 334: ImageDrawLineEx() (5 input parameters)
+Function 333: ImageDrawLineEx() (5 input parameters)
Name: ImageDrawLineEx
Return type: void
Description: Draw a line defining thickness within an image
@@ -3042,7 +3035,7 @@ Function 334: ImageDrawLineEx() (5 input parameters)
Param[3]: end (type: Vector2)
Param[4]: thick (type: int)
Param[5]: color (type: Color)
-Function 335: ImageDrawCircle() (5 input parameters)
+Function 334: ImageDrawCircle() (5 input parameters)
Name: ImageDrawCircle
Return type: void
Description: Draw a filled circle within an image
@@ -3051,7 +3044,7 @@ Function 335: ImageDrawCircle() (5 input parameters)
Param[3]: centerY (type: int)
Param[4]: radius (type: int)
Param[5]: color (type: Color)
-Function 336: ImageDrawCircleV() (4 input parameters)
+Function 335: ImageDrawCircleV() (4 input parameters)
Name: ImageDrawCircleV
Return type: void
Description: Draw a filled circle within an image (Vector version)
@@ -3059,7 +3052,7 @@ Function 336: ImageDrawCircleV() (4 input parameters)
Param[2]: center (type: Vector2)
Param[3]: radius (type: int)
Param[4]: color (type: Color)
-Function 337: ImageDrawCircleLines() (5 input parameters)
+Function 336: ImageDrawCircleLines() (5 input parameters)
Name: ImageDrawCircleLines
Return type: void
Description: Draw circle outline within an image
@@ -3068,7 +3061,7 @@ Function 337: ImageDrawCircleLines() (5 input parameters)
Param[3]: centerY (type: int)
Param[4]: radius (type: int)
Param[5]: color (type: Color)
-Function 338: ImageDrawCircleLinesV() (4 input parameters)
+Function 337: ImageDrawCircleLinesV() (4 input parameters)
Name: ImageDrawCircleLinesV
Return type: void
Description: Draw circle outline within an image (Vector version)
@@ -3076,7 +3069,7 @@ Function 338: ImageDrawCircleLinesV() (4 input parameters)
Param[2]: center (type: Vector2)
Param[3]: radius (type: int)
Param[4]: color (type: Color)
-Function 339: ImageDrawRectangle() (6 input parameters)
+Function 338: ImageDrawRectangle() (6 input parameters)
Name: ImageDrawRectangle
Return type: void
Description: Draw rectangle within an image
@@ -3086,7 +3079,7 @@ Function 339: ImageDrawRectangle() (6 input parameters)
Param[4]: width (type: int)
Param[5]: height (type: int)
Param[6]: color (type: Color)
-Function 340: ImageDrawRectangleV() (4 input parameters)
+Function 339: ImageDrawRectangleV() (4 input parameters)
Name: ImageDrawRectangleV
Return type: void
Description: Draw rectangle within an image (Vector version)
@@ -3094,14 +3087,14 @@ Function 340: ImageDrawRectangleV() (4 input parameters)
Param[2]: position (type: Vector2)
Param[3]: size (type: Vector2)
Param[4]: color (type: Color)
-Function 341: ImageDrawRectangleRec() (3 input parameters)
+Function 340: ImageDrawRectangleRec() (3 input parameters)
Name: ImageDrawRectangleRec
Return type: void
Description: Draw rectangle within an image
Param[1]: dst (type: Image *)
Param[2]: rec (type: Rectangle)
Param[3]: color (type: Color)
-Function 342: ImageDrawRectangleLines() (4 input parameters)
+Function 341: ImageDrawRectangleLines() (4 input parameters)
Name: ImageDrawRectangleLines
Return type: void
Description: Draw rectangle lines within an image
@@ -3109,7 +3102,7 @@ Function 342: ImageDrawRectangleLines() (4 input parameters)
Param[2]: rec (type: Rectangle)
Param[3]: thick (type: int)
Param[4]: color (type: Color)
-Function 343: ImageDrawTriangle() (5 input parameters)
+Function 342: ImageDrawTriangle() (5 input parameters)
Name: ImageDrawTriangle
Return type: void
Description: Draw triangle within an image
@@ -3118,7 +3111,7 @@ Function 343: ImageDrawTriangle() (5 input parameters)
Param[3]: v2 (type: Vector2)
Param[4]: v3 (type: Vector2)
Param[5]: color (type: Color)
-Function 344: ImageDrawTriangleEx() (7 input parameters)
+Function 343: ImageDrawTriangleEx() (7 input parameters)
Name: ImageDrawTriangleEx
Return type: void
Description: Draw triangle with interpolated colors within an image
@@ -3129,7 +3122,7 @@ Function 344: ImageDrawTriangleEx() (7 input parameters)
Param[5]: c1 (type: Color)
Param[6]: c2 (type: Color)
Param[7]: c3 (type: Color)
-Function 345: ImageDrawTriangleLines() (5 input parameters)
+Function 344: ImageDrawTriangleLines() (5 input parameters)
Name: ImageDrawTriangleLines
Return type: void
Description: Draw triangle outline within an image
@@ -3138,7 +3131,7 @@ Function 345: ImageDrawTriangleLines() (5 input parameters)
Param[3]: v2 (type: Vector2)
Param[4]: v3 (type: Vector2)
Param[5]: color (type: Color)
-Function 346: ImageDrawTriangleFan() (4 input parameters)
+Function 345: ImageDrawTriangleFan() (4 input parameters)
Name: ImageDrawTriangleFan
Return type: void
Description: Draw a triangle fan defined by points within an image (first vertex is the center)
@@ -3146,7 +3139,7 @@ Function 346: ImageDrawTriangleFan() (4 input parameters)
Param[2]: points (type: Vector2 *)
Param[3]: pointCount (type: int)
Param[4]: color (type: Color)
-Function 347: ImageDrawTriangleStrip() (4 input parameters)
+Function 346: ImageDrawTriangleStrip() (4 input parameters)
Name: ImageDrawTriangleStrip
Return type: void
Description: Draw a triangle strip defined by points within an image
@@ -3154,7 +3147,7 @@ Function 347: ImageDrawTriangleStrip() (4 input parameters)
Param[2]: points (type: Vector2 *)
Param[3]: pointCount (type: int)
Param[4]: color (type: Color)
-Function 348: ImageDraw() (5 input parameters)
+Function 347: ImageDraw() (5 input parameters)
Name: ImageDraw
Return type: void
Description: Draw a source image within a destination image (tint applied to source)
@@ -3163,7 +3156,7 @@ Function 348: ImageDraw() (5 input parameters)
Param[3]: srcRec (type: Rectangle)
Param[4]: dstRec (type: Rectangle)
Param[5]: tint (type: Color)
-Function 349: ImageDrawText() (6 input parameters)
+Function 348: ImageDrawText() (6 input parameters)
Name: ImageDrawText
Return type: void
Description: Draw text (using default font) within an image (destination)
@@ -3173,7 +3166,7 @@ Function 349: ImageDrawText() (6 input parameters)
Param[4]: posY (type: int)
Param[5]: fontSize (type: int)
Param[6]: color (type: Color)
-Function 350: ImageDrawTextEx() (7 input parameters)
+Function 349: ImageDrawTextEx() (7 input parameters)
Name: ImageDrawTextEx
Return type: void
Description: Draw text (custom sprite font) within an image (destination)
@@ -3184,79 +3177,79 @@ Function 350: ImageDrawTextEx() (7 input parameters)
Param[5]: fontSize (type: float)
Param[6]: spacing (type: float)
Param[7]: tint (type: Color)
-Function 351: LoadTexture() (1 input parameters)
+Function 350: LoadTexture() (1 input parameters)
Name: LoadTexture
Return type: Texture2D
Description: Load texture from file into GPU memory (VRAM)
Param[1]: fileName (type: const char *)
-Function 352: LoadTextureFromImage() (1 input parameters)
+Function 351: LoadTextureFromImage() (1 input parameters)
Name: LoadTextureFromImage
Return type: Texture2D
Description: Load texture from image data
Param[1]: image (type: Image)
-Function 353: LoadTextureCubemap() (2 input parameters)
+Function 352: LoadTextureCubemap() (2 input parameters)
Name: LoadTextureCubemap
Return type: TextureCubemap
Description: Load cubemap from image, multiple image cubemap layouts supported
Param[1]: image (type: Image)
Param[2]: layout (type: int)
-Function 354: LoadRenderTexture() (2 input parameters)
+Function 353: LoadRenderTexture() (2 input parameters)
Name: LoadRenderTexture
Return type: RenderTexture2D
Description: Load texture for rendering (framebuffer)
Param[1]: width (type: int)
Param[2]: height (type: int)
-Function 355: IsTextureReady() (1 input parameters)
+Function 354: IsTextureReady() (1 input parameters)
Name: IsTextureReady
Return type: bool
Description: Check if a texture is ready
Param[1]: texture (type: Texture2D)
-Function 356: UnloadTexture() (1 input parameters)
+Function 355: UnloadTexture() (1 input parameters)
Name: UnloadTexture
Return type: void
Description: Unload texture from GPU memory (VRAM)
Param[1]: texture (type: Texture2D)
-Function 357: IsRenderTextureReady() (1 input parameters)
+Function 356: IsRenderTextureReady() (1 input parameters)
Name: IsRenderTextureReady
Return type: bool
Description: Check if a render texture is ready
Param[1]: target (type: RenderTexture2D)
-Function 358: UnloadRenderTexture() (1 input parameters)
+Function 357: UnloadRenderTexture() (1 input parameters)
Name: UnloadRenderTexture
Return type: void
Description: Unload render texture from GPU memory (VRAM)
Param[1]: target (type: RenderTexture2D)
-Function 359: UpdateTexture() (2 input parameters)
+Function 358: UpdateTexture() (2 input parameters)
Name: UpdateTexture
Return type: void
Description: Update GPU texture with new data
Param[1]: texture (type: Texture2D)
Param[2]: pixels (type: const void *)
-Function 360: UpdateTextureRec() (3 input parameters)
+Function 359: UpdateTextureRec() (3 input parameters)
Name: UpdateTextureRec
Return type: void
Description: Update GPU texture rectangle with new data
Param[1]: texture (type: Texture2D)
Param[2]: rec (type: Rectangle)
Param[3]: pixels (type: const void *)
-Function 361: GenTextureMipmaps() (1 input parameters)
+Function 360: GenTextureMipmaps() (1 input parameters)
Name: GenTextureMipmaps
Return type: void
Description: Generate GPU mipmaps for a texture
Param[1]: texture (type: Texture2D *)
-Function 362: SetTextureFilter() (2 input parameters)
+Function 361: SetTextureFilter() (2 input parameters)
Name: SetTextureFilter
Return type: void
Description: Set texture scaling filter mode
Param[1]: texture (type: Texture2D)
Param[2]: filter (type: int)
-Function 363: SetTextureWrap() (2 input parameters)
+Function 362: SetTextureWrap() (2 input parameters)
Name: SetTextureWrap
Return type: void
Description: Set texture wrapping mode
Param[1]: texture (type: Texture2D)
Param[2]: wrap (type: int)
-Function 364: DrawTexture() (4 input parameters)
+Function 363: DrawTexture() (4 input parameters)
Name: DrawTexture
Return type: void
Description: Draw a Texture2D
@@ -3264,14 +3257,14 @@ Function 364: DrawTexture() (4 input parameters)
Param[2]: posX (type: int)
Param[3]: posY (type: int)
Param[4]: tint (type: Color)
-Function 365: DrawTextureV() (3 input parameters)
+Function 364: DrawTextureV() (3 input parameters)
Name: DrawTextureV
Return type: void
Description: Draw a Texture2D with position defined as Vector2
Param[1]: texture (type: Texture2D)
Param[2]: position (type: Vector2)
Param[3]: tint (type: Color)
-Function 366: DrawTextureEx() (5 input parameters)
+Function 365: DrawTextureEx() (5 input parameters)
Name: DrawTextureEx
Return type: void
Description: Draw a Texture2D with extended parameters
@@ -3280,7 +3273,7 @@ Function 366: DrawTextureEx() (5 input parameters)
Param[3]: rotation (type: float)
Param[4]: scale (type: float)
Param[5]: tint (type: Color)
-Function 367: DrawTextureRec() (4 input parameters)
+Function 366: DrawTextureRec() (4 input parameters)
Name: DrawTextureRec
Return type: void
Description: Draw a part of a texture defined by a rectangle
@@ -3288,7 +3281,7 @@ Function 367: DrawTextureRec() (4 input parameters)
Param[2]: source (type: Rectangle)
Param[3]: position (type: Vector2)
Param[4]: tint (type: Color)
-Function 368: DrawTexturePro() (6 input parameters)
+Function 367: DrawTexturePro() (6 input parameters)
Name: DrawTexturePro
Return type: void
Description: Draw a part of a texture defined by a rectangle with 'pro' parameters
@@ -3298,7 +3291,7 @@ Function 368: DrawTexturePro() (6 input parameters)
Param[4]: origin (type: Vector2)
Param[5]: rotation (type: float)
Param[6]: tint (type: Color)
-Function 369: DrawTextureNPatch() (6 input parameters)
+Function 368: DrawTextureNPatch() (6 input parameters)
Name: DrawTextureNPatch
Return type: void
Description: Draws a texture (or part of it) that stretches or shrinks nicely
@@ -3308,119 +3301,119 @@ Function 369: DrawTextureNPatch() (6 input parameters)
Param[4]: origin (type: Vector2)
Param[5]: rotation (type: float)
Param[6]: tint (type: Color)
-Function 370: ColorIsEqual() (2 input parameters)
+Function 369: ColorIsEqual() (2 input parameters)
Name: ColorIsEqual
Return type: bool
Description: Check if two colors are equal
Param[1]: col1 (type: Color)
Param[2]: col2 (type: Color)
-Function 371: Fade() (2 input parameters)
+Function 370: Fade() (2 input parameters)
Name: Fade
Return type: Color
Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f
Param[1]: color (type: Color)
Param[2]: alpha (type: float)
-Function 372: ColorToInt() (1 input parameters)
+Function 371: ColorToInt() (1 input parameters)
Name: ColorToInt
Return type: int
Description: Get hexadecimal value for a Color (0xRRGGBBAA)
Param[1]: color (type: Color)
-Function 373: ColorNormalize() (1 input parameters)
+Function 372: ColorNormalize() (1 input parameters)
Name: ColorNormalize
Return type: Vector4
Description: Get Color normalized as float [0..1]
Param[1]: color (type: Color)
-Function 374: ColorFromNormalized() (1 input parameters)
+Function 373: ColorFromNormalized() (1 input parameters)
Name: ColorFromNormalized
Return type: Color
Description: Get Color from normalized values [0..1]
Param[1]: normalized (type: Vector4)
-Function 375: ColorToHSV() (1 input parameters)
+Function 374: ColorToHSV() (1 input parameters)
Name: ColorToHSV
Return type: Vector3
Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1]
Param[1]: color (type: Color)
-Function 376: ColorFromHSV() (3 input parameters)
+Function 375: ColorFromHSV() (3 input parameters)
Name: ColorFromHSV
Return type: Color
Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1]
Param[1]: hue (type: float)
Param[2]: saturation (type: float)
Param[3]: value (type: float)
-Function 377: ColorTint() (2 input parameters)
+Function 376: ColorTint() (2 input parameters)
Name: ColorTint
Return type: Color
Description: Get color multiplied with another color
Param[1]: color (type: Color)
Param[2]: tint (type: Color)
-Function 378: ColorBrightness() (2 input parameters)
+Function 377: ColorBrightness() (2 input parameters)
Name: ColorBrightness
Return type: Color
Description: Get color with brightness correction, brightness factor goes from -1.0f to 1.0f
Param[1]: color (type: Color)
Param[2]: factor (type: float)
-Function 379: ColorContrast() (2 input parameters)
+Function 378: ColorContrast() (2 input parameters)
Name: ColorContrast
Return type: Color
Description: Get color with contrast correction, contrast values between -1.0f and 1.0f
Param[1]: color (type: Color)
Param[2]: contrast (type: float)
-Function 380: ColorAlpha() (2 input parameters)
+Function 379: ColorAlpha() (2 input parameters)
Name: ColorAlpha
Return type: Color
Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f
Param[1]: color (type: Color)
Param[2]: alpha (type: float)
-Function 381: ColorAlphaBlend() (3 input parameters)
+Function 380: ColorAlphaBlend() (3 input parameters)
Name: ColorAlphaBlend
Return type: Color
Description: Get src alpha-blended into dst color with tint
Param[1]: dst (type: Color)
Param[2]: src (type: Color)
Param[3]: tint (type: Color)
-Function 382: ColorLerp() (3 input parameters)
+Function 381: ColorLerp() (3 input parameters)
Name: ColorLerp
Return type: Color
Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f]
Param[1]: color1 (type: Color)
Param[2]: color2 (type: Color)
Param[3]: factor (type: float)
-Function 383: GetColor() (1 input parameters)
+Function 382: GetColor() (1 input parameters)
Name: GetColor
Return type: Color
Description: Get Color structure from hexadecimal value
Param[1]: hexValue (type: unsigned int)
-Function 384: GetPixelColor() (2 input parameters)
+Function 383: GetPixelColor() (2 input parameters)
Name: GetPixelColor
Return type: Color
Description: Get Color from a source pixel pointer of certain format
Param[1]: srcPtr (type: void *)
Param[2]: format (type: int)
-Function 385: SetPixelColor() (3 input parameters)
+Function 384: SetPixelColor() (3 input parameters)
Name: SetPixelColor
Return type: void
Description: Set color formatted into destination pixel pointer
Param[1]: dstPtr (type: void *)
Param[2]: color (type: Color)
Param[3]: format (type: int)
-Function 386: GetPixelDataSize() (3 input parameters)
+Function 385: GetPixelDataSize() (3 input parameters)
Name: GetPixelDataSize
Return type: int
Description: Get pixel data size in bytes for certain format
Param[1]: width (type: int)
Param[2]: height (type: int)
Param[3]: format (type: int)
-Function 387: GetFontDefault() (0 input parameters)
+Function 386: GetFontDefault() (0 input parameters)
Name: GetFontDefault
Return type: Font
Description: Get the default Font
No input parameters
-Function 388: LoadFont() (1 input parameters)
+Function 387: LoadFont() (1 input parameters)
Name: LoadFont
Return type: Font
Description: Load font from file into GPU memory (VRAM)
Param[1]: fileName (type: const char *)
-Function 389: LoadFontEx() (4 input parameters)
+Function 388: LoadFontEx() (4 input parameters)
Name: LoadFontEx
Return type: Font
Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height
@@ -3428,14 +3421,14 @@ Function 389: LoadFontEx() (4 input parameters)
Param[2]: fontSize (type: int)
Param[3]: codepoints (type: int *)
Param[4]: codepointCount (type: int)
-Function 390: LoadFontFromImage() (3 input parameters)
+Function 389: LoadFontFromImage() (3 input parameters)
Name: LoadFontFromImage
Return type: Font
Description: Load font from Image (XNA style)
Param[1]: image (type: Image)
Param[2]: key (type: Color)
Param[3]: firstChar (type: int)
-Function 391: LoadFontFromMemory() (6 input parameters)
+Function 390: LoadFontFromMemory() (6 input parameters)
Name: LoadFontFromMemory
Return type: Font
Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
@@ -3445,12 +3438,12 @@ Function 391: LoadFontFromMemory() (6 input parameters)
Param[4]: fontSize (type: int)
Param[5]: codepoints (type: int *)
Param[6]: codepointCount (type: int)
-Function 392: IsFontReady() (1 input parameters)
+Function 391: IsFontReady() (1 input parameters)
Name: IsFontReady
Return type: bool
Description: Check if a font is ready
Param[1]: font (type: Font)
-Function 393: LoadFontData() (6 input parameters)
+Function 392: LoadFontData() (6 input parameters)
Name: LoadFontData
Return type: GlyphInfo *
Description: Load font data for further use
@@ -3460,7 +3453,7 @@ Function 393: LoadFontData() (6 input parameters)
Param[4]: codepoints (type: int *)
Param[5]: codepointCount (type: int)
Param[6]: type (type: int)
-Function 394: GenImageFontAtlas() (6 input parameters)
+Function 393: GenImageFontAtlas() (6 input parameters)
Name: GenImageFontAtlas
Return type: Image
Description: Generate image font atlas using chars info
@@ -3470,30 +3463,30 @@ Function 394: GenImageFontAtlas() (6 input parameters)
Param[4]: fontSize (type: int)
Param[5]: padding (type: int)
Param[6]: packMethod (type: int)
-Function 395: UnloadFontData() (2 input parameters)
+Function 394: UnloadFontData() (2 input parameters)
Name: UnloadFontData
Return type: void
Description: Unload font chars info data (RAM)
Param[1]: glyphs (type: GlyphInfo *)
Param[2]: glyphCount (type: int)
-Function 396: UnloadFont() (1 input parameters)
+Function 395: UnloadFont() (1 input parameters)
Name: UnloadFont
Return type: void
Description: Unload font from GPU memory (VRAM)
Param[1]: font (type: Font)
-Function 397: ExportFontAsCode() (2 input parameters)
+Function 396: ExportFontAsCode() (2 input parameters)
Name: ExportFontAsCode
Return type: bool
Description: Export font as code file, returns true on success
Param[1]: font (type: Font)
Param[2]: fileName (type: const char *)
-Function 398: DrawFPS() (2 input parameters)
+Function 397: DrawFPS() (2 input parameters)
Name: DrawFPS
Return type: void
Description: Draw current FPS
Param[1]: posX (type: int)
Param[2]: posY (type: int)
-Function 399: DrawText() (5 input parameters)
+Function 398: DrawText() (5 input parameters)
Name: DrawText
Return type: void
Description: Draw text (using default font)
@@ -3502,7 +3495,7 @@ Function 399: DrawText() (5 input parameters)
Param[3]: posY (type: int)
Param[4]: fontSize (type: int)
Param[5]: color (type: Color)
-Function 400: DrawTextEx() (6 input parameters)
+Function 399: DrawTextEx() (6 input parameters)
Name: DrawTextEx
Return type: void
Description: Draw text using font and additional parameters
@@ -3512,7 +3505,7 @@ Function 400: DrawTextEx() (6 input parameters)
Param[4]: fontSize (type: float)
Param[5]: spacing (type: float)
Param[6]: tint (type: Color)
-Function 401: DrawTextPro() (8 input parameters)
+Function 400: DrawTextPro() (8 input parameters)
Name: DrawTextPro
Return type: void
Description: Draw text using Font and pro parameters (rotation)
@@ -3524,7 +3517,7 @@ Function 401: DrawTextPro() (8 input parameters)
Param[6]: fontSize (type: float)
Param[7]: spacing (type: float)
Param[8]: tint (type: Color)
-Function 402: DrawTextCodepoint() (5 input parameters)
+Function 401: DrawTextCodepoint() (5 input parameters)
Name: DrawTextCodepoint
Return type: void
Description: Draw one character (codepoint)
@@ -3533,7 +3526,7 @@ Function 402: DrawTextCodepoint() (5 input parameters)
Param[3]: position (type: Vector2)
Param[4]: fontSize (type: float)
Param[5]: tint (type: Color)
-Function 403: DrawTextCodepoints() (7 input parameters)
+Function 402: DrawTextCodepoints() (7 input parameters)
Name: DrawTextCodepoints
Return type: void
Description: Draw multiple character (codepoint)
@@ -3544,18 +3537,18 @@ Function 403: DrawTextCodepoints() (7 input parameters)
Param[5]: fontSize (type: float)
Param[6]: spacing (type: float)
Param[7]: tint (type: Color)
-Function 404: SetTextLineSpacing() (1 input parameters)
+Function 403: SetTextLineSpacing() (1 input parameters)
Name: SetTextLineSpacing
Return type: void
Description: Set vertical line spacing when drawing with line-breaks
Param[1]: spacing (type: int)
-Function 405: MeasureText() (2 input parameters)
+Function 404: MeasureText() (2 input parameters)
Name: MeasureText
Return type: int
Description: Measure string width for default font
Param[1]: text (type: const char *)
Param[2]: fontSize (type: int)
-Function 406: MeasureTextEx() (4 input parameters)
+Function 405: MeasureTextEx() (4 input parameters)
Name: MeasureTextEx
Return type: Vector2
Description: Measure string size for Font
@@ -3563,195 +3556,195 @@ Function 406: MeasureTextEx() (4 input parameters)
Param[2]: text (type: const char *)
Param[3]: fontSize (type: float)
Param[4]: spacing (type: float)
-Function 407: GetGlyphIndex() (2 input parameters)
+Function 406: GetGlyphIndex() (2 input parameters)
Name: GetGlyphIndex
Return type: int
Description: Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found
Param[1]: font (type: Font)
Param[2]: codepoint (type: int)
-Function 408: GetGlyphInfo() (2 input parameters)
+Function 407: GetGlyphInfo() (2 input parameters)
Name: GetGlyphInfo
Return type: GlyphInfo
Description: Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found
Param[1]: font (type: Font)
Param[2]: codepoint (type: int)
-Function 409: GetGlyphAtlasRec() (2 input parameters)
+Function 408: GetGlyphAtlasRec() (2 input parameters)
Name: GetGlyphAtlasRec
Return type: Rectangle
Description: Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found
Param[1]: font (type: Font)
Param[2]: codepoint (type: int)
-Function 410: LoadUTF8() (2 input parameters)
+Function 409: LoadUTF8() (2 input parameters)
Name: LoadUTF8
Return type: char *
Description: Load UTF-8 text encoded from codepoints array
Param[1]: codepoints (type: const int *)
Param[2]: length (type: int)
-Function 411: UnloadUTF8() (1 input parameters)
+Function 410: UnloadUTF8() (1 input parameters)
Name: UnloadUTF8
Return type: void
Description: Unload UTF-8 text encoded from codepoints array
Param[1]: text (type: char *)
-Function 412: LoadCodepoints() (2 input parameters)
+Function 411: LoadCodepoints() (2 input parameters)
Name: LoadCodepoints
Return type: int *
Description: Load all codepoints from a UTF-8 text string, codepoints count returned by parameter
Param[1]: text (type: const char *)
Param[2]: count (type: int *)
-Function 413: UnloadCodepoints() (1 input parameters)
+Function 412: UnloadCodepoints() (1 input parameters)
Name: UnloadCodepoints
Return type: void
Description: Unload codepoints data from memory
Param[1]: codepoints (type: int *)
-Function 414: GetCodepointCount() (1 input parameters)
+Function 413: GetCodepointCount() (1 input parameters)
Name: GetCodepointCount
Return type: int
Description: Get total number of codepoints in a UTF-8 encoded string
Param[1]: text (type: const char *)
-Function 415: GetCodepoint() (2 input parameters)
+Function 414: GetCodepoint() (2 input parameters)
Name: GetCodepoint
Return type: int
Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
Param[1]: text (type: const char *)
Param[2]: codepointSize (type: int *)
-Function 416: GetCodepointNext() (2 input parameters)
+Function 415: GetCodepointNext() (2 input parameters)
Name: GetCodepointNext
Return type: int
Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
Param[1]: text (type: const char *)
Param[2]: codepointSize (type: int *)
-Function 417: GetCodepointPrevious() (2 input parameters)
+Function 416: GetCodepointPrevious() (2 input parameters)
Name: GetCodepointPrevious
Return type: int
Description: Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
Param[1]: text (type: const char *)
Param[2]: codepointSize (type: int *)
-Function 418: CodepointToUTF8() (2 input parameters)
+Function 417: CodepointToUTF8() (2 input parameters)
Name: CodepointToUTF8
Return type: const char *
Description: Encode one codepoint into UTF-8 byte array (array length returned as parameter)
Param[1]: codepoint (type: int)
Param[2]: utf8Size (type: int *)
-Function 419: TextCopy() (2 input parameters)
+Function 418: TextCopy() (2 input parameters)
Name: TextCopy
Return type: int
Description: Copy one string to another, returns bytes copied
Param[1]: dst (type: char *)
Param[2]: src (type: const char *)
-Function 420: TextIsEqual() (2 input parameters)
+Function 419: TextIsEqual() (2 input parameters)
Name: TextIsEqual
Return type: bool
Description: Check if two text string are equal
Param[1]: text1 (type: const char *)
Param[2]: text2 (type: const char *)
-Function 421: TextLength() (1 input parameters)
+Function 420: TextLength() (1 input parameters)
Name: TextLength
Return type: unsigned int
Description: Get text length, checks for '\0' ending
Param[1]: text (type: const char *)
-Function 422: TextFormat() (2 input parameters)
+Function 421: TextFormat() (2 input parameters)
Name: TextFormat
Return type: const char *
Description: Text formatting with variables (sprintf() style)
Param[1]: text (type: const char *)
Param[2]: args (type: ...)
-Function 423: TextSubtext() (3 input parameters)
+Function 422: TextSubtext() (3 input parameters)
Name: TextSubtext
Return type: const char *
Description: Get a piece of a text string
Param[1]: text (type: const char *)
Param[2]: position (type: int)
Param[3]: length (type: int)
-Function 424: TextReplace() (3 input parameters)
+Function 423: TextReplace() (3 input parameters)
Name: TextReplace
Return type: char *
Description: Replace text string (WARNING: memory must be freed!)
Param[1]: text (type: const char *)
Param[2]: replace (type: const char *)
Param[3]: by (type: const char *)
-Function 425: TextInsert() (3 input parameters)
+Function 424: TextInsert() (3 input parameters)
Name: TextInsert
Return type: char *
Description: Insert text in a position (WARNING: memory must be freed!)
Param[1]: text (type: const char *)
Param[2]: insert (type: const char *)
Param[3]: position (type: int)
-Function 426: TextJoin() (3 input parameters)
+Function 425: TextJoin() (3 input parameters)
Name: TextJoin
Return type: const char *
Description: Join text strings with delimiter
Param[1]: textList (type: const char **)
Param[2]: count (type: int)
Param[3]: delimiter (type: const char *)
-Function 427: TextSplit() (3 input parameters)
+Function 426: TextSplit() (3 input parameters)
Name: TextSplit
Return type: const char **
Description: Split text into multiple strings
Param[1]: text (type: const char *)
Param[2]: delimiter (type: char)
Param[3]: count (type: int *)
-Function 428: TextAppend() (3 input parameters)
+Function 427: TextAppend() (3 input parameters)
Name: TextAppend
Return type: void
Description: Append text at specific position and move cursor!
Param[1]: text (type: char *)
Param[2]: append (type: const char *)
Param[3]: position (type: int *)
-Function 429: TextFindIndex() (2 input parameters)
+Function 428: TextFindIndex() (2 input parameters)
Name: TextFindIndex
Return type: int
Description: Find first text occurrence within a string
Param[1]: text (type: const char *)
Param[2]: find (type: const char *)
-Function 430: TextToUpper() (1 input parameters)
+Function 429: TextToUpper() (1 input parameters)
Name: TextToUpper
Return type: const char *
Description: Get upper case version of provided string
Param[1]: text (type: const char *)
-Function 431: TextToLower() (1 input parameters)
+Function 430: TextToLower() (1 input parameters)
Name: TextToLower
Return type: const char *
Description: Get lower case version of provided string
Param[1]: text (type: const char *)
-Function 432: TextToPascal() (1 input parameters)
+Function 431: TextToPascal() (1 input parameters)
Name: TextToPascal
Return type: const char *
Description: Get Pascal case notation version of provided string
Param[1]: text (type: const char *)
-Function 433: TextToSnake() (1 input parameters)
+Function 432: TextToSnake() (1 input parameters)
Name: TextToSnake
Return type: const char *
Description: Get Snake case notation version of provided string
Param[1]: text (type: const char *)
-Function 434: TextToCamel() (1 input parameters)
+Function 433: TextToCamel() (1 input parameters)
Name: TextToCamel
Return type: const char *
Description: Get Camel case notation version of provided string
Param[1]: text (type: const char *)
-Function 435: TextToInteger() (1 input parameters)
+Function 434: TextToInteger() (1 input parameters)
Name: TextToInteger
Return type: int
Description: Get integer value from text (negative values not supported)
Param[1]: text (type: const char *)
-Function 436: TextToFloat() (1 input parameters)
+Function 435: TextToFloat() (1 input parameters)
Name: TextToFloat
Return type: float
Description: Get float value from text (negative values not supported)
Param[1]: text (type: const char *)
-Function 437: DrawLine3D() (3 input parameters)
+Function 436: DrawLine3D() (3 input parameters)
Name: DrawLine3D
Return type: void
Description: Draw a line in 3D world space
Param[1]: startPos (type: Vector3)
Param[2]: endPos (type: Vector3)
Param[3]: color (type: Color)
-Function 438: DrawPoint3D() (2 input parameters)
+Function 437: DrawPoint3D() (2 input parameters)
Name: DrawPoint3D
Return type: void
Description: Draw a point in 3D space, actually a small line
Param[1]: position (type: Vector3)
Param[2]: color (type: Color)
-Function 439: DrawCircle3D() (5 input parameters)
+Function 438: DrawCircle3D() (5 input parameters)
Name: DrawCircle3D
Return type: void
Description: Draw a circle in 3D world space
@@ -3760,7 +3753,7 @@ Function 439: DrawCircle3D() (5 input parameters)
Param[3]: rotationAxis (type: Vector3)
Param[4]: rotationAngle (type: float)
Param[5]: color (type: Color)
-Function 440: DrawTriangle3D() (4 input parameters)
+Function 439: DrawTriangle3D() (4 input parameters)
Name: DrawTriangle3D
Return type: void
Description: Draw a color-filled triangle (vertex in counter-clockwise order!)
@@ -3768,14 +3761,14 @@ Function 440: DrawTriangle3D() (4 input parameters)
Param[2]: v2 (type: Vector3)
Param[3]: v3 (type: Vector3)
Param[4]: color (type: Color)
-Function 441: DrawTriangleStrip3D() (3 input parameters)
+Function 440: DrawTriangleStrip3D() (3 input parameters)
Name: DrawTriangleStrip3D
Return type: void
Description: Draw a triangle strip defined by points
Param[1]: points (type: const Vector3 *)
Param[2]: pointCount (type: int)
Param[3]: color (type: Color)
-Function 442: DrawCube() (5 input parameters)
+Function 441: DrawCube() (5 input parameters)
Name: DrawCube
Return type: void
Description: Draw cube
@@ -3784,14 +3777,14 @@ Function 442: DrawCube() (5 input parameters)
Param[3]: height (type: float)
Param[4]: length (type: float)
Param[5]: color (type: Color)
-Function 443: DrawCubeV() (3 input parameters)
+Function 442: DrawCubeV() (3 input parameters)
Name: DrawCubeV
Return type: void
Description: Draw cube (Vector version)
Param[1]: position (type: Vector3)
Param[2]: size (type: Vector3)
Param[3]: color (type: Color)
-Function 444: DrawCubeWires() (5 input parameters)
+Function 443: DrawCubeWires() (5 input parameters)
Name: DrawCubeWires
Return type: void
Description: Draw cube wires
@@ -3800,21 +3793,21 @@ Function 444: DrawCubeWires() (5 input parameters)
Param[3]: height (type: float)
Param[4]: length (type: float)
Param[5]: color (type: Color)
-Function 445: DrawCubeWiresV() (3 input parameters)
+Function 444: DrawCubeWiresV() (3 input parameters)
Name: DrawCubeWiresV
Return type: void
Description: Draw cube wires (Vector version)
Param[1]: position (type: Vector3)
Param[2]: size (type: Vector3)
Param[3]: color (type: Color)
-Function 446: DrawSphere() (3 input parameters)
+Function 445: DrawSphere() (3 input parameters)
Name: DrawSphere
Return type: void
Description: Draw sphere
Param[1]: centerPos (type: Vector3)
Param[2]: radius (type: float)
Param[3]: color (type: Color)
-Function 447: DrawSphereEx() (5 input parameters)
+Function 446: DrawSphereEx() (5 input parameters)
Name: DrawSphereEx
Return type: void
Description: Draw sphere with extended parameters
@@ -3823,7 +3816,7 @@ Function 447: DrawSphereEx() (5 input parameters)
Param[3]: rings (type: int)
Param[4]: slices (type: int)
Param[5]: color (type: Color)
-Function 448: DrawSphereWires() (5 input parameters)
+Function 447: DrawSphereWires() (5 input parameters)
Name: DrawSphereWires
Return type: void
Description: Draw sphere wires
@@ -3832,7 +3825,7 @@ Function 448: DrawSphereWires() (5 input parameters)
Param[3]: rings (type: int)
Param[4]: slices (type: int)
Param[5]: color (type: Color)
-Function 449: DrawCylinder() (6 input parameters)
+Function 448: DrawCylinder() (6 input parameters)
Name: DrawCylinder
Return type: void
Description: Draw a cylinder/cone
@@ -3842,7 +3835,7 @@ Function 449: DrawCylinder() (6 input parameters)
Param[4]: height (type: float)
Param[5]: slices (type: int)
Param[6]: color (type: Color)
-Function 450: DrawCylinderEx() (6 input parameters)
+Function 449: DrawCylinderEx() (6 input parameters)
Name: DrawCylinderEx
Return type: void
Description: Draw a cylinder with base at startPos and top at endPos
@@ -3852,7 +3845,7 @@ Function 450: DrawCylinderEx() (6 input parameters)
Param[4]: endRadius (type: float)
Param[5]: sides (type: int)
Param[6]: color (type: Color)
-Function 451: DrawCylinderWires() (6 input parameters)
+Function 450: DrawCylinderWires() (6 input parameters)
Name: DrawCylinderWires
Return type: void
Description: Draw a cylinder/cone wires
@@ -3862,7 +3855,7 @@ Function 451: DrawCylinderWires() (6 input parameters)
Param[4]: height (type: float)
Param[5]: slices (type: int)
Param[6]: color (type: Color)
-Function 452: DrawCylinderWiresEx() (6 input parameters)
+Function 451: DrawCylinderWiresEx() (6 input parameters)
Name: DrawCylinderWiresEx
Return type: void
Description: Draw a cylinder wires with base at startPos and top at endPos
@@ -3872,7 +3865,7 @@ Function 452: DrawCylinderWiresEx() (6 input parameters)
Param[4]: endRadius (type: float)
Param[5]: sides (type: int)
Param[6]: color (type: Color)
-Function 453: DrawCapsule() (6 input parameters)
+Function 452: DrawCapsule() (6 input parameters)
Name: DrawCapsule
Return type: void
Description: Draw a capsule with the center of its sphere caps at startPos and endPos
@@ -3882,7 +3875,7 @@ Function 453: DrawCapsule() (6 input parameters)
Param[4]: slices (type: int)
Param[5]: rings (type: int)
Param[6]: color (type: Color)
-Function 454: DrawCapsuleWires() (6 input parameters)
+Function 453: DrawCapsuleWires() (6 input parameters)
Name: DrawCapsuleWires
Return type: void
Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos
@@ -3892,51 +3885,51 @@ Function 454: DrawCapsuleWires() (6 input parameters)
Param[4]: slices (type: int)
Param[5]: rings (type: int)
Param[6]: color (type: Color)
-Function 455: DrawPlane() (3 input parameters)
+Function 454: DrawPlane() (3 input parameters)
Name: DrawPlane
Return type: void
Description: Draw a plane XZ
Param[1]: centerPos (type: Vector3)
Param[2]: size (type: Vector2)
Param[3]: color (type: Color)
-Function 456: DrawRay() (2 input parameters)
+Function 455: DrawRay() (2 input parameters)
Name: DrawRay
Return type: void
Description: Draw a ray line
Param[1]: ray (type: Ray)
Param[2]: color (type: Color)
-Function 457: DrawGrid() (2 input parameters)
+Function 456: DrawGrid() (2 input parameters)
Name: DrawGrid
Return type: void
Description: Draw a grid (centered at (0, 0, 0))
Param[1]: slices (type: int)
Param[2]: spacing (type: float)
-Function 458: LoadModel() (1 input parameters)
+Function 457: LoadModel() (1 input parameters)
Name: LoadModel
Return type: Model
Description: Load model from files (meshes and materials)
Param[1]: fileName (type: const char *)
-Function 459: LoadModelFromMesh() (1 input parameters)
+Function 458: LoadModelFromMesh() (1 input parameters)
Name: LoadModelFromMesh
Return type: Model
Description: Load model from generated mesh (default material)
Param[1]: mesh (type: Mesh)
-Function 460: IsModelReady() (1 input parameters)
+Function 459: IsModelReady() (1 input parameters)
Name: IsModelReady
Return type: bool
Description: Check if a model is ready
Param[1]: model (type: Model)
-Function 461: UnloadModel() (1 input parameters)
+Function 460: UnloadModel() (1 input parameters)
Name: UnloadModel
Return type: void
Description: Unload model (including meshes) from memory (RAM and/or VRAM)
Param[1]: model (type: Model)
-Function 462: GetModelBoundingBox() (1 input parameters)
+Function 461: GetModelBoundingBox() (1 input parameters)
Name: GetModelBoundingBox
Return type: BoundingBox
Description: Compute model bounding box limits (considers all meshes)
Param[1]: model (type: Model)
-Function 463: DrawModel() (4 input parameters)
+Function 462: DrawModel() (4 input parameters)
Name: DrawModel
Return type: void
Description: Draw a model (with texture if set)
@@ -3944,7 +3937,7 @@ Function 463: DrawModel() (4 input parameters)
Param[2]: position (type: Vector3)
Param[3]: scale (type: float)
Param[4]: tint (type: Color)
-Function 464: DrawModelEx() (6 input parameters)
+Function 463: DrawModelEx() (6 input parameters)
Name: DrawModelEx
Return type: void
Description: Draw a model with extended parameters
@@ -3954,7 +3947,7 @@ Function 464: DrawModelEx() (6 input parameters)
Param[4]: rotationAngle (type: float)
Param[5]: scale (type: Vector3)
Param[6]: tint (type: Color)
-Function 465: DrawModelWires() (4 input parameters)
+Function 464: DrawModelWires() (4 input parameters)
Name: DrawModelWires
Return type: void
Description: Draw a model wires (with texture if set)
@@ -3962,7 +3955,7 @@ Function 465: DrawModelWires() (4 input parameters)
Param[2]: position (type: Vector3)
Param[3]: scale (type: float)
Param[4]: tint (type: Color)
-Function 466: DrawModelWiresEx() (6 input parameters)
+Function 465: DrawModelWiresEx() (6 input parameters)
Name: DrawModelWiresEx
Return type: void
Description: Draw a model wires (with texture if set) with extended parameters
@@ -3972,7 +3965,7 @@ Function 466: DrawModelWiresEx() (6 input parameters)
Param[4]: rotationAngle (type: float)
Param[5]: scale (type: Vector3)
Param[6]: tint (type: Color)
-Function 467: DrawModelPoints() (4 input parameters)
+Function 466: DrawModelPoints() (4 input parameters)
Name: DrawModelPoints
Return type: void
Description: Draw a model as points
@@ -3980,7 +3973,7 @@ Function 467: DrawModelPoints() (4 input parameters)
Param[2]: position (type: Vector3)
Param[3]: scale (type: float)
Param[4]: tint (type: Color)
-Function 468: DrawModelPointsEx() (6 input parameters)
+Function 467: DrawModelPointsEx() (6 input parameters)
Name: DrawModelPointsEx
Return type: void
Description: Draw a model as points with extended parameters
@@ -3990,13 +3983,13 @@ Function 468: DrawModelPointsEx() (6 input parameters)
Param[4]: rotationAngle (type: float)
Param[5]: scale (type: Vector3)
Param[6]: tint (type: Color)
-Function 469: DrawBoundingBox() (2 input parameters)
+Function 468: DrawBoundingBox() (2 input parameters)
Name: DrawBoundingBox
Return type: void
Description: Draw bounding box (wires)
Param[1]: box (type: BoundingBox)
Param[2]: color (type: Color)
-Function 470: DrawBillboard() (5 input parameters)
+Function 469: DrawBillboard() (5 input parameters)
Name: DrawBillboard
Return type: void
Description: Draw a billboard texture
@@ -4005,7 +3998,7 @@ Function 470: DrawBillboard() (5 input parameters)
Param[3]: position (type: Vector3)
Param[4]: scale (type: float)
Param[5]: tint (type: Color)
-Function 471: DrawBillboardRec() (6 input parameters)
+Function 470: DrawBillboardRec() (6 input parameters)
Name: DrawBillboardRec
Return type: void
Description: Draw a billboard texture defined by source
@@ -4015,7 +4008,7 @@ Function 471: DrawBillboardRec() (6 input parameters)
Param[4]: position (type: Vector3)
Param[5]: size (type: Vector2)
Param[6]: tint (type: Color)
-Function 472: DrawBillboardPro() (9 input parameters)
+Function 471: DrawBillboardPro() (9 input parameters)
Name: DrawBillboardPro
Return type: void
Description: Draw a billboard texture defined by source and rotation
@@ -4028,13 +4021,13 @@ Function 472: DrawBillboardPro() (9 input parameters)
Param[7]: origin (type: Vector2)
Param[8]: rotation (type: float)
Param[9]: tint (type: Color)
-Function 473: UploadMesh() (2 input parameters)
+Function 472: UploadMesh() (2 input parameters)
Name: UploadMesh
Return type: void
Description: Upload mesh vertex data in GPU and provide VAO/VBO ids
Param[1]: mesh (type: Mesh *)
Param[2]: dynamic (type: bool)
-Function 474: UpdateMeshBuffer() (5 input parameters)
+Function 473: UpdateMeshBuffer() (5 input parameters)
Name: UpdateMeshBuffer
Return type: void
Description: Update mesh vertex data in GPU for a specific buffer index
@@ -4043,19 +4036,19 @@ Function 474: UpdateMeshBuffer() (5 input parameters)
Param[3]: data (type: const void *)
Param[4]: dataSize (type: int)
Param[5]: offset (type: int)
-Function 475: UnloadMesh() (1 input parameters)
+Function 474: UnloadMesh() (1 input parameters)
Name: UnloadMesh
Return type: void
Description: Unload mesh data from CPU and GPU
Param[1]: mesh (type: Mesh)
-Function 476: DrawMesh() (3 input parameters)
+Function 475: DrawMesh() (3 input parameters)
Name: DrawMesh
Return type: void
Description: Draw a 3d mesh with material and transform
Param[1]: mesh (type: Mesh)
Param[2]: material (type: Material)
Param[3]: transform (type: Matrix)
-Function 477: DrawMeshInstanced() (4 input parameters)
+Function 476: DrawMeshInstanced() (4 input parameters)
Name: DrawMeshInstanced
Return type: void
Description: Draw multiple mesh instances with material and different transforms
@@ -4063,35 +4056,35 @@ Function 477: DrawMeshInstanced() (4 input parameters)
Param[2]: material (type: Material)
Param[3]: transforms (type: const Matrix *)
Param[4]: instances (type: int)
-Function 478: GetMeshBoundingBox() (1 input parameters)
+Function 477: GetMeshBoundingBox() (1 input parameters)
Name: GetMeshBoundingBox
Return type: BoundingBox
Description: Compute mesh bounding box limits
Param[1]: mesh (type: Mesh)
-Function 479: GenMeshTangents() (1 input parameters)
+Function 478: GenMeshTangents() (1 input parameters)
Name: GenMeshTangents
Return type: void
Description: Compute mesh tangents
Param[1]: mesh (type: Mesh *)
-Function 480: ExportMesh() (2 input parameters)
+Function 479: ExportMesh() (2 input parameters)
Name: ExportMesh
Return type: bool
Description: Export mesh data to file, returns true on success
Param[1]: mesh (type: Mesh)
Param[2]: fileName (type: const char *)
-Function 481: ExportMeshAsCode() (2 input parameters)
+Function 480: ExportMeshAsCode() (2 input parameters)
Name: ExportMeshAsCode
Return type: bool
Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes
Param[1]: mesh (type: Mesh)
Param[2]: fileName (type: const char *)
-Function 482: GenMeshPoly() (2 input parameters)
+Function 481: GenMeshPoly() (2 input parameters)
Name: GenMeshPoly
Return type: Mesh
Description: Generate polygonal mesh
Param[1]: sides (type: int)
Param[2]: radius (type: float)
-Function 483: GenMeshPlane() (4 input parameters)
+Function 482: GenMeshPlane() (4 input parameters)
Name: GenMeshPlane
Return type: Mesh
Description: Generate plane mesh (with subdivisions)
@@ -4099,42 +4092,42 @@ Function 483: GenMeshPlane() (4 input parameters)
Param[2]: length (type: float)
Param[3]: resX (type: int)
Param[4]: resZ (type: int)
-Function 484: GenMeshCube() (3 input parameters)
+Function 483: GenMeshCube() (3 input parameters)
Name: GenMeshCube
Return type: Mesh
Description: Generate cuboid mesh
Param[1]: width (type: float)
Param[2]: height (type: float)
Param[3]: length (type: float)
-Function 485: GenMeshSphere() (3 input parameters)
+Function 484: GenMeshSphere() (3 input parameters)
Name: GenMeshSphere
Return type: Mesh
Description: Generate sphere mesh (standard sphere)
Param[1]: radius (type: float)
Param[2]: rings (type: int)
Param[3]: slices (type: int)
-Function 486: GenMeshHemiSphere() (3 input parameters)
+Function 485: GenMeshHemiSphere() (3 input parameters)
Name: GenMeshHemiSphere
Return type: Mesh
Description: Generate half-sphere mesh (no bottom cap)
Param[1]: radius (type: float)
Param[2]: rings (type: int)
Param[3]: slices (type: int)
-Function 487: GenMeshCylinder() (3 input parameters)
+Function 486: GenMeshCylinder() (3 input parameters)
Name: GenMeshCylinder
Return type: Mesh
Description: Generate cylinder mesh
Param[1]: radius (type: float)
Param[2]: height (type: float)
Param[3]: slices (type: int)
-Function 488: GenMeshCone() (3 input parameters)
+Function 487: GenMeshCone() (3 input parameters)
Name: GenMeshCone
Return type: Mesh
Description: Generate cone/pyramid mesh
Param[1]: radius (type: float)
Param[2]: height (type: float)
Param[3]: slices (type: int)
-Function 489: GenMeshTorus() (4 input parameters)
+Function 488: GenMeshTorus() (4 input parameters)
Name: GenMeshTorus
Return type: Mesh
Description: Generate torus mesh
@@ -4142,7 +4135,7 @@ Function 489: GenMeshTorus() (4 input parameters)
Param[2]: size (type: float)
Param[3]: radSeg (type: int)
Param[4]: sides (type: int)
-Function 490: GenMeshKnot() (4 input parameters)
+Function 489: GenMeshKnot() (4 input parameters)
Name: GenMeshKnot
Return type: Mesh
Description: Generate trefoil knot mesh
@@ -4150,91 +4143,91 @@ Function 490: GenMeshKnot() (4 input parameters)
Param[2]: size (type: float)
Param[3]: radSeg (type: int)
Param[4]: sides (type: int)
-Function 491: GenMeshHeightmap() (2 input parameters)
+Function 490: GenMeshHeightmap() (2 input parameters)
Name: GenMeshHeightmap
Return type: Mesh
Description: Generate heightmap mesh from image data
Param[1]: heightmap (type: Image)
Param[2]: size (type: Vector3)
-Function 492: GenMeshCubicmap() (2 input parameters)
+Function 491: GenMeshCubicmap() (2 input parameters)
Name: GenMeshCubicmap
Return type: Mesh
Description: Generate cubes-based map mesh from image data
Param[1]: cubicmap (type: Image)
Param[2]: cubeSize (type: Vector3)
-Function 493: LoadMaterials() (2 input parameters)
+Function 492: LoadMaterials() (2 input parameters)
Name: LoadMaterials
Return type: Material *
Description: Load materials from model file
Param[1]: fileName (type: const char *)
Param[2]: materialCount (type: int *)
-Function 494: LoadMaterialDefault() (0 input parameters)
+Function 493: LoadMaterialDefault() (0 input parameters)
Name: LoadMaterialDefault
Return type: Material
Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
No input parameters
-Function 495: IsMaterialReady() (1 input parameters)
+Function 494: IsMaterialReady() (1 input parameters)
Name: IsMaterialReady
Return type: bool
Description: Check if a material is ready
Param[1]: material (type: Material)
-Function 496: UnloadMaterial() (1 input parameters)
+Function 495: UnloadMaterial() (1 input parameters)
Name: UnloadMaterial
Return type: void
Description: Unload material from GPU memory (VRAM)
Param[1]: material (type: Material)
-Function 497: SetMaterialTexture() (3 input parameters)
+Function 496: SetMaterialTexture() (3 input parameters)
Name: SetMaterialTexture
Return type: void
Description: Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
Param[1]: material (type: Material *)
Param[2]: mapType (type: int)
Param[3]: texture (type: Texture2D)
-Function 498: SetModelMeshMaterial() (3 input parameters)
+Function 497: SetModelMeshMaterial() (3 input parameters)
Name: SetModelMeshMaterial
Return type: void
Description: Set material for a mesh
Param[1]: model (type: Model *)
Param[2]: meshId (type: int)
Param[3]: materialId (type: int)
-Function 499: LoadModelAnimations() (2 input parameters)
+Function 498: LoadModelAnimations() (2 input parameters)
Name: LoadModelAnimations
Return type: ModelAnimation *
Description: Load model animations from file
Param[1]: fileName (type: const char *)
Param[2]: animCount (type: int *)
-Function 500: UpdateModelAnimation() (3 input parameters)
+Function 499: UpdateModelAnimation() (3 input parameters)
Name: UpdateModelAnimation
Return type: void
Description: Update model animation pose
Param[1]: model (type: Model)
Param[2]: anim (type: ModelAnimation)
Param[3]: frame (type: int)
-Function 501: UnloadModelAnimation() (1 input parameters)
+Function 500: UnloadModelAnimation() (1 input parameters)
Name: UnloadModelAnimation
Return type: void
Description: Unload animation data
Param[1]: anim (type: ModelAnimation)
-Function 502: UnloadModelAnimations() (2 input parameters)
+Function 501: UnloadModelAnimations() (2 input parameters)
Name: UnloadModelAnimations
Return type: void
Description: Unload animation array data
Param[1]: animations (type: ModelAnimation *)
Param[2]: animCount (type: int)
-Function 503: IsModelAnimationValid() (2 input parameters)
+Function 502: IsModelAnimationValid() (2 input parameters)
Name: IsModelAnimationValid
Return type: bool
Description: Check model animation skeleton match
Param[1]: model (type: Model)
Param[2]: anim (type: ModelAnimation)
-Function 504: UpdateModelAnimationBoneMatrices() (3 input parameters)
+Function 503: UpdateModelAnimationBoneMatrices() (3 input parameters)
Name: UpdateModelAnimationBoneMatrices
Return type: void
Description: Update model animation mesh bone matrices (Note GPU skinning does not work on Mac)
Param[1]: model (type: Model)
Param[2]: anim (type: ModelAnimation)
Param[3]: frame (type: int)
-Function 505: CheckCollisionSpheres() (4 input parameters)
+Function 504: CheckCollisionSpheres() (4 input parameters)
Name: CheckCollisionSpheres
Return type: bool
Description: Check collision between two spheres
@@ -4242,40 +4235,40 @@ Function 505: CheckCollisionSpheres() (4 input parameters)
Param[2]: radius1 (type: float)
Param[3]: center2 (type: Vector3)
Param[4]: radius2 (type: float)
-Function 506: CheckCollisionBoxes() (2 input parameters)
+Function 505: CheckCollisionBoxes() (2 input parameters)
Name: CheckCollisionBoxes
Return type: bool
Description: Check collision between two bounding boxes
Param[1]: box1 (type: BoundingBox)
Param[2]: box2 (type: BoundingBox)
-Function 507: CheckCollisionBoxSphere() (3 input parameters)
+Function 506: CheckCollisionBoxSphere() (3 input parameters)
Name: CheckCollisionBoxSphere
Return type: bool
Description: Check collision between box and sphere
Param[1]: box (type: BoundingBox)
Param[2]: center (type: Vector3)
Param[3]: radius (type: float)
-Function 508: GetRayCollisionSphere() (3 input parameters)
+Function 507: GetRayCollisionSphere() (3 input parameters)
Name: GetRayCollisionSphere
Return type: RayCollision
Description: Get collision info between ray and sphere
Param[1]: ray (type: Ray)
Param[2]: center (type: Vector3)
Param[3]: radius (type: float)
-Function 509: GetRayCollisionBox() (2 input parameters)
+Function 508: GetRayCollisionBox() (2 input parameters)
Name: GetRayCollisionBox
Return type: RayCollision
Description: Get collision info between ray and box
Param[1]: ray (type: Ray)
Param[2]: box (type: BoundingBox)
-Function 510: GetRayCollisionMesh() (3 input parameters)
+Function 509: GetRayCollisionMesh() (3 input parameters)
Name: GetRayCollisionMesh
Return type: RayCollision
Description: Get collision info between ray and mesh
Param[1]: ray (type: Ray)
Param[2]: mesh (type: Mesh)
Param[3]: transform (type: Matrix)
-Function 511: GetRayCollisionTriangle() (4 input parameters)
+Function 510: GetRayCollisionTriangle() (4 input parameters)
Name: GetRayCollisionTriangle
Return type: RayCollision
Description: Get collision info between ray and triangle
@@ -4283,7 +4276,7 @@ Function 511: GetRayCollisionTriangle() (4 input parameters)
Param[2]: p1 (type: Vector3)
Param[3]: p2 (type: Vector3)
Param[4]: p3 (type: Vector3)
-Function 512: GetRayCollisionQuad() (5 input parameters)
+Function 511: GetRayCollisionQuad() (5 input parameters)
Name: GetRayCollisionQuad
Return type: RayCollision
Description: Get collision info between ray and quad
@@ -4292,158 +4285,158 @@ Function 512: GetRayCollisionQuad() (5 input parameters)
Param[3]: p2 (type: Vector3)
Param[4]: p3 (type: Vector3)
Param[5]: p4 (type: Vector3)
-Function 513: InitAudioDevice() (0 input parameters)
+Function 512: InitAudioDevice() (0 input parameters)
Name: InitAudioDevice
Return type: void
Description: Initialize audio device and context
No input parameters
-Function 514: CloseAudioDevice() (0 input parameters)
+Function 513: CloseAudioDevice() (0 input parameters)
Name: CloseAudioDevice
Return type: void
Description: Close the audio device and context
No input parameters
-Function 515: IsAudioDeviceReady() (0 input parameters)
+Function 514: IsAudioDeviceReady() (0 input parameters)
Name: IsAudioDeviceReady
Return type: bool
Description: Check if audio device has been initialized successfully
No input parameters
-Function 516: SetMasterVolume() (1 input parameters)
+Function 515: SetMasterVolume() (1 input parameters)
Name: SetMasterVolume
Return type: void
Description: Set master volume (listener)
Param[1]: volume (type: float)
-Function 517: GetMasterVolume() (0 input parameters)
+Function 516: GetMasterVolume() (0 input parameters)
Name: GetMasterVolume
Return type: float
Description: Get master volume (listener)
No input parameters
-Function 518: LoadWave() (1 input parameters)
+Function 517: LoadWave() (1 input parameters)
Name: LoadWave
Return type: Wave
Description: Load wave data from file
Param[1]: fileName (type: const char *)
-Function 519: LoadWaveFromMemory() (3 input parameters)
+Function 518: LoadWaveFromMemory() (3 input parameters)
Name: LoadWaveFromMemory
Return type: Wave
Description: Load wave from memory buffer, fileType refers to extension: i.e. '.wav'
Param[1]: fileType (type: const char *)
Param[2]: fileData (type: const unsigned char *)
Param[3]: dataSize (type: int)
-Function 520: IsWaveReady() (1 input parameters)
+Function 519: IsWaveReady() (1 input parameters)
Name: IsWaveReady
Return type: bool
Description: Checks if wave data is ready
Param[1]: wave (type: Wave)
-Function 521: LoadSound() (1 input parameters)
+Function 520: LoadSound() (1 input parameters)
Name: LoadSound
Return type: Sound
Description: Load sound from file
Param[1]: fileName (type: const char *)
-Function 522: LoadSoundFromWave() (1 input parameters)
+Function 521: LoadSoundFromWave() (1 input parameters)
Name: LoadSoundFromWave
Return type: Sound
Description: Load sound from wave data
Param[1]: wave (type: Wave)
-Function 523: LoadSoundAlias() (1 input parameters)
+Function 522: LoadSoundAlias() (1 input parameters)
Name: LoadSoundAlias
Return type: Sound
Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data
Param[1]: source (type: Sound)
-Function 524: IsSoundReady() (1 input parameters)
+Function 523: IsSoundReady() (1 input parameters)
Name: IsSoundReady
Return type: bool
Description: Checks if a sound is ready
Param[1]: sound (type: Sound)
-Function 525: UpdateSound() (3 input parameters)
+Function 524: UpdateSound() (3 input parameters)
Name: UpdateSound
Return type: void
Description: Update sound buffer with new data
Param[1]: sound (type: Sound)
Param[2]: data (type: const void *)
Param[3]: sampleCount (type: int)
-Function 526: UnloadWave() (1 input parameters)
+Function 525: UnloadWave() (1 input parameters)
Name: UnloadWave
Return type: void
Description: Unload wave data
Param[1]: wave (type: Wave)
-Function 527: UnloadSound() (1 input parameters)
+Function 526: UnloadSound() (1 input parameters)
Name: UnloadSound
Return type: void
Description: Unload sound
Param[1]: sound (type: Sound)
-Function 528: UnloadSoundAlias() (1 input parameters)
+Function 527: UnloadSoundAlias() (1 input parameters)
Name: UnloadSoundAlias
Return type: void
Description: Unload a sound alias (does not deallocate sample data)
Param[1]: alias (type: Sound)
-Function 529: ExportWave() (2 input parameters)
+Function 528: ExportWave() (2 input parameters)
Name: ExportWave
Return type: bool
Description: Export wave data to file, returns true on success
Param[1]: wave (type: Wave)
Param[2]: fileName (type: const char *)
-Function 530: ExportWaveAsCode() (2 input parameters)
+Function 529: ExportWaveAsCode() (2 input parameters)
Name: ExportWaveAsCode
Return type: bool
Description: Export wave sample data to code (.h), returns true on success
Param[1]: wave (type: Wave)
Param[2]: fileName (type: const char *)
-Function 531: PlaySound() (1 input parameters)
+Function 530: PlaySound() (1 input parameters)
Name: PlaySound
Return type: void
Description: Play a sound
Param[1]: sound (type: Sound)
-Function 532: StopSound() (1 input parameters)
+Function 531: StopSound() (1 input parameters)
Name: StopSound
Return type: void
Description: Stop playing a sound
Param[1]: sound (type: Sound)
-Function 533: PauseSound() (1 input parameters)
+Function 532: PauseSound() (1 input parameters)
Name: PauseSound
Return type: void
Description: Pause a sound
Param[1]: sound (type: Sound)
-Function 534: ResumeSound() (1 input parameters)
+Function 533: ResumeSound() (1 input parameters)
Name: ResumeSound
Return type: void
Description: Resume a paused sound
Param[1]: sound (type: Sound)
-Function 535: IsSoundPlaying() (1 input parameters)
+Function 534: IsSoundPlaying() (1 input parameters)
Name: IsSoundPlaying
Return type: bool
Description: Check if a sound is currently playing
Param[1]: sound (type: Sound)
-Function 536: SetSoundVolume() (2 input parameters)
+Function 535: SetSoundVolume() (2 input parameters)
Name: SetSoundVolume
Return type: void
Description: Set volume for a sound (1.0 is max level)
Param[1]: sound (type: Sound)
Param[2]: volume (type: float)
-Function 537: SetSoundPitch() (2 input parameters)
+Function 536: SetSoundPitch() (2 input parameters)
Name: SetSoundPitch
Return type: void
Description: Set pitch for a sound (1.0 is base level)
Param[1]: sound (type: Sound)
Param[2]: pitch (type: float)
-Function 538: SetSoundPan() (2 input parameters)
+Function 537: SetSoundPan() (2 input parameters)
Name: SetSoundPan
Return type: void
Description: Set pan for a sound (0.5 is center)
Param[1]: sound (type: Sound)
Param[2]: pan (type: float)
-Function 539: WaveCopy() (1 input parameters)
+Function 538: WaveCopy() (1 input parameters)
Name: WaveCopy
Return type: Wave
Description: Copy a wave to a new wave
Param[1]: wave (type: Wave)
-Function 540: WaveCrop() (3 input parameters)
+Function 539: WaveCrop() (3 input parameters)
Name: WaveCrop
Return type: void
Description: Crop a wave to defined frames range
Param[1]: wave (type: Wave *)
Param[2]: initFrame (type: int)
Param[3]: finalFrame (type: int)
-Function 541: WaveFormat() (4 input parameters)
+Function 540: WaveFormat() (4 input parameters)
Name: WaveFormat
Return type: void
Description: Convert wave data to desired format
@@ -4451,203 +4444,203 @@ Function 541: WaveFormat() (4 input parameters)
Param[2]: sampleRate (type: int)
Param[3]: sampleSize (type: int)
Param[4]: channels (type: int)
-Function 542: LoadWaveSamples() (1 input parameters)
+Function 541: LoadWaveSamples() (1 input parameters)
Name: LoadWaveSamples
Return type: float *
Description: Load samples data from wave as a 32bit float data array
Param[1]: wave (type: Wave)
-Function 543: UnloadWaveSamples() (1 input parameters)
+Function 542: UnloadWaveSamples() (1 input parameters)
Name: UnloadWaveSamples
Return type: void
Description: Unload samples data loaded with LoadWaveSamples()
Param[1]: samples (type: float *)
-Function 544: LoadMusicStream() (1 input parameters)
+Function 543: LoadMusicStream() (1 input parameters)
Name: LoadMusicStream
Return type: Music
Description: Load music stream from file
Param[1]: fileName (type: const char *)
-Function 545: LoadMusicStreamFromMemory() (3 input parameters)
+Function 544: LoadMusicStreamFromMemory() (3 input parameters)
Name: LoadMusicStreamFromMemory
Return type: Music
Description: Load music stream from data
Param[1]: fileType (type: const char *)
Param[2]: data (type: const unsigned char *)
Param[3]: dataSize (type: int)
-Function 546: IsMusicReady() (1 input parameters)
+Function 545: IsMusicReady() (1 input parameters)
Name: IsMusicReady
Return type: bool
Description: Checks if a music stream is ready
Param[1]: music (type: Music)
-Function 547: UnloadMusicStream() (1 input parameters)
+Function 546: UnloadMusicStream() (1 input parameters)
Name: UnloadMusicStream
Return type: void
Description: Unload music stream
Param[1]: music (type: Music)
-Function 548: PlayMusicStream() (1 input parameters)
+Function 547: PlayMusicStream() (1 input parameters)
Name: PlayMusicStream
Return type: void
Description: Start music playing
Param[1]: music (type: Music)
-Function 549: IsMusicStreamPlaying() (1 input parameters)
+Function 548: IsMusicStreamPlaying() (1 input parameters)
Name: IsMusicStreamPlaying
Return type: bool
Description: Check if music is playing
Param[1]: music (type: Music)
-Function 550: UpdateMusicStream() (1 input parameters)
+Function 549: UpdateMusicStream() (1 input parameters)
Name: UpdateMusicStream
Return type: void
Description: Updates buffers for music streaming
Param[1]: music (type: Music)
-Function 551: StopMusicStream() (1 input parameters)
+Function 550: StopMusicStream() (1 input parameters)
Name: StopMusicStream
Return type: void
Description: Stop music playing
Param[1]: music (type: Music)
-Function 552: PauseMusicStream() (1 input parameters)
+Function 551: PauseMusicStream() (1 input parameters)
Name: PauseMusicStream
Return type: void
Description: Pause music playing
Param[1]: music (type: Music)
-Function 553: ResumeMusicStream() (1 input parameters)
+Function 552: ResumeMusicStream() (1 input parameters)
Name: ResumeMusicStream
Return type: void
Description: Resume playing paused music
Param[1]: music (type: Music)
-Function 554: SeekMusicStream() (2 input parameters)
+Function 553: SeekMusicStream() (2 input parameters)
Name: SeekMusicStream
Return type: void
Description: Seek music to a position (in seconds)
Param[1]: music (type: Music)
Param[2]: position (type: float)
-Function 555: SetMusicVolume() (2 input parameters)
+Function 554: SetMusicVolume() (2 input parameters)
Name: SetMusicVolume
Return type: void
Description: Set volume for music (1.0 is max level)
Param[1]: music (type: Music)
Param[2]: volume (type: float)
-Function 556: SetMusicPitch() (2 input parameters)
+Function 555: SetMusicPitch() (2 input parameters)
Name: SetMusicPitch
Return type: void
Description: Set pitch for a music (1.0 is base level)
Param[1]: music (type: Music)
Param[2]: pitch (type: float)
-Function 557: SetMusicPan() (2 input parameters)
+Function 556: SetMusicPan() (2 input parameters)
Name: SetMusicPan
Return type: void
Description: Set pan for a music (0.5 is center)
Param[1]: music (type: Music)
Param[2]: pan (type: float)
-Function 558: GetMusicTimeLength() (1 input parameters)
+Function 557: GetMusicTimeLength() (1 input parameters)
Name: GetMusicTimeLength
Return type: float
Description: Get music time length (in seconds)
Param[1]: music (type: Music)
-Function 559: GetMusicTimePlayed() (1 input parameters)
+Function 558: GetMusicTimePlayed() (1 input parameters)
Name: GetMusicTimePlayed
Return type: float
Description: Get current music time played (in seconds)
Param[1]: music (type: Music)
-Function 560: LoadAudioStream() (3 input parameters)
+Function 559: LoadAudioStream() (3 input parameters)
Name: LoadAudioStream
Return type: AudioStream
Description: Load audio stream (to stream raw audio pcm data)
Param[1]: sampleRate (type: unsigned int)
Param[2]: sampleSize (type: unsigned int)
Param[3]: channels (type: unsigned int)
-Function 561: IsAudioStreamReady() (1 input parameters)
+Function 560: IsAudioStreamReady() (1 input parameters)
Name: IsAudioStreamReady
Return type: bool
Description: Checks if an audio stream is ready
Param[1]: stream (type: AudioStream)
-Function 562: UnloadAudioStream() (1 input parameters)
+Function 561: UnloadAudioStream() (1 input parameters)
Name: UnloadAudioStream
Return type: void
Description: Unload audio stream and free memory
Param[1]: stream (type: AudioStream)
-Function 563: UpdateAudioStream() (3 input parameters)
+Function 562: UpdateAudioStream() (3 input parameters)
Name: UpdateAudioStream
Return type: void
Description: Update audio stream buffers with data
Param[1]: stream (type: AudioStream)
Param[2]: data (type: const void *)
Param[3]: frameCount (type: int)
-Function 564: IsAudioStreamProcessed() (1 input parameters)
+Function 563: IsAudioStreamProcessed() (1 input parameters)
Name: IsAudioStreamProcessed
Return type: bool
Description: Check if any audio stream buffers requires refill
Param[1]: stream (type: AudioStream)
-Function 565: PlayAudioStream() (1 input parameters)
+Function 564: PlayAudioStream() (1 input parameters)
Name: PlayAudioStream
Return type: void
Description: Play audio stream
Param[1]: stream (type: AudioStream)
-Function 566: PauseAudioStream() (1 input parameters)
+Function 565: PauseAudioStream() (1 input parameters)
Name: PauseAudioStream
Return type: void
Description: Pause audio stream
Param[1]: stream (type: AudioStream)
-Function 567: ResumeAudioStream() (1 input parameters)
+Function 566: ResumeAudioStream() (1 input parameters)
Name: ResumeAudioStream
Return type: void
Description: Resume audio stream
Param[1]: stream (type: AudioStream)
-Function 568: IsAudioStreamPlaying() (1 input parameters)
+Function 567: IsAudioStreamPlaying() (1 input parameters)
Name: IsAudioStreamPlaying
Return type: bool
Description: Check if audio stream is playing
Param[1]: stream (type: AudioStream)
-Function 569: StopAudioStream() (1 input parameters)
+Function 568: StopAudioStream() (1 input parameters)
Name: StopAudioStream
Return type: void
Description: Stop audio stream
Param[1]: stream (type: AudioStream)
-Function 570: SetAudioStreamVolume() (2 input parameters)
+Function 569: SetAudioStreamVolume() (2 input parameters)
Name: SetAudioStreamVolume
Return type: void
Description: Set volume for audio stream (1.0 is max level)
Param[1]: stream (type: AudioStream)
Param[2]: volume (type: float)
-Function 571: SetAudioStreamPitch() (2 input parameters)
+Function 570: SetAudioStreamPitch() (2 input parameters)
Name: SetAudioStreamPitch
Return type: void
Description: Set pitch for audio stream (1.0 is base level)
Param[1]: stream (type: AudioStream)
Param[2]: pitch (type: float)
-Function 572: SetAudioStreamPan() (2 input parameters)
+Function 571: SetAudioStreamPan() (2 input parameters)
Name: SetAudioStreamPan
Return type: void
Description: Set pan for audio stream (0.5 is centered)
Param[1]: stream (type: AudioStream)
Param[2]: pan (type: float)
-Function 573: SetAudioStreamBufferSizeDefault() (1 input parameters)
+Function 572: SetAudioStreamBufferSizeDefault() (1 input parameters)
Name: SetAudioStreamBufferSizeDefault
Return type: void
Description: Default size for new audio streams
Param[1]: size (type: int)
-Function 574: SetAudioStreamCallback() (2 input parameters)
+Function 573: SetAudioStreamCallback() (2 input parameters)
Name: SetAudioStreamCallback
Return type: void
Description: Audio thread callback to request new data
Param[1]: stream (type: AudioStream)
Param[2]: callback (type: AudioCallback)
-Function 575: AttachAudioStreamProcessor() (2 input parameters)
+Function 574: AttachAudioStreamProcessor() (2 input parameters)
Name: AttachAudioStreamProcessor
Return type: void
Description: Attach audio stream processor to stream, receives the samples as 'float'
Param[1]: stream (type: AudioStream)
Param[2]: processor (type: AudioCallback)
-Function 576: DetachAudioStreamProcessor() (2 input parameters)
+Function 575: DetachAudioStreamProcessor() (2 input parameters)
Name: DetachAudioStreamProcessor
Return type: void
Description: Detach audio stream processor from stream
Param[1]: stream (type: AudioStream)
Param[2]: processor (type: AudioCallback)
-Function 577: AttachAudioMixedProcessor() (1 input parameters)
+Function 576: AttachAudioMixedProcessor() (1 input parameters)
Name: AttachAudioMixedProcessor
Return type: void
Description: Attach audio stream processor to the entire audio pipeline, receives the samples as 'float'
Param[1]: processor (type: AudioCallback)
-Function 578: DetachAudioMixedProcessor() (1 input parameters)
+Function 577: DetachAudioMixedProcessor() (1 input parameters)
Name: DetachAudioMixedProcessor
Return type: void
Description: Detach audio stream processor from the entire audio pipeline
diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml
index 895680f2c..73ce0dae7 100644
--- a/parser/output/raylib_api.xml
+++ b/parser/output/raylib_api.xml
@@ -675,7 +675,7 @@
-
+
@@ -1699,11 +1699,6 @@
-
-
-
-
-
diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln
index 2b262bcfe..1dbd38984 100644
--- a/projects/VS2022/raylib.sln
+++ b/projects/VS2022/raylib.sln
@@ -293,8 +293,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_texture_outline", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_texture_tiling", "examples\shaders_texture_tiling.vcxproj", "{EFA150D4-F93B-4D7D-A69C-9E8B4663BECD}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_svg_loading", "examples\textures_svg_loading.vcxproj", "{D8026C60-CCBC-45DF-9085-BF21569EB414}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_splines_drawing", "examples\shapes_splines_drawing.vcxproj", "{DF25E545-00FF-4E64-844C-7DF98991F901}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_top_down_lights", "examples\shapes_top_down_lights.vcxproj", "{703BE7BA-5B99-4F70-806D-3A259F6A991E}"
diff --git a/src/Makefile b/src/Makefile
index 4740f1f01..137c28b53 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -109,8 +109,9 @@ RAYLIB_MODULE_RAYGUI_PATH ?= $(RAYLIB_SRC_PATH)/../../raygui/src
# Use external GLFW library instead of rglfw module
USE_EXTERNAL_GLFW ?= FALSE
-# Enable support for both Wayland and X11 by default on Linux when using GLFW
-GLFW_LINUX_ENABLE_WAYLAND ?= TRUE
+# Enable support for X11 by default on Linux when using GLFW
+# NOTE: Wayland is disabled by default, only enable if you are sure
+GLFW_LINUX_ENABLE_WAYLAND ?= FALSE
GLFW_LINUX_ENABLE_X11 ?= TRUE
# PLATFORM_DESKTOP_SDL: It requires SDL library to be provided externally
diff --git a/src/build.zig b/src/build.zig
index 4e112d78f..2a8b88262 100644
--- a/src/build.zig
+++ b/src/build.zig
@@ -1,8 +1,14 @@
const std = @import("std");
const builtin = @import("builtin");
+/// Minimum supported version of Zig
+const min_ver = "0.12.0";
+
comptime {
- if (builtin.zig_version.minor < 12) @compileError("Raylib requires zig version 0.12.0");
+ const order = std.SemanticVersion.order;
+ const parse = std.SemanticVersion.parse;
+ if (order(builtin.zig_version, parse(min_ver) catch unreachable) == .lt)
+ @compileError("Raylib requires zig version " ++ min_ver);
}
// NOTE(freakmangd): I don't like using a global here, but it prevents having to
@@ -24,7 +30,7 @@ pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
.rshapes = options.rshapes,
.rtext = options.rtext,
.rtextures = options.rtextures,
- .platform_drm = options.platform_drm,
+ .platform = options.platform,
.shared = options.shared,
.linux_display_backend = options.linux_display_backend,
.opengl_version = options.opengl_version,
@@ -40,6 +46,32 @@ pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
return raylib;
}
+fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void {
+ raylib.defineCMacro("PLATFORM_DESKTOP", null);
+
+ switch (platform) {
+ .glfw => raylib.defineCMacro("PLATFORM_DESKTOP_GLFW", null),
+ .rgfw => raylib.defineCMacro("PLATFORM_DESKTOP_RGFW", null),
+ .sdl => raylib.defineCMacro("PLATFORM_DESKTOP_SDL", null),
+ else => {},
+ }
+}
+
+/// TODO: Once the minimum supported version is bumped to 0.14.0, it can be simplified again:
+/// https://github.com/raysan5/raylib/pull/4375#issuecomment-2408998315
+/// https://github.com/raysan5/raylib/blob/9b9c72eb0dc705cde194b053a366a40396acfb67/src/build.zig#L54-L56
+fn srcDir(b: *std.Build) []const u8 {
+ comptime {
+ const order = std.SemanticVersion.order;
+ const parse = std.SemanticVersion.parse;
+ if (order(parse(min_ver) catch unreachable, parse("0.14.0") catch unreachable) != .lt)
+ @compileError("Please take a look at this function again");
+ }
+
+ const src_file = std.fs.path.relative(b.allocator, @src().file, ".") catch @panic("OOM");
+ return std.fs.path.dirname(src_file) orelse ".";
+}
+
fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile {
raylib_flags_arr.clearRetainingCapacity();
@@ -53,9 +85,8 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
"-DGL_SILENCE_DEPRECATION=199309L",
"-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674
});
- if (options.config) |config| {
- const file = try std.fs.path.join(b.allocator, &.{ std.fs.path.dirname(@src().file) orelse ".", "config.h" });
- defer b.allocator.free(file);
+ if (options.config.len > 0) {
+ const file = b.pathJoin(&.{ srcDir(b), "config.h" });
const content = try std.fs.cwd().readFileAlloc(b.allocator, file, std.math.maxInt(usize));
defer b.allocator.free(content);
@@ -63,22 +94,23 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
while (lines.next()) |line| {
if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue;
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
flag = flag["#define ".len - 1 ..]; // Remove #define
flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace
- flag = flag[0..std.mem.indexOf(u8, flag, " ").?]; // Flag is only one word, so capture till space
+ flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space
flag = try std.fmt.allocPrint(b.allocator, "-D{s}", .{flag}); // Prepend with -D
// If user specifies the flag skip it
- if (std.mem.containsAtLeast(u8, config, 1, flag)) continue;
+ if (std.mem.containsAtLeast(u8, options.config, 1, flag)) continue;
// Append default value from config.h to compile flags
try raylib_flags_arr.append(b.allocator, flag);
}
// Append config flags supplied by user to compile flags
- try raylib_flags_arr.append(b.allocator, config);
+ try raylib_flags_arr.append(b.allocator, options.config);
try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
}
@@ -102,8 +134,8 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
raylib.linkLibC();
// No GLFW required on PLATFORM_DRM
- if (!options.platform_drm) {
- raylib.addIncludePath(b.path("src/external/glfw/include"));
+ if (options.platform != .drm) {
+ raylib.addIncludePath(b.path(b.pathJoin(&.{ srcDir(b), "external/glfw/include" })));
}
var c_source_files = try std.ArrayList([]const u8).initCapacity(b.allocator, 2);
@@ -136,10 +168,10 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
raylib.linkSystemLibrary("gdi32");
raylib.linkSystemLibrary("opengl32");
- raylib.defineCMacro("PLATFORM_DESKTOP", null);
+ setDesktopPlatform(raylib, options.platform);
},
.linux => {
- if (!options.platform_drm) {
+ if (options.platform != .drm) {
try c_source_files.append("rglfw.c");
raylib.linkSystemLibrary("GL");
raylib.linkSystemLibrary("rt");
@@ -156,17 +188,16 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) {
_ = b.findProgram(&.{"wayland-scanner"}, &.{}) catch {
std.log.err(
- \\ Wayland may not be installed on the system.
+ \\ `wayland-scanner` may not be installed on the system.
\\ You can switch to X11 in your `build.zig` by changing `Options.linux_display_backend`
, .{});
- @panic("No Wayland");
+ @panic("`wayland-scanner` not found");
};
raylib.defineCMacro("_GLFW_WAYLAND", null);
raylib.linkSystemLibrary("wayland-client");
raylib.linkSystemLibrary("wayland-cursor");
raylib.linkSystemLibrary("wayland-egl");
raylib.linkSystemLibrary("xkbcommon");
- raylib.addIncludePath(b.path("src"));
waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol");
waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol");
waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol");
@@ -177,7 +208,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
waylandGenerate(b, raylib, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol");
waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol");
}
- raylib.defineCMacro("PLATFORM_DESKTOP", null);
+ setDesktopPlatform(raylib, options.platform);
} else {
if (options.opengl_version == .auto) {
raylib.linkSystemLibrary("GLESv2");
@@ -211,13 +242,13 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
raylib.linkSystemLibrary("Xxf86vm");
raylib.linkSystemLibrary("Xcursor");
- raylib.defineCMacro("PLATFORM_DESKTOP", null);
+ setDesktopPlatform(raylib, options.platform);
},
.macos => {
// On macos rglfw.c include Objective-C files.
try raylib_flags_arr.append(b.allocator, "-ObjC");
raylib.root_module.addCSourceFile(.{
- .file = b.path("src/rglfw.c"),
+ .file = b.path(b.pathJoin(&.{ srcDir(b), "rglfw.c" })),
.flags = raylib_flags_arr.items,
});
_ = raylib_flags_arr.pop();
@@ -227,7 +258,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
raylib.linkFramework("AppKit");
raylib.linkFramework("IOKit");
- raylib.defineCMacro("PLATFORM_DESKTOP", null);
+ setDesktopPlatform(raylib, options.platform);
},
.emscripten => {
raylib.defineCMacro("PLATFORM_WEB", null);
@@ -239,8 +270,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
@panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'");
}
- const cache_include = std.fs.path.join(b.allocator, &.{ b.sysroot.?, "cache", "sysroot", "include" }) catch @panic("Out of memory");
- defer b.allocator.free(cache_include);
+ const cache_include = b.pathJoin(&.{ b.sysroot.?, "cache", "sysroot", "include" });
var dir = std.fs.openDirAbsolute(cache_include, std.fs.Dir.OpenDirOptions{ .access_sub_paths = true, .no_follow = true }) catch @panic("No emscripten cache. Generate it!");
dir.close();
@@ -251,9 +281,8 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
},
}
- raylib.addIncludePath(b.path("src"));
raylib.root_module.addCSourceFiles(.{
- .root = b.path("src"),
+ .root = b.path(srcDir(b)),
.files = c_source_files.items,
.flags = raylib_flags_arr.items,
});
@@ -286,11 +315,12 @@ pub const Options = struct {
rtext: bool = true,
rtextures: bool = true,
raygui: bool = false,
- platform_drm: bool = false,
+ platform: PlatformBackend = .glfw,
shared: bool = false,
linux_display_backend: LinuxDisplayBackend = .Both,
opengl_version: OpenglVersion = .auto,
- config: ?[]const u8 = null,
+ /// config should be a list of cflags, eg, "-DSUPPORT_CUSTOM_FRAME_CONTROL"
+ config: []const u8 = &.{},
raygui_dependency_name: []const u8 = "raygui",
};
@@ -323,6 +353,13 @@ pub const LinuxDisplayBackend = enum {
Both,
};
+pub const PlatformBackend = enum {
+ glfw,
+ rgfw,
+ sdl,
+ drm,
+};
+
pub fn build(b: *std.Build) !void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
@@ -336,8 +373,9 @@ pub fn build(b: *std.Build) !void {
const defaults = Options{};
const options = Options{
- .platform_drm = b.option(bool, "platform_drm", "Compile raylib in native mode (no X11)") orelse defaults.platform_drm,
+ .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform,
.raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio,
+ .raygui = b.option(bool, "raygui", "Compile with raygui support") orelse defaults.raygui,
.rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels,
.rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext,
.rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures,
@@ -345,22 +383,26 @@ pub fn build(b: *std.Build) !void {
.shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared,
.linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend,
.opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version,
- .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse null,
+ .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{},
};
const lib = try compileRaylib(b, target, optimize, options);
- lib.installHeader(b.path("src/raylib.h"), "raylib.h");
- lib.installHeader(b.path("src/raymath.h"), "raymath.h");
- lib.installHeader(b.path("src/rlgl.h"), "rlgl.h");
+ lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "raylib.h" })), "raylib.h");
+ lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "raymath.h" })), "raymath.h");
+ lib.installHeader(b.path(b.pathJoin(&.{ srcDir(b), "rlgl.h" })), "rlgl.h");
b.installArtifact(lib);
}
-const waylandDir = "src/external/glfw/deps/wayland";
-
-fn waylandGenerate(b: *std.Build, raylib: *std.Build.Step.Compile, comptime protocol: []const u8, comptime basename: []const u8) void {
- const protocolDir = waylandDir ++ "/" ++ protocol;
+fn waylandGenerate(
+ b: *std.Build,
+ raylib: *std.Build.Step.Compile,
+ comptime protocol: []const u8,
+ comptime basename: []const u8,
+) void {
+ const waylandDir = b.pathJoin(&.{ srcDir(b), "external/glfw/deps/wayland" });
+ const protocolDir = b.pathJoin(&.{ waylandDir, protocol });
const clientHeader = basename ++ ".h";
const privateCode = basename ++ "-code.h";
diff --git a/src/config.h b/src/config.h
index 8bba37606..9123a2291 100644
--- a/src/config.h
+++ b/src/config.h
@@ -121,12 +121,10 @@
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6
-// The mac OpenGL drivers do not support more than 8 VBOs, so we can't support GPU animations
-#ifndef __APPLE__
-#define RL_SUPPORT_MESH_ANIMATION_VBO
-#endif
-#ifdef RL_SUPPORT_MESH_ANIMATION_VBO
+#define RL_SUPPORT_MESH_GPU_SKINNING // Remove this if your GPU does not support more than 8 VBOs
+
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
#endif
@@ -182,7 +180,6 @@
//#define SUPPORT_FILEFORMAT_ASTC 1
//#define SUPPORT_FILEFORMAT_PKM 1
//#define SUPPORT_FILEFORMAT_PVR 1
-//#define SUPPORT_FILEFORMAT_SVG 1
// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi)
#define SUPPORT_IMAGE_EXPORT 1
@@ -237,7 +234,12 @@
// rmodels: Configuration values
//------------------------------------------------------------------------------------
#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported
+
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
#define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh
+#else
+#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
+#endif
//------------------------------------------------------------------------------------
// Module: raudio - Configuration Flags
diff --git a/src/external/RGFW.h b/src/external/RGFW.h
index 35e782d4a..fb389d5b4 100644
--- a/src/external/RGFW.h
+++ b/src/external/RGFW.h
@@ -192,7 +192,7 @@
typedef u32 b32;
#endif
-#define RGFW_TRUE 1
+#define RGFW_TRUE (!(0))
#define RGFW_FALSE 0
/* thse OS macros looks better & are standardized */
@@ -276,11 +276,6 @@
#endif
#ifdef RGFW_EGL
- #if defined(__APPLE__)
- #warning EGL is not supported for Cocoa, switching back to the native opengl api
- #undef RGFW_EGL
- #endif
-
#include
#elif defined(RGFW_OSMESA)
#ifndef __APPLE__
@@ -611,10 +606,17 @@ typedef struct RGFW_window {
/** * @defgroup Window_management
* @{ */
+
+/*!
+ * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM
+ * by default the class name will == the root window's name
+*/
+RGFWDEF void RGFW_setClassName(char* name);
+
/*! this has to be set before createWindow is called, else the fulscreen size is used */
RGFWDEF void RGFW_setBufferSize(RGFW_area size); /*!< the buffer cannot be resized (by RGFW) */
-RGFW_window* RGFW_createWindow(
+RGFWDEF RGFW_window* RGFW_createWindow(
const char* name, /* name of the window */
RGFW_rect rect, /* rect of window */
u16 args /* extra arguments (NULL / (u16)0 means no args used)*/
@@ -635,7 +637,7 @@ RGFWDEF RGFW_area RGFW_getScreenSize(void);
although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents`
*/
-RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/
+RGFWDEF RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/
/*!
for RGFW_window_eventWait and RGFW_window_checkEvents
@@ -706,7 +708,7 @@ RGFWDEF void RGFW_window_setName(RGFW_window* win,
char* name
);
-void RGFW_window_setIcon(RGFW_window* win, /*!< source window */
+RGFWDEF void RGFW_window_setIcon(RGFW_window* win, /*!< source window */
u8* icon /*!< icon bitmap */,
RGFW_area a /*!< width and height of the bitmap*/,
i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */
@@ -1609,9 +1611,6 @@ RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) {
if (args & RGFW_FULLSCREEN)
rect = RGFW_RECT(0, 0, screenR.w, screenR.h);
- if (args & RGFW_CENTER)
- rect = RGFW_RECT((screenR.w - rect.w) / 2, (screenR.h - rect.h) / 2, rect.w, rect.h);
-
/* set and init the new window's data */
win->r = rect;
win->event.inFocus = 1;
@@ -1627,7 +1626,7 @@ RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) {
void RGFW_window_scaleToMonitor(RGFW_window* win) {
RGFW_monitor monitor = RGFW_window_getMonitor(win);
- RGFW_window_resize(win, RGFW_AREA(((u32) monitor.scaleX) * win->r.w, ((u32) monitor.scaleX) * win->r.h));
+ RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleX * (float)win->r.h)));
}
#endif
@@ -1637,6 +1636,16 @@ RGFW_window* RGFW_root = NULL;
#define RGFW_HOLD_MOUSE (1L<<2) /*!< hold the moues still */
#define RGFW_MOUSE_LEFT (1L<<3) /* if mouse left the window */
+#ifdef RGFW_MACOS
+RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer);
+RGFWDEF void* RGFW_cocoaGetLayer(void);
+#endif
+
+char* RGFW_className = NULL;
+void RGFW_setClassName(char* name) {
+ RGFW_className = name;
+}
+
void RGFW_clipboardFree(char* str) { RGFW_FREE(str); }
RGFW_keyState RGFW_mouseButtons[5] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} };
@@ -2073,6 +2082,8 @@ void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) {
#ifdef RGFW_WINDOWS
win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc);
+ #elif defined(RGFW_MACOS)
+ win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0);
#else
win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
#endif
@@ -2104,8 +2115,15 @@ void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) {
EGLint numConfigs;
eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs);
-
- win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
+ #if defined(RGFW_MACOS)
+ void* layer = RGFW_cocoaGetLayer();
+
+ RGFW_window_cocoaSetLayer(win, layer);
+
+ win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL);
+ #else
+ win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
+ #endif
EGLint attribs[] = {
EGL_CONTEXT_CLIENT_VERSION,
@@ -2322,7 +2340,7 @@ Start of Linux / Unix defines
u8 RGFW_mouseIconSrc[] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor};
/*atoms needed for drag and drop*/
- Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XdndActionMove, XdndActionLink, XdndActionAsk, XdndActionPrivate;
+ Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XtextPlain, XtextUriList;
Atom wm_delete_window = 0;
@@ -2563,9 +2581,13 @@ Start of Linux / Unix defines
// In your .desktop app, if you set the property
// StartupWMClass=RGFW that will assoicate the launcher icon
// with your application - robrohan
+
+ if (RGFW_className == NULL)
+ RGFW_className = (char*)name;
+
XClassHint *hint = XAllocClassHint();
assert(hint != NULL);
- hint->res_class = (char*)"RGFW";
+ hint->res_class = (char*)RGFW_className;
hint->res_name = (char*)name; // just use the window name as the app name
XSetClassHint((Display*) win->src.display, win->src.window, hint);
XFree(hint);
@@ -2609,6 +2631,11 @@ Start of Linux / Unix defines
RGFW_window_scaleToMonitor(win);
#endif
+ if (args & RGFW_CENTER) {
+ RGFW_area screenR = RGFW_getScreenSize();
+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
+ }
+
if (args & RGFW_NO_RESIZE) { /* make it so the user can't resize the window*/
XSizeHints* sh = XAllocSizeHints();
sh->flags = (1L << 4) | (1L << 5);
@@ -2646,7 +2673,6 @@ Start of Linux / Unix defines
if (args & RGFW_ALLOW_DND) { /* init drag and drop atoms and turn on drag and drop for this window */
win->_winArgs |= RGFW_ALLOW_DND;
- XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False);
XdndTypeList = XInternAtom((Display*) win->src.display, "XdndTypeList", False);
XdndSelection = XInternAtom((Display*) win->src.display, "XdndSelection", False);
@@ -2660,15 +2686,16 @@ Start of Linux / Unix defines
/* actions */
XdndActionCopy = XInternAtom((Display*) win->src.display, "XdndActionCopy", False);
- XdndActionMove = XInternAtom((Display*) win->src.display, "XdndActionMove", False);
- XdndActionLink = XInternAtom((Display*) win->src.display, "XdndActionLink", False);
- XdndActionAsk = XInternAtom((Display*) win->src.display, "XdndActionAsk", False);
- XdndActionPrivate = XInternAtom((Display*) win->src.display, "XdndActionPrivate", False);
- const Atom version = 5;
+
+ XtextUriList = XInternAtom((Display*) win->src.display, "text/uri-list", False);
+ XtextPlain = XInternAtom((Display*) win->src.display, "text/plain", False);
+
+ XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False);
+ const u8 version = 5;
XChangeProperty((Display*) win->src.display, (Window) win->src.window,
XdndAware, 4, 32,
- PropModeReplace, (u8*) &version, 1); /*!< turns on drag and drop */
+ PropModeReplace, &version, 1); /*!< turns on drag and drop */
}
#ifdef RGFW_EGL
@@ -2716,17 +2743,16 @@ Start of Linux / Unix defines
return RGFWMouse;
}
- typedef struct XDND {
- long source, version;
- i32 format;
- } XDND; /*!< data structure for xdnd events */
- XDND xdnd;
-
int xAxis = 0, yAxis = 0;
RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
assert(win != NULL);
+ static struct {
+ long source, version;
+ i32 format;
+ } xdnd;
+
if (win->event.type == 0)
RGFW_resetKey();
@@ -2893,13 +2919,16 @@ Start of Linux / Unix defines
win->event.droppedFilesCount = 0;
- /*
- much of this event (drag and drop code) is source from glfw
- */
-
if ((win->_winArgs & RGFW_ALLOW_DND) == 0)
break;
+ XEvent reply = { ClientMessage };
+ reply.xclient.window = xdnd.source;
+ reply.xclient.format = 32;
+ reply.xclient.data.l[0] = (long) win->src.window;
+ reply.xclient.data.l[1] = 0;
+ reply.xclient.data.l[2] = None;
+
if (E.xclient.message_type == XdndEnter) {
unsigned long count;
Atom* formats;
@@ -2944,28 +2973,11 @@ Start of Linux / Unix defines
formats = real_formats;
}
- u32 i;
- for (i = 0; i < (u32)count; i++) {
- char* name = XGetAtomName((Display*) win->src.display, formats[i]);
-
- char* links[2] = { (char*) (const char*) "text/uri-list", (char*) (const char*) "text/plain" };
- for (; 1; name++) {
- u32 j;
- for (j = 0; j < 2; j++) {
- if (*links[j] != *name) {
- links[j] = (char*) (const char*) "\1";
- continue;
- }
-
- if (*links[j] == '\0' && *name == '\0')
- xdnd.format = formats[i];
-
- if (*links[j] != '\0' && *links[j] != '\1')
- links[j]++;
- }
-
- if (*name == '\0')
- break;
+ unsigned long i;
+ for (i = 0; i < count; i++) {
+ if (formats[i] == XtextUriList || formats[i] == XtextPlain) {
+ xdnd.format = formats[i];
+ break;
}
}
@@ -2994,13 +3006,8 @@ Start of Linux / Unix defines
win->event.point.x = xpos;
win->event.point.y = ypos;
- XEvent reply = { ClientMessage };
reply.xclient.window = xdnd.source;
reply.xclient.message_type = XdndStatus;
- reply.xclient.format = 32;
- reply.xclient.data.l[0] = (long) win->src.window;
- reply.xclient.data.l[2] = 0;
- reply.xclient.data.l[3] = 0;
if (xdnd.format) {
reply.xclient.data.l[1] = 1;
@@ -3035,12 +3042,6 @@ Start of Linux / Unix defines
time);
} else if (xdnd.version >= 2) {
XEvent reply = { ClientMessage };
- reply.xclient.window = xdnd.source;
- reply.xclient.message_type = XdndFinished;
- reply.xclient.format = 32;
- reply.xclient.data.l[0] = (long) win->src.window;
- reply.xclient.data.l[1] = 0;
- reply.xclient.data.l[2] = None;
XSendEvent((Display*) win->src.display, xdnd.source,
False, NoEventMask, &reply);
@@ -3125,11 +3126,7 @@ Start of Linux / Unix defines
XFree(data);
if (xdnd.version >= 2) {
- XEvent reply = { ClientMessage };
- reply.xclient.window = xdnd.source;
reply.xclient.message_type = XdndFinished;
- reply.xclient.format = 32;
- reply.xclient.data.l[0] = (long) win->src.window;
reply.xclient.data.l[1] = result;
reply.xclient.data.l[2] = XdndActionCopy;
@@ -3480,7 +3477,7 @@ Start of Linux / Unix defines
*size = sizeN;
return s;
- }
+ }
/*
almost all of this function is sourced from GLFW
@@ -3520,9 +3517,6 @@ Start of Linux / Unix defines
XEvent reply = { SelectionNotify };
reply.xselection.property = 0;
- const Atom formats[] = { UTF8_STRING, XA_STRING };
- const i32 formatCount = sizeof(formats) / sizeof(formats[0]);
-
if (request->target == TARGETS) {
const Atom targets[] = { TARGETS,
MULTIPLE,
@@ -3552,15 +3546,7 @@ Start of Linux / Unix defines
unsigned long i;
for (i = 0; i < (u32)count; i += 2) {
- i32 j;
-
- for (j = 0; j < formatCount; j++) {
- if (targets[i] == formats[j])
- break;
- }
-
- if (j < formatCount)
- {
+ if (targets[i] == UTF8_STRING || targets[i] == XA_STRING) {
XChangeProperty((Display*) RGFW_root->src.display,
request->requestor,
targets[i + 1],
@@ -3727,32 +3713,54 @@ Start of Linux / Unix defines
RGFW_monitor monitor;
Display* display = XOpenDisplay(NULL);
+
+ RGFW_area size = RGFW_getScreenSize();
- monitor.rect = RGFW_RECT(0, 0, DisplayWidth(display, screen), DisplayHeight(display, screen));
- monitor.physW = (monitor.rect.w * 25.4f / 96.f);
- monitor.physH = (monitor.rect.h * 25.4f / 96.f);
-
- strncpy(monitor.name, DisplayString(display), 128);
-
+ monitor.rect = RGFW_RECT(0, 0, size.w, size.h);
+ monitor.physW = DisplayWidthMM(display, screen);
+ monitor.physH = DisplayHeightMM(display, screen);
+
XGetSystemContentScale(display, &monitor.scaleX, &monitor.scaleY);
-
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen));
XRRCrtcInfo* ci = NULL;
- int crtc = 0;
+ int crtc = screen;
if (sr->ncrtc > crtc) {
ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]);
}
-
+
if (ci == NULL) {
+ float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4));
+ float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4));
+
+ monitor.scaleX = (float) (dpi_width) / (float) 96;
+ monitor.scaleY = (float) (dpi_height) / (float) 96;
XRRFreeScreenResources(sr);
XCloseDisplay(display);
return monitor;
}
+
+ XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]);
+ monitor.physW = info->mm_width;
+ monitor.physH = info->mm_height;
monitor.rect.x = ci->x;
monitor.rect.y = ci->y;
+ monitor.rect.w = ci->width;
+ monitor.rect.h = ci->height;
+
+ float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4));
+ float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4));
+
+ monitor.scaleX = (float) (dpi_width) / (float) 96;
+ monitor.scaleY = (float) (dpi_height) / (float) 96;
+
+ if (monitor.scaleX > 1 && monitor.scaleX < 1.1)
+ monitor.scaleX = 1;
+
+ if (monitor.scaleY > 1 && monitor.scaleY < 1.1)
+ monitor.scaleY = 1;
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
@@ -4150,9 +4158,6 @@ RGFW_Event RGFW_eventPipe_pop(RGFW_window* win) {
if (win->src.eventLen >= 0)
ev = win->src.events[win->src.eventLen];
- else {
- printf("H2\n");
- }
return ev;
}
@@ -4675,6 +4680,10 @@ static const struct wl_callback_listener wl_surface_frame_listener = {
decoration_manager, win->src.xdg_toplevel);
}
+ if (args & RGFW_CENTER) {
+ RGFW_area screenR = RGFW_getScreenSize();
+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
+ }
if (args & RGFW_OPENGL_SOFTWARE)
setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
@@ -4999,9 +5008,7 @@ static const struct wl_callback_listener wl_surface_frame_listener = {
#define WIN32_LEAN_AND_MEAN
#define OEMRESOURCE
#include
-
- __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar);
-
+
#include
#include
#include
@@ -5009,6 +5016,10 @@ static const struct wl_callback_listener wl_surface_frame_listener = {
#include
#include
+ #include
+
+ __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar);
+
#ifndef RGFW_NO_XINPUT
typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
PFN_XInputGetState XInputGetStateSRC = NULL;
@@ -5226,14 +5237,15 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
}
void RGFW_releaseCursor(RGFW_window* win) {
+ RGFW_UNUSED(win);
ClipCursor(NULL);
const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL };
RegisterRawInputDevices(&id, 1, sizeof(id));
}
void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) {
- RGFW_UNUSED(win)
-
+ RGFW_UNUSED(win); RGFW_UNUSED(rect);
+
RECT clipRect;
GetClientRect(win->src.window, &clipRect);
ClientToScreen(win->src.window, (POINT*) &clipRect.left);
@@ -5254,6 +5266,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
if (RGFW_Shcore_dll == NULL) {
RGFW_Shcore_dll = LoadLibraryA("shcore.dll");
GetDpiForMonitorSRC = (PFN_GetDpiForMonitor)(void*)GetProcAddress(RGFW_Shcore_dll, "GetDpiForMonitor");
+ SetProcessDPIAware();
}
#endif
@@ -5288,7 +5301,10 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
WNDCLASSA Class = { };
#endif
- Class.lpszClassName = name;
+ if (RGFW_className == NULL)
+ RGFW_className = (char*)name;
+
+ Class.lpszClassName = RGFW_className;
Class.hInstance = inh;
Class.hCursor = LoadCursor(NULL, IDC_ARROW);
Class.lpfnWndProc = WndProc;
@@ -5501,6 +5517,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
if (args & RGFW_SCALE_TO_MONITOR)
RGFW_window_scaleToMonitor(win);
#endif
+
+ if (args & RGFW_CENTER) {
+ RGFW_area screenR = RGFW_getScreenSize();
+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
+ }
#ifdef RGFW_EGL
if ((args & RGFW_NO_INIT_API) == 0)
@@ -6102,7 +6123,8 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
if (GetDpiForMonitor != NULL) {
u32 x, y;
- GetDpiForMonitor(src, MDT_ANGULAR_DPI, &x, &y);
+ GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y);
+
monitor.scaleX = (float) (x) / (float) USER_DEFAULT_SCREEN_DPI;
monitor.scaleY = (float) (y) / (float) USER_DEFAULT_SCREEN_DPI;
}
@@ -6117,7 +6139,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
/* Calculate physical height in inches */
monitor.physW = GetSystemMetrics(SM_CYSCREEN) / (float) ppiX;
monitor.physH = GetSystemMetrics(SM_CXSCREEN) / (float) ppiY;
-
+
return monitor;
}
#endif /* RGFW_NO_MONITOR */
@@ -6152,7 +6174,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
RGFW_mInfo info;
info.iIndex = 0;
while (EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info));
-
+
return RGFW_monitors;
}
@@ -7104,7 +7126,6 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
for (int i = 0; i < count; i++) {
id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
- // printf("File: %s\n", filePath);
strncpy(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH);
win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
}
@@ -7208,6 +7229,16 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
#endif
}
+
+ void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) {
+ objc_msgSend_void_id(win->src.view, sel_registerName("setLayer"), layer);
+ }
+
+ void* RGFW_cocoaGetLayer(void) {
+ return objc_msgSend_class(objc_getClass("CAMetalLayer"), sel_registerName("layer"));
+ }
+
+
NSPasteboardType const NSPasteboardTypeURL = "public.url";
NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url";
@@ -7263,6 +7294,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
NSString* str = NSString_stringWithUTF8String(name);
objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str);
+#ifdef RGFW_EGL
+ if ((args & RGFW_NO_INIT_API) == 0)
+ RGFW_createOpenGLContext(win);
+#endif
+
#ifdef RGFW_OPENGL
if ((args & RGFW_NO_INIT_API) == 0) {
void* attrs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE);
@@ -7329,6 +7365,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
RGFW_window_scaleToMonitor(win);
#endif
+ if (args & RGFW_CENTER) {
+ RGFW_area screenR = RGFW_getScreenSize();
+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
+ }
+
if (args & RGFW_HIDE_MOUSE)
RGFW_window_showMouse(win, 0);
@@ -7935,6 +7976,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
}
void RGFW_releaseCursor(RGFW_window* win) {
+ RGFW_UNUSED(win);
CGAssociateMouseAndMouseCursorPosition(1);
}
@@ -7994,13 +8036,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
monitor.rect = RGFW_RECT((int) bounds.origin.x, (int) bounds.origin.y, (int) bounds.size.width, (int) bounds.size.height);
CGSize screenSizeMM = CGDisplayScreenSize(display);
- monitor.physW = screenSizeMM.width / 25.4;
- monitor.physH = screenSizeMM.height / 25.4;
+ monitor.physW = screenSizeMM.width;
+ monitor.physH = screenSizeMM.height;
- monitor.scaleX = (monitor.rect.w / (screenSizeMM.width)) / 2.6;
- monitor.scaleY = (monitor.rect.h / (screenSizeMM.height)) / 2.6;
-
- snprintf(monitor.name, 128, "%i %i %i", CGDisplayModelNumber(display), CGDisplayVendorNumber(display), CGDisplaySerialNumber(display));
+ monitor.scaleX = ((monitor.rect.w / (screenSizeMM.width / 25.4)) / 96) + 0.25;
+ monitor.scaleY = ((monitor.rect.h / (screenSizeMM.height / 25.4)) / 96) + 0.25;
return monitor;
}
@@ -8090,6 +8130,8 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
#if defined(RGFW_OPENGL)
NSOpenGLContext_setValues(win->src.ctx, &swapInterval, 222);
+ #else
+ RGFW_UNUSED(swapInterval);
#endif
}
#endif
@@ -8532,7 +8574,7 @@ RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
emscripten_webgl_make_context_current(win->src.ctx);
#ifdef LEGACY_GL_EMULATION
- EM_ASM("Module.useWebGL = true; GLImmediate.init();");
+ EM_ASM("Module.useWebGL = true; GLImmediate.init();");
#endif
emscripten_set_canvas_element_size("#canvas", rect.w, rect.h);
@@ -8875,11 +8917,12 @@ u64 RGFW_getTime(void) {
}
void RGFW_releaseCursor(RGFW_window* win) {
+ RGFW_UNUSED(win);
emscripten_exit_pointerlock();
}
void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
- RGFW_UNUSED(win)
+ RGFW_UNUSED(win); RGFW_UNUSED(r);
emscripten_request_pointerlock("#canvas", 1);
}
diff --git a/src/external/nanosvg.h b/src/external/nanosvg.h
deleted file mode 100644
index b80f540ba..000000000
--- a/src/external/nanosvg.h
+++ /dev/null
@@ -1,3053 +0,0 @@
-/*
- * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- *
- * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example
- * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/)
- *
- * Arc calculation code based on canvg (https://code.google.com/p/canvg/)
- *
- * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
- *
- */
-
-#ifndef NANOSVG_H
-#define NANOSVG_H
-
-#ifndef NANOSVG_CPLUSPLUS
-#ifdef __cplusplus
-extern "C" {
-#endif
-#endif
-
-// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
-//
-// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game.
-//
-// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request!
-//
-// The shapes in the SVG images are transformed by the viewBox and converted to specified units.
-// That is, you should get the same looking data as your designed in your favorite app.
-//
-// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
-// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
-//
-// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
-// DPI (dots-per-inch) controls how the unit conversion is done.
-//
-// If you don't know or care about the units stuff, "px" and 96 should get you going.
-
-
-/* Example Usage:
- // Load SVG
- NSVGimage* image;
- image = nsvgParseFromFile("test.svg", "px", 96);
- printf("size: %f x %f\n", image->width, image->height);
- // Use...
- for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) {
- for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {
- for (int i = 0; i < path->npts-1; i += 3) {
- float* p = &path->pts[i*2];
- drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
- }
- }
- }
- // Delete
- nsvgDelete(image);
-*/
-
-enum NSVGpaintType {
- NSVG_PAINT_NONE = 0,
- NSVG_PAINT_COLOR = 1,
- NSVG_PAINT_LINEAR_GRADIENT = 2,
- NSVG_PAINT_RADIAL_GRADIENT = 3
-};
-
-enum NSVGspreadType {
- NSVG_SPREAD_PAD = 0,
- NSVG_SPREAD_REFLECT = 1,
- NSVG_SPREAD_REPEAT = 2
-};
-
-enum NSVGlineJoin {
- NSVG_JOIN_MITER = 0,
- NSVG_JOIN_ROUND = 1,
- NSVG_JOIN_BEVEL = 2
-};
-
-enum NSVGlineCap {
- NSVG_CAP_BUTT = 0,
- NSVG_CAP_ROUND = 1,
- NSVG_CAP_SQUARE = 2
-};
-
-enum NSVGfillRule {
- NSVG_FILLRULE_NONZERO = 0,
- NSVG_FILLRULE_EVENODD = 1
-};
-
-enum NSVGflags {
- NSVG_FLAGS_VISIBLE = 0x01
-};
-
-typedef struct NSVGgradientStop {
- unsigned int color;
- float offset;
-} NSVGgradientStop;
-
-typedef struct NSVGgradient {
- float xform[6];
- char spread;
- float fx, fy;
- int nstops;
- NSVGgradientStop stops[1];
-} NSVGgradient;
-
-typedef struct NSVGpaint {
- char type;
- union {
- unsigned int color;
- NSVGgradient* gradient;
- };
-} NSVGpaint;
-
-typedef struct NSVGpath
-{
- float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
- int npts; // Total number of bezier points.
- char closed; // Flag indicating if shapes should be treated as closed.
- float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
- struct NSVGpath* next; // Pointer to next path, or NULL if last element.
-} NSVGpath;
-
-typedef struct NSVGshape
-{
- char id[64]; // Optional 'id' attr of the shape or its group
- NSVGpaint fill; // Fill paint
- NSVGpaint stroke; // Stroke paint
- float opacity; // Opacity of the shape.
- float strokeWidth; // Stroke width (scaled).
- float strokeDashOffset; // Stroke dash offset (scaled).
- float strokeDashArray[8]; // Stroke dash array (scaled).
- char strokeDashCount; // Number of dash values in dash array.
- char strokeLineJoin; // Stroke join type.
- char strokeLineCap; // Stroke cap type.
- float miterLimit; // Miter limit
- char fillRule; // Fill rule, see NSVGfillRule.
- unsigned char flags; // Logical or of NSVG_FLAGS_* flags
- float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
- NSVGpath* paths; // Linked list of paths in the image.
- struct NSVGshape* next; // Pointer to next shape, or NULL if last element.
-} NSVGshape;
-
-typedef struct NSVGimage
-{
- float width; // Width of the image.
- float height; // Height of the image.
- NSVGshape* shapes; // Linked list of shapes in the image.
-} NSVGimage;
-
-// Parses SVG file from a file, returns SVG image as paths.
-NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi);
-
-// Parses SVG file from a null terminated string, returns SVG image as paths.
-// Important note: changes the string.
-NSVGimage* nsvgParse(char* input, const char* units, float dpi);
-
-// Duplicates a path.
-NSVGpath* nsvgDuplicatePath(NSVGpath* p);
-
-// Deletes an image.
-void nsvgDelete(NSVGimage* image);
-
-#ifndef NANOSVG_CPLUSPLUS
-#ifdef __cplusplus
-}
-#endif
-#endif
-
-#ifdef NANOSVG_IMPLEMENTATION
-
-#include
-#include
-#include
-#include
-
-#define NSVG_PI (3.14159265358979323846264338327f)
-#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs.
-
-#define NSVG_ALIGN_MIN 0
-#define NSVG_ALIGN_MID 1
-#define NSVG_ALIGN_MAX 2
-#define NSVG_ALIGN_NONE 0
-#define NSVG_ALIGN_MEET 1
-#define NSVG_ALIGN_SLICE 2
-
-#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0)
-#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16))
-
-#ifdef _MSC_VER
- #pragma warning (disable: 4996) // Switch off security warnings
- #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings
- #ifdef __cplusplus
- #define NSVG_INLINE inline
- #else
- #define NSVG_INLINE
- #endif
-#else
- #define NSVG_INLINE inline
-#endif
-
-
-static int nsvg__isspace(char c)
-{
- return strchr(" \t\n\v\f\r", c) != 0;
-}
-
-static int nsvg__isdigit(char c)
-{
- return c >= '0' && c <= '9';
-}
-
-static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; }
-static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; }
-
-
-// Simple XML parser
-
-#define NSVG_XML_TAG 1
-#define NSVG_XML_CONTENT 2
-#define NSVG_XML_MAX_ATTRIBS 256
-
-static void nsvg__parseContent(char* s,
- void (*contentCb)(void* ud, const char* s),
- void* ud)
-{
- // Trim start white spaces
- while (*s && nsvg__isspace(*s)) s++;
- if (!*s) return;
-
- if (contentCb)
- (*contentCb)(ud, s);
-}
-
-static void nsvg__parseElement(char* s,
- void (*startelCb)(void* ud, const char* el, const char** attr),
- void (*endelCb)(void* ud, const char* el),
- void* ud)
-{
- const char* attr[NSVG_XML_MAX_ATTRIBS];
- int nattr = 0;
- char* name;
- int start = 0;
- int end = 0;
- char quote;
-
- // Skip white space after the '<'
- while (*s && nsvg__isspace(*s)) s++;
-
- // Check if the tag is end tag
- if (*s == '/') {
- s++;
- end = 1;
- } else {
- start = 1;
- }
-
- // Skip comments, data and preprocessor stuff.
- if (!*s || *s == '?' || *s == '!')
- return;
-
- // Get tag name
- name = s;
- while (*s && !nsvg__isspace(*s)) s++;
- if (*s) { *s++ = '\0'; }
-
- // Get attribs
- while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
- char* name = NULL;
- char* value = NULL;
-
- // Skip white space before the attrib name
- while (*s && nsvg__isspace(*s)) s++;
- if (!*s) break;
- if (*s == '/') {
- end = 1;
- break;
- }
- name = s;
- // Find end of the attrib name.
- while (*s && !nsvg__isspace(*s) && *s != '=') s++;
- if (*s) { *s++ = '\0'; }
- // Skip until the beginning of the value.
- while (*s && *s != '\"' && *s != '\'') s++;
- if (!*s) break;
- quote = *s;
- s++;
- // Store value and find the end of it.
- value = s;
- while (*s && *s != quote) s++;
- if (*s) { *s++ = '\0'; }
-
- // Store only well formed attributes
- if (name && value) {
- attr[nattr++] = name;
- attr[nattr++] = value;
- }
- }
-
- // List terminator
- attr[nattr++] = 0;
- attr[nattr++] = 0;
-
- // Call callbacks.
- if (start && startelCb)
- (*startelCb)(ud, name, attr);
- if (end && endelCb)
- (*endelCb)(ud, name);
-}
-
-int nsvg__parseXML(char* input,
- void (*startelCb)(void* ud, const char* el, const char** attr),
- void (*endelCb)(void* ud, const char* el),
- void (*contentCb)(void* ud, const char* s),
- void* ud)
-{
- char* s = input;
- char* mark = s;
- int state = NSVG_XML_CONTENT;
- while (*s) {
- if (*s == '<' && state == NSVG_XML_CONTENT) {
- // Start of a tag
- *s++ = '\0';
- nsvg__parseContent(mark, contentCb, ud);
- mark = s;
- state = NSVG_XML_TAG;
- } else if (*s == '>' && state == NSVG_XML_TAG) {
- // Start of a content or new tag.
- *s++ = '\0';
- nsvg__parseElement(mark, startelCb, endelCb, ud);
- mark = s;
- state = NSVG_XML_CONTENT;
- } else {
- s++;
- }
- }
-
- return 1;
-}
-
-
-/* Simple SVG parser. */
-
-#define NSVG_MAX_ATTR 128
-
-enum NSVGgradientUnits {
- NSVG_USER_SPACE = 0,
- NSVG_OBJECT_SPACE = 1
-};
-
-#define NSVG_MAX_DASHES 8
-
-enum NSVGunits {
- NSVG_UNITS_USER,
- NSVG_UNITS_PX,
- NSVG_UNITS_PT,
- NSVG_UNITS_PC,
- NSVG_UNITS_MM,
- NSVG_UNITS_CM,
- NSVG_UNITS_IN,
- NSVG_UNITS_PERCENT,
- NSVG_UNITS_EM,
- NSVG_UNITS_EX
-};
-
-typedef struct NSVGcoordinate {
- float value;
- int units;
-} NSVGcoordinate;
-
-typedef struct NSVGlinearData {
- NSVGcoordinate x1, y1, x2, y2;
-} NSVGlinearData;
-
-typedef struct NSVGradialData {
- NSVGcoordinate cx, cy, r, fx, fy;
-} NSVGradialData;
-
-typedef struct NSVGgradientData
-{
- char id[64];
- char ref[64];
- char type;
- union {
- NSVGlinearData linear;
- NSVGradialData radial;
- };
- char spread;
- char units;
- float xform[6];
- int nstops;
- NSVGgradientStop* stops;
- struct NSVGgradientData* next;
-} NSVGgradientData;
-
-typedef struct NSVGattrib
-{
- char id[64];
- float xform[6];
- unsigned int fillColor;
- unsigned int strokeColor;
- float opacity;
- float fillOpacity;
- float strokeOpacity;
- char fillGradient[64];
- char strokeGradient[64];
- float strokeWidth;
- float strokeDashOffset;
- float strokeDashArray[NSVG_MAX_DASHES];
- int strokeDashCount;
- char strokeLineJoin;
- char strokeLineCap;
- float miterLimit;
- char fillRule;
- float fontSize;
- unsigned int stopColor;
- float stopOpacity;
- float stopOffset;
- char hasFill;
- char hasStroke;
- char visible;
-} NSVGattrib;
-
-typedef struct NSVGparser
-{
- NSVGattrib attr[NSVG_MAX_ATTR];
- int attrHead;
- float* pts;
- int npts;
- int cpts;
- NSVGpath* plist;
- NSVGimage* image;
- NSVGgradientData* gradients;
- NSVGshape* shapesTail;
- float viewMinx, viewMiny, viewWidth, viewHeight;
- int alignX, alignY, alignType;
- float dpi;
- char pathFlag;
- char defsFlag;
-} NSVGparser;
-
-static void nsvg__xformIdentity(float* t)
-{
- t[0] = 1.0f; t[1] = 0.0f;
- t[2] = 0.0f; t[3] = 1.0f;
- t[4] = 0.0f; t[5] = 0.0f;
-}
-
-static void nsvg__xformSetTranslation(float* t, float tx, float ty)
-{
- t[0] = 1.0f; t[1] = 0.0f;
- t[2] = 0.0f; t[3] = 1.0f;
- t[4] = tx; t[5] = ty;
-}
-
-static void nsvg__xformSetScale(float* t, float sx, float sy)
-{
- t[0] = sx; t[1] = 0.0f;
- t[2] = 0.0f; t[3] = sy;
- t[4] = 0.0f; t[5] = 0.0f;
-}
-
-static void nsvg__xformSetSkewX(float* t, float a)
-{
- t[0] = 1.0f; t[1] = 0.0f;
- t[2] = tanf(a); t[3] = 1.0f;
- t[4] = 0.0f; t[5] = 0.0f;
-}
-
-static void nsvg__xformSetSkewY(float* t, float a)
-{
- t[0] = 1.0f; t[1] = tanf(a);
- t[2] = 0.0f; t[3] = 1.0f;
- t[4] = 0.0f; t[5] = 0.0f;
-}
-
-static void nsvg__xformSetRotation(float* t, float a)
-{
- float cs = cosf(a), sn = sinf(a);
- t[0] = cs; t[1] = sn;
- t[2] = -sn; t[3] = cs;
- t[4] = 0.0f; t[5] = 0.0f;
-}
-
-static void nsvg__xformMultiply(float* t, float* s)
-{
- float t0 = t[0] * s[0] + t[1] * s[2];
- float t2 = t[2] * s[0] + t[3] * s[2];
- float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
- t[1] = t[0] * s[1] + t[1] * s[3];
- t[3] = t[2] * s[1] + t[3] * s[3];
- t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
- t[0] = t0;
- t[2] = t2;
- t[4] = t4;
-}
-
-static void nsvg__xformInverse(float* inv, float* t)
-{
- double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1];
- if (det > -1e-6 && det < 1e-6) {
- nsvg__xformIdentity(t);
- return;
- }
- invdet = 1.0 / det;
- inv[0] = (float)(t[3] * invdet);
- inv[2] = (float)(-t[2] * invdet);
- inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);
- inv[1] = (float)(-t[1] * invdet);
- inv[3] = (float)(t[0] * invdet);
- inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);
-}
-
-static void nsvg__xformPremultiply(float* t, float* s)
-{
- float s2[6];
- memcpy(s2, s, sizeof(float)*6);
- nsvg__xformMultiply(s2, t);
- memcpy(t, s2, sizeof(float)*6);
-}
-
-static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t)
-{
- *dx = x*t[0] + y*t[2] + t[4];
- *dy = x*t[1] + y*t[3] + t[5];
-}
-
-static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t)
-{
- *dx = x*t[0] + y*t[2];
- *dy = x*t[1] + y*t[3];
-}
-
-#define NSVG_EPSILON (1e-12)
-
-static int nsvg__ptInBounds(float* pt, float* bounds)
-{
- return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3];
-}
-
-
-static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3)
-{
- double it = 1.0-t;
- return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3;
-}
-
-static void nsvg__curveBounds(float* bounds, float* curve)
-{
- int i, j, count;
- double roots[2], a, b, c, b2ac, t, v;
- float* v0 = &curve[0];
- float* v1 = &curve[2];
- float* v2 = &curve[4];
- float* v3 = &curve[6];
-
- // Start the bounding box by end points
- bounds[0] = nsvg__minf(v0[0], v3[0]);
- bounds[1] = nsvg__minf(v0[1], v3[1]);
- bounds[2] = nsvg__maxf(v0[0], v3[0]);
- bounds[3] = nsvg__maxf(v0[1], v3[1]);
-
- // Bezier curve fits inside the convex hull of it's control points.
- // If control points are inside the bounds, we're done.
- if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds))
- return;
-
- // Add bezier curve inflection points in X and Y.
- for (i = 0; i < 2; i++) {
- a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i];
- b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i];
- c = 3.0 * v1[i] - 3.0 * v0[i];
- count = 0;
- if (fabs(a) < NSVG_EPSILON) {
- if (fabs(b) > NSVG_EPSILON) {
- t = -c / b;
- if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
- roots[count++] = t;
- }
- } else {
- b2ac = b*b - 4.0*c*a;
- if (b2ac > NSVG_EPSILON) {
- t = (-b + sqrt(b2ac)) / (2.0 * a);
- if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
- roots[count++] = t;
- t = (-b - sqrt(b2ac)) / (2.0 * a);
- if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
- roots[count++] = t;
- }
- }
- for (j = 0; j < count; j++) {
- v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]);
- bounds[0+i] = nsvg__minf(bounds[0+i], (float)v);
- bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v);
- }
- }
-}
-
-static NSVGparser* nsvg__createParser(void)
-{
- NSVGparser* p;
- p = (NSVGparser*)malloc(sizeof(NSVGparser));
- if (p == NULL) goto error;
- memset(p, 0, sizeof(NSVGparser));
-
- p->image = (NSVGimage*)malloc(sizeof(NSVGimage));
- if (p->image == NULL) goto error;
- memset(p->image, 0, sizeof(NSVGimage));
-
- // Init style
- nsvg__xformIdentity(p->attr[0].xform);
- memset(p->attr[0].id, 0, sizeof p->attr[0].id);
- p->attr[0].fillColor = NSVG_RGB(0,0,0);
- p->attr[0].strokeColor = NSVG_RGB(0,0,0);
- p->attr[0].opacity = 1;
- p->attr[0].fillOpacity = 1;
- p->attr[0].strokeOpacity = 1;
- p->attr[0].stopOpacity = 1;
- p->attr[0].strokeWidth = 1;
- p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
- p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
- p->attr[0].miterLimit = 4;
- p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
- p->attr[0].hasFill = 1;
- p->attr[0].visible = 1;
-
- return p;
-
-error:
- if (p) {
- if (p->image) free(p->image);
- free(p);
- }
- return NULL;
-}
-
-static void nsvg__deletePaths(NSVGpath* path)
-{
- while (path) {
- NSVGpath *next = path->next;
- if (path->pts != NULL)
- free(path->pts);
- free(path);
- path = next;
- }
-}
-
-static void nsvg__deletePaint(NSVGpaint* paint)
-{
- if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT)
- free(paint->gradient);
-}
-
-static void nsvg__deleteGradientData(NSVGgradientData* grad)
-{
- NSVGgradientData* next;
- while (grad != NULL) {
- next = grad->next;
- free(grad->stops);
- free(grad);
- grad = next;
- }
-}
-
-static void nsvg__deleteParser(NSVGparser* p)
-{
- if (p != NULL) {
- nsvg__deletePaths(p->plist);
- nsvg__deleteGradientData(p->gradients);
- nsvgDelete(p->image);
- free(p->pts);
- free(p);
- }
-}
-
-static void nsvg__resetPath(NSVGparser* p)
-{
- p->npts = 0;
-}
-
-static void nsvg__addPoint(NSVGparser* p, float x, float y)
-{
- if (p->npts+1 > p->cpts) {
- p->cpts = p->cpts ? p->cpts*2 : 8;
- p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float));
- if (!p->pts) return;
- }
- p->pts[p->npts*2+0] = x;
- p->pts[p->npts*2+1] = y;
- p->npts++;
-}
-
-static void nsvg__moveTo(NSVGparser* p, float x, float y)
-{
- if (p->npts > 0) {
- p->pts[(p->npts-1)*2+0] = x;
- p->pts[(p->npts-1)*2+1] = y;
- } else {
- nsvg__addPoint(p, x, y);
- }
-}
-
-static void nsvg__lineTo(NSVGparser* p, float x, float y)
-{
- float px,py, dx,dy;
- if (p->npts > 0) {
- px = p->pts[(p->npts-1)*2+0];
- py = p->pts[(p->npts-1)*2+1];
- dx = x - px;
- dy = y - py;
- nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f);
- nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f);
- nsvg__addPoint(p, x, y);
- }
-}
-
-static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)
-{
- if (p->npts > 0) {
- nsvg__addPoint(p, cpx1, cpy1);
- nsvg__addPoint(p, cpx2, cpy2);
- nsvg__addPoint(p, x, y);
- }
-}
-
-static NSVGattrib* nsvg__getAttr(NSVGparser* p)
-{
- return &p->attr[p->attrHead];
-}
-
-static void nsvg__pushAttr(NSVGparser* p)
-{
- if (p->attrHead < NSVG_MAX_ATTR-1) {
- p->attrHead++;
- memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib));
- }
-}
-
-static void nsvg__popAttr(NSVGparser* p)
-{
- if (p->attrHead > 0)
- p->attrHead--;
-}
-
-static float nsvg__actualOrigX(NSVGparser* p)
-{
- return p->viewMinx;
-}
-
-static float nsvg__actualOrigY(NSVGparser* p)
-{
- return p->viewMiny;
-}
-
-static float nsvg__actualWidth(NSVGparser* p)
-{
- return p->viewWidth;
-}
-
-static float nsvg__actualHeight(NSVGparser* p)
-{
- return p->viewHeight;
-}
-
-static float nsvg__actualLength(NSVGparser* p)
-{
- float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p);
- return sqrtf(w*w + h*h) / sqrtf(2.0f);
-}
-
-static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length)
-{
- NSVGattrib* attr = nsvg__getAttr(p);
- switch (c.units) {
- case NSVG_UNITS_USER: return c.value;
- case NSVG_UNITS_PX: return c.value;
- case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi;
- case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi;
- case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi;
- case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi;
- case NSVG_UNITS_IN: return c.value * p->dpi;
- case NSVG_UNITS_EM: return c.value * attr->fontSize;
- case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica.
- case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length;
- default: return c.value;
- }
- return c.value;
-}
-
-static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
-{
- NSVGgradientData* grad = p->gradients;
- if (id == NULL || *id == '\0')
- return NULL;
- while (grad != NULL) {
- if (strcmp(grad->id, id) == 0)
- return grad;
- grad = grad->next;
- }
- return NULL;
-}
-
-static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType)
-{
- NSVGattrib* attr = nsvg__getAttr(p);
- NSVGgradientData* data = NULL;
- NSVGgradientData* ref = NULL;
- NSVGgradientStop* stops = NULL;
- NSVGgradient* grad;
- float ox, oy, sw, sh, sl;
- int nstops = 0;
- int refIter;
-
- data = nsvg__findGradientData(p, id);
- if (data == NULL) return NULL;
-
- // TODO: use ref to fill in all unset values too.
- ref = data;
- refIter = 0;
- while (ref != NULL) {
- NSVGgradientData* nextRef = NULL;
- if (stops == NULL && ref->stops != NULL) {
- stops = ref->stops;
- nstops = ref->nstops;
- break;
- }
- nextRef = nsvg__findGradientData(p, ref->ref);
- if (nextRef == ref) break; // prevent infite loops on malformed data
- ref = nextRef;
- refIter++;
- if (refIter > 32) break; // prevent infite loops on malformed data
- }
- if (stops == NULL) return NULL;
-
- grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1));
- if (grad == NULL) return NULL;
-
- // The shape width and height.
- if (data->units == NSVG_OBJECT_SPACE) {
- ox = localBounds[0];
- oy = localBounds[1];
- sw = localBounds[2] - localBounds[0];
- sh = localBounds[3] - localBounds[1];
- } else {
- ox = nsvg__actualOrigX(p);
- oy = nsvg__actualOrigY(p);
- sw = nsvg__actualWidth(p);
- sh = nsvg__actualHeight(p);
- }
- sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f);
-
- if (data->type == NSVG_PAINT_LINEAR_GRADIENT) {
- float x1, y1, x2, y2, dx, dy;
- x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw);
- y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh);
- x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw);
- y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh);
- // Calculate transform aligned to the line
- dx = x2 - x1;
- dy = y2 - y1;
- grad->xform[0] = dy; grad->xform[1] = -dx;
- grad->xform[2] = dx; grad->xform[3] = dy;
- grad->xform[4] = x1; grad->xform[5] = y1;
- } else {
- float cx, cy, fx, fy, r;
- cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw);
- cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh);
- fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw);
- fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh);
- r = nsvg__convertToPixels(p, data->radial.r, 0, sl);
- // Calculate transform aligned to the circle
- grad->xform[0] = r; grad->xform[1] = 0;
- grad->xform[2] = 0; grad->xform[3] = r;
- grad->xform[4] = cx; grad->xform[5] = cy;
- grad->fx = fx / r;
- grad->fy = fy / r;
- }
-
- nsvg__xformMultiply(grad->xform, data->xform);
- nsvg__xformMultiply(grad->xform, attr->xform);
-
- grad->spread = data->spread;
- memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop));
- grad->nstops = nstops;
-
- *paintType = data->type;
-
- return grad;
-}
-
-static float nsvg__getAverageScale(float* t)
-{
- float sx = sqrtf(t[0]*t[0] + t[2]*t[2]);
- float sy = sqrtf(t[1]*t[1] + t[3]*t[3]);
- return (sx + sy) * 0.5f;
-}
-
-static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform)
-{
- NSVGpath* path;
- float curve[4*2], curveBounds[4];
- int i, first = 1;
- for (path = shape->paths; path != NULL; path = path->next) {
- nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform);
- for (i = 0; i < path->npts-1; i += 3) {
- nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform);
- nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform);
- nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform);
- nsvg__curveBounds(curveBounds, curve);
- if (first) {
- bounds[0] = curveBounds[0];
- bounds[1] = curveBounds[1];
- bounds[2] = curveBounds[2];
- bounds[3] = curveBounds[3];
- first = 0;
- } else {
- bounds[0] = nsvg__minf(bounds[0], curveBounds[0]);
- bounds[1] = nsvg__minf(bounds[1], curveBounds[1]);
- bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]);
- bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]);
- }
- curve[0] = curve[6];
- curve[1] = curve[7];
- }
- }
-}
-
-static void nsvg__addShape(NSVGparser* p)
-{
- NSVGattrib* attr = nsvg__getAttr(p);
- float scale = 1.0f;
- NSVGshape* shape;
- NSVGpath* path;
- int i;
-
- if (p->plist == NULL)
- return;
-
- shape = (NSVGshape*)malloc(sizeof(NSVGshape));
- if (shape == NULL) goto error;
- memset(shape, 0, sizeof(NSVGshape));
-
- memcpy(shape->id, attr->id, sizeof shape->id);
- scale = nsvg__getAverageScale(attr->xform);
- shape->strokeWidth = attr->strokeWidth * scale;
- shape->strokeDashOffset = attr->strokeDashOffset * scale;
- shape->strokeDashCount = (char)attr->strokeDashCount;
- for (i = 0; i < attr->strokeDashCount; i++)
- shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
- shape->strokeLineJoin = attr->strokeLineJoin;
- shape->strokeLineCap = attr->strokeLineCap;
- shape->miterLimit = attr->miterLimit;
- shape->fillRule = attr->fillRule;
- shape->opacity = attr->opacity;
-
- shape->paths = p->plist;
- p->plist = NULL;
-
- // Calculate shape bounds
- shape->bounds[0] = shape->paths->bounds[0];
- shape->bounds[1] = shape->paths->bounds[1];
- shape->bounds[2] = shape->paths->bounds[2];
- shape->bounds[3] = shape->paths->bounds[3];
- for (path = shape->paths->next; path != NULL; path = path->next) {
- shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]);
- shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]);
- shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]);
- shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]);
- }
-
- // Set fill
- if (attr->hasFill == 0) {
- shape->fill.type = NSVG_PAINT_NONE;
- } else if (attr->hasFill == 1) {
- shape->fill.type = NSVG_PAINT_COLOR;
- shape->fill.color = attr->fillColor;
- shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24;
- } else if (attr->hasFill == 2) {
- float inv[6], localBounds[4];
- nsvg__xformInverse(inv, attr->xform);
- nsvg__getLocalBounds(localBounds, shape, inv);
- shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type);
- if (shape->fill.gradient == NULL) {
- shape->fill.type = NSVG_PAINT_NONE;
- }
- }
-
- // Set stroke
- if (attr->hasStroke == 0) {
- shape->stroke.type = NSVG_PAINT_NONE;
- } else if (attr->hasStroke == 1) {
- shape->stroke.type = NSVG_PAINT_COLOR;
- shape->stroke.color = attr->strokeColor;
- shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24;
- } else if (attr->hasStroke == 2) {
- float inv[6], localBounds[4];
- nsvg__xformInverse(inv, attr->xform);
- nsvg__getLocalBounds(localBounds, shape, inv);
- shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type);
- if (shape->stroke.gradient == NULL)
- shape->stroke.type = NSVG_PAINT_NONE;
- }
-
- // Set flags
- shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
-
- // Add to tail
- if (p->image->shapes == NULL)
- p->image->shapes = shape;
- else
- p->shapesTail->next = shape;
- p->shapesTail = shape;
-
- return;
-
-error:
- if (shape) free(shape);
-}
-
-static void nsvg__addPath(NSVGparser* p, char closed)
-{
- NSVGattrib* attr = nsvg__getAttr(p);
- NSVGpath* path = NULL;
- float bounds[4];
- float* curve;
- int i;
-
- if (p->npts < 4)
- return;
-
- if (closed)
- nsvg__lineTo(p, p->pts[0], p->pts[1]);
-
- // Expect 1 + N*3 points (N = number of cubic bezier segments).
- if ((p->npts % 3) != 1)
- return;
-
- path = (NSVGpath*)malloc(sizeof(NSVGpath));
- if (path == NULL) goto error;
- memset(path, 0, sizeof(NSVGpath));
-
- path->pts = (float*)malloc(p->npts*2*sizeof(float));
- if (path->pts == NULL) goto error;
- path->closed = closed;
- path->npts = p->npts;
-
- // Transform path.
- for (i = 0; i < p->npts; ++i)
- nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform);
-
- // Find bounds
- for (i = 0; i < path->npts-1; i += 3) {
- curve = &path->pts[i*2];
- nsvg__curveBounds(bounds, curve);
- if (i == 0) {
- path->bounds[0] = bounds[0];
- path->bounds[1] = bounds[1];
- path->bounds[2] = bounds[2];
- path->bounds[3] = bounds[3];
- } else {
- path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]);
- path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]);
- path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]);
- path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]);
- }
- }
-
- path->next = p->plist;
- p->plist = path;
-
- return;
-
-error:
- if (path != NULL) {
- if (path->pts != NULL) free(path->pts);
- free(path);
- }
-}
-
-// We roll our own string to float because the std library one uses locale and messes things up.
-static double nsvg__atof(const char* s)
-{
- char* cur = (char*)s;
- char* end = NULL;
- double res = 0.0, sign = 1.0;
- long long intPart = 0, fracPart = 0;
- char hasIntPart = 0, hasFracPart = 0;
-
- // Parse optional sign
- if (*cur == '+') {
- cur++;
- } else if (*cur == '-') {
- sign = -1;
- cur++;
- }
-
- // Parse integer part
- if (nsvg__isdigit(*cur)) {
- // Parse digit sequence
- intPart = strtoll(cur, &end, 10);
- if (cur != end) {
- res = (double)intPart;
- hasIntPart = 1;
- cur = end;
- }
- }
-
- // Parse fractional part.
- if (*cur == '.') {
- cur++; // Skip '.'
- if (nsvg__isdigit(*cur)) {
- // Parse digit sequence
- fracPart = strtoll(cur, &end, 10);
- if (cur != end) {
- res += (double)fracPart / pow(10.0, (double)(end - cur));
- hasFracPart = 1;
- cur = end;
- }
- }
- }
-
- // A valid number should have integer or fractional part.
- if (!hasIntPart && !hasFracPart)
- return 0.0;
-
- // Parse optional exponent
- if (*cur == 'e' || *cur == 'E') {
- long expPart = 0;
- cur++; // skip 'E'
- expPart = strtol(cur, &end, 10); // Parse digit sequence with sign
- if (cur != end) {
- res *= pow(10.0, (double)expPart);
- }
- }
-
- return res * sign;
-}
-
-
-static const char* nsvg__parseNumber(const char* s, char* it, const int size)
-{
- const int last = size-1;
- int i = 0;
-
- // sign
- if (*s == '-' || *s == '+') {
- if (i < last) it[i++] = *s;
- s++;
- }
- // integer part
- while (*s && nsvg__isdigit(*s)) {
- if (i < last) it[i++] = *s;
- s++;
- }
- if (*s == '.') {
- // decimal point
- if (i < last) it[i++] = *s;
- s++;
- // fraction part
- while (*s && nsvg__isdigit(*s)) {
- if (i < last) it[i++] = *s;
- s++;
- }
- }
- // exponent
- if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
- if (i < last) it[i++] = *s;
- s++;
- if (*s == '-' || *s == '+') {
- if (i < last) it[i++] = *s;
- s++;
- }
- while (*s && nsvg__isdigit(*s)) {
- if (i < last) it[i++] = *s;
- s++;
- }
- }
- it[i] = '\0';
-
- return s;
-}
-
-static const char* nsvg__getNextPathItem(const char* s, char* it)
-{
- it[0] = '\0';
- // Skip white spaces and commas
- while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
- if (!*s) return s;
- if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) {
- s = nsvg__parseNumber(s, it, 64);
- } else {
- // Parse command
- it[0] = *s++;
- it[1] = '\0';
- return s;
- }
-
- return s;
-}
-
-static unsigned int nsvg__parseColorHex(const char* str)
-{
- unsigned int r=0, g=0, b=0;
- if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex
- return NSVG_RGB(r, g, b);
- if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa
- return NSVG_RGB(r*17, g*17, b*17); // same effect as (r<<4|r), (g<<4|g), ..
- return NSVG_RGB(128, 128, 128);
-}
-
-// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters).
-// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors
-// for backwards compatibility. Note: other image viewers return black instead.
-
-static unsigned int nsvg__parseColorRGB(const char* str)
-{
- int i;
- unsigned int rgbi[3];
- float rgbf[3];
- // try decimal integers first
- if (sscanf(str, "rgb(%u, %u, %u)", &rgbi[0], &rgbi[1], &rgbi[2]) != 3) {
- // integers failed, try percent values (float, locale independent)
- const char delimiter[3] = {',', ',', ')'};
- str += 4; // skip "rgb("
- for (i = 0; i < 3; i++) {
- while (*str && (nsvg__isspace(*str))) str++; // skip leading spaces
- if (*str == '+') str++; // skip '+' (don't allow '-')
- if (!*str) break;
- rgbf[i] = nsvg__atof(str);
-
- // Note 1: it would be great if nsvg__atof() returned how many
- // bytes it consumed but it doesn't. We need to skip the number,
- // the '%' character, spaces, and the delimiter ',' or ')'.
-
- // Note 2: The following code does not allow values like "33.%",
- // i.e. a decimal point w/o fractional part, but this is consistent
- // with other image viewers, e.g. firefox, chrome, eog, gimp.
-
- while (*str && nsvg__isdigit(*str)) str++; // skip integer part
- if (*str == '.') {
- str++;
- if (!nsvg__isdigit(*str)) break; // error: no digit after '.'
- while (*str && nsvg__isdigit(*str)) str++; // skip fractional part
- }
- if (*str == '%') str++; else break;
- while (nsvg__isspace(*str)) str++;
- if (*str == delimiter[i]) str++;
- else break;
- }
- if (i == 3) {
- rgbi[0] = roundf(rgbf[0] * 2.55f);
- rgbi[1] = roundf(rgbf[1] * 2.55f);
- rgbi[2] = roundf(rgbf[2] * 2.55f);
- } else {
- rgbi[0] = rgbi[1] = rgbi[2] = 128;
- }
- }
- // clip values as the CSS spec requires
- for (i = 0; i < 3; i++) {
- if (rgbi[i] > 255) rgbi[i] = 255;
- }
- return NSVG_RGB(rgbi[0], rgbi[1], rgbi[2]);
-}
-
-typedef struct NSVGNamedColor {
- const char* name;
- unsigned int color;
-} NSVGNamedColor;
-
-NSVGNamedColor nsvg__colors[] = {
-
- { "red", NSVG_RGB(255, 0, 0) },
- { "green", NSVG_RGB( 0, 128, 0) },
- { "blue", NSVG_RGB( 0, 0, 255) },
- { "yellow", NSVG_RGB(255, 255, 0) },
- { "cyan", NSVG_RGB( 0, 255, 255) },
- { "magenta", NSVG_RGB(255, 0, 255) },
- { "black", NSVG_RGB( 0, 0, 0) },
- { "grey", NSVG_RGB(128, 128, 128) },
- { "gray", NSVG_RGB(128, 128, 128) },
- { "white", NSVG_RGB(255, 255, 255) },
-
-#ifdef NANOSVG_ALL_COLOR_KEYWORDS
- { "aliceblue", NSVG_RGB(240, 248, 255) },
- { "antiquewhite", NSVG_RGB(250, 235, 215) },
- { "aqua", NSVG_RGB( 0, 255, 255) },
- { "aquamarine", NSVG_RGB(127, 255, 212) },
- { "azure", NSVG_RGB(240, 255, 255) },
- { "beige", NSVG_RGB(245, 245, 220) },
- { "bisque", NSVG_RGB(255, 228, 196) },
- { "blanchedalmond", NSVG_RGB(255, 235, 205) },
- { "blueviolet", NSVG_RGB(138, 43, 226) },
- { "brown", NSVG_RGB(165, 42, 42) },
- { "burlywood", NSVG_RGB(222, 184, 135) },
- { "cadetblue", NSVG_RGB( 95, 158, 160) },
- { "chartreuse", NSVG_RGB(127, 255, 0) },
- { "chocolate", NSVG_RGB(210, 105, 30) },
- { "coral", NSVG_RGB(255, 127, 80) },
- { "cornflowerblue", NSVG_RGB(100, 149, 237) },
- { "cornsilk", NSVG_RGB(255, 248, 220) },
- { "crimson", NSVG_RGB(220, 20, 60) },
- { "darkblue", NSVG_RGB( 0, 0, 139) },
- { "darkcyan", NSVG_RGB( 0, 139, 139) },
- { "darkgoldenrod", NSVG_RGB(184, 134, 11) },
- { "darkgray", NSVG_RGB(169, 169, 169) },
- { "darkgreen", NSVG_RGB( 0, 100, 0) },
- { "darkgrey", NSVG_RGB(169, 169, 169) },
- { "darkkhaki", NSVG_RGB(189, 183, 107) },
- { "darkmagenta", NSVG_RGB(139, 0, 139) },
- { "darkolivegreen", NSVG_RGB( 85, 107, 47) },
- { "darkorange", NSVG_RGB(255, 140, 0) },
- { "darkorchid", NSVG_RGB(153, 50, 204) },
- { "darkred", NSVG_RGB(139, 0, 0) },
- { "darksalmon", NSVG_RGB(233, 150, 122) },
- { "darkseagreen", NSVG_RGB(143, 188, 143) },
- { "darkslateblue", NSVG_RGB( 72, 61, 139) },
- { "darkslategray", NSVG_RGB( 47, 79, 79) },
- { "darkslategrey", NSVG_RGB( 47, 79, 79) },
- { "darkturquoise", NSVG_RGB( 0, 206, 209) },
- { "darkviolet", NSVG_RGB(148, 0, 211) },
- { "deeppink", NSVG_RGB(255, 20, 147) },
- { "deepskyblue", NSVG_RGB( 0, 191, 255) },
- { "dimgray", NSVG_RGB(105, 105, 105) },
- { "dimgrey", NSVG_RGB(105, 105, 105) },
- { "dodgerblue", NSVG_RGB( 30, 144, 255) },
- { "firebrick", NSVG_RGB(178, 34, 34) },
- { "floralwhite", NSVG_RGB(255, 250, 240) },
- { "forestgreen", NSVG_RGB( 34, 139, 34) },
- { "fuchsia", NSVG_RGB(255, 0, 255) },
- { "gainsboro", NSVG_RGB(220, 220, 220) },
- { "ghostwhite", NSVG_RGB(248, 248, 255) },
- { "gold", NSVG_RGB(255, 215, 0) },
- { "goldenrod", NSVG_RGB(218, 165, 32) },
- { "greenyellow", NSVG_RGB(173, 255, 47) },
- { "honeydew", NSVG_RGB(240, 255, 240) },
- { "hotpink", NSVG_RGB(255, 105, 180) },
- { "indianred", NSVG_RGB(205, 92, 92) },
- { "indigo", NSVG_RGB( 75, 0, 130) },
- { "ivory", NSVG_RGB(255, 255, 240) },
- { "khaki", NSVG_RGB(240, 230, 140) },
- { "lavender", NSVG_RGB(230, 230, 250) },
- { "lavenderblush", NSVG_RGB(255, 240, 245) },
- { "lawngreen", NSVG_RGB(124, 252, 0) },
- { "lemonchiffon", NSVG_RGB(255, 250, 205) },
- { "lightblue", NSVG_RGB(173, 216, 230) },
- { "lightcoral", NSVG_RGB(240, 128, 128) },
- { "lightcyan", NSVG_RGB(224, 255, 255) },
- { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) },
- { "lightgray", NSVG_RGB(211, 211, 211) },
- { "lightgreen", NSVG_RGB(144, 238, 144) },
- { "lightgrey", NSVG_RGB(211, 211, 211) },
- { "lightpink", NSVG_RGB(255, 182, 193) },
- { "lightsalmon", NSVG_RGB(255, 160, 122) },
- { "lightseagreen", NSVG_RGB( 32, 178, 170) },
- { "lightskyblue", NSVG_RGB(135, 206, 250) },
- { "lightslategray", NSVG_RGB(119, 136, 153) },
- { "lightslategrey", NSVG_RGB(119, 136, 153) },
- { "lightsteelblue", NSVG_RGB(176, 196, 222) },
- { "lightyellow", NSVG_RGB(255, 255, 224) },
- { "lime", NSVG_RGB( 0, 255, 0) },
- { "limegreen", NSVG_RGB( 50, 205, 50) },
- { "linen", NSVG_RGB(250, 240, 230) },
- { "maroon", NSVG_RGB(128, 0, 0) },
- { "mediumaquamarine", NSVG_RGB(102, 205, 170) },
- { "mediumblue", NSVG_RGB( 0, 0, 205) },
- { "mediumorchid", NSVG_RGB(186, 85, 211) },
- { "mediumpurple", NSVG_RGB(147, 112, 219) },
- { "mediumseagreen", NSVG_RGB( 60, 179, 113) },
- { "mediumslateblue", NSVG_RGB(123, 104, 238) },
- { "mediumspringgreen", NSVG_RGB( 0, 250, 154) },
- { "mediumturquoise", NSVG_RGB( 72, 209, 204) },
- { "mediumvioletred", NSVG_RGB(199, 21, 133) },
- { "midnightblue", NSVG_RGB( 25, 25, 112) },
- { "mintcream", NSVG_RGB(245, 255, 250) },
- { "mistyrose", NSVG_RGB(255, 228, 225) },
- { "moccasin", NSVG_RGB(255, 228, 181) },
- { "navajowhite", NSVG_RGB(255, 222, 173) },
- { "navy", NSVG_RGB( 0, 0, 128) },
- { "oldlace", NSVG_RGB(253, 245, 230) },
- { "olive", NSVG_RGB(128, 128, 0) },
- { "olivedrab", NSVG_RGB(107, 142, 35) },
- { "orange", NSVG_RGB(255, 165, 0) },
- { "orangered", NSVG_RGB(255, 69, 0) },
- { "orchid", NSVG_RGB(218, 112, 214) },
- { "palegoldenrod", NSVG_RGB(238, 232, 170) },
- { "palegreen", NSVG_RGB(152, 251, 152) },
- { "paleturquoise", NSVG_RGB(175, 238, 238) },
- { "palevioletred", NSVG_RGB(219, 112, 147) },
- { "papayawhip", NSVG_RGB(255, 239, 213) },
- { "peachpuff", NSVG_RGB(255, 218, 185) },
- { "peru", NSVG_RGB(205, 133, 63) },
- { "pink", NSVG_RGB(255, 192, 203) },
- { "plum", NSVG_RGB(221, 160, 221) },
- { "powderblue", NSVG_RGB(176, 224, 230) },
- { "purple", NSVG_RGB(128, 0, 128) },
- { "rosybrown", NSVG_RGB(188, 143, 143) },
- { "royalblue", NSVG_RGB( 65, 105, 225) },
- { "saddlebrown", NSVG_RGB(139, 69, 19) },
- { "salmon", NSVG_RGB(250, 128, 114) },
- { "sandybrown", NSVG_RGB(244, 164, 96) },
- { "seagreen", NSVG_RGB( 46, 139, 87) },
- { "seashell", NSVG_RGB(255, 245, 238) },
- { "sienna", NSVG_RGB(160, 82, 45) },
- { "silver", NSVG_RGB(192, 192, 192) },
- { "skyblue", NSVG_RGB(135, 206, 235) },
- { "slateblue", NSVG_RGB(106, 90, 205) },
- { "slategray", NSVG_RGB(112, 128, 144) },
- { "slategrey", NSVG_RGB(112, 128, 144) },
- { "snow", NSVG_RGB(255, 250, 250) },
- { "springgreen", NSVG_RGB( 0, 255, 127) },
- { "steelblue", NSVG_RGB( 70, 130, 180) },
- { "tan", NSVG_RGB(210, 180, 140) },
- { "teal", NSVG_RGB( 0, 128, 128) },
- { "thistle", NSVG_RGB(216, 191, 216) },
- { "tomato", NSVG_RGB(255, 99, 71) },
- { "turquoise", NSVG_RGB( 64, 224, 208) },
- { "violet", NSVG_RGB(238, 130, 238) },
- { "wheat", NSVG_RGB(245, 222, 179) },
- { "whitesmoke", NSVG_RGB(245, 245, 245) },
- { "yellowgreen", NSVG_RGB(154, 205, 50) },
-#endif
-};
-
-static unsigned int nsvg__parseColorName(const char* str)
-{
- int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor);
-
- for (i = 0; i < ncolors; i++) {
- if (strcmp(nsvg__colors[i].name, str) == 0) {
- return nsvg__colors[i].color;
- }
- }
-
- return NSVG_RGB(128, 128, 128);
-}
-
-static unsigned int nsvg__parseColor(const char* str)
-{
- size_t len = 0;
- while(*str == ' ') ++str;
- len = strlen(str);
- if (len >= 1 && *str == '#')
- return nsvg__parseColorHex(str);
- else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(')
- return nsvg__parseColorRGB(str);
- return nsvg__parseColorName(str);
-}
-
-static float nsvg__parseOpacity(const char* str)
-{
- float val = nsvg__atof(str);
- if (val < 0.0f) val = 0.0f;
- if (val > 1.0f) val = 1.0f;
- return val;
-}
-
-static float nsvg__parseMiterLimit(const char* str)
-{
- float val = nsvg__atof(str);
- if (val < 0.0f) val = 0.0f;
- return val;
-}
-
-static int nsvg__parseUnits(const char* units)
-{
- if (units[0] == 'p' && units[1] == 'x')
- return NSVG_UNITS_PX;
- else if (units[0] == 'p' && units[1] == 't')
- return NSVG_UNITS_PT;
- else if (units[0] == 'p' && units[1] == 'c')
- return NSVG_UNITS_PC;
- else if (units[0] == 'm' && units[1] == 'm')
- return NSVG_UNITS_MM;
- else if (units[0] == 'c' && units[1] == 'm')
- return NSVG_UNITS_CM;
- else if (units[0] == 'i' && units[1] == 'n')
- return NSVG_UNITS_IN;
- else if (units[0] == '%')
- return NSVG_UNITS_PERCENT;
- else if (units[0] == 'e' && units[1] == 'm')
- return NSVG_UNITS_EM;
- else if (units[0] == 'e' && units[1] == 'x')
- return NSVG_UNITS_EX;
- return NSVG_UNITS_USER;
-}
-
-static int nsvg__isCoordinate(const char* s)
-{
- // optional sign
- if (*s == '-' || *s == '+')
- s++;
- // must have at least one digit, or start by a dot
- return (nsvg__isdigit(*s) || *s == '.');
-}
-
-static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
-{
- NSVGcoordinate coord = {0, NSVG_UNITS_USER};
- char buf[64];
- coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));
- coord.value = nsvg__atof(buf);
- return coord;
-}
-
-static NSVGcoordinate nsvg__coord(float v, int units)
-{
- NSVGcoordinate coord = {v, units};
- return coord;
-}
-
-static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length)
-{
- NSVGcoordinate coord = nsvg__parseCoordinateRaw(str);
- return nsvg__convertToPixels(p, coord, orig, length);
-}
-
-static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na)
-{
- const char* end;
- const char* ptr;
- char it[64];
-
- *na = 0;
- ptr = str;
- while (*ptr && *ptr != '(') ++ptr;
- if (*ptr == 0)
- return 1;
- end = ptr;
- while (*end && *end != ')') ++end;
- if (*end == 0)
- return 1;
-
- while (ptr < end) {
- if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {
- if (*na >= maxNa) return 0;
- ptr = nsvg__parseNumber(ptr, it, 64);
- args[(*na)++] = (float)nsvg__atof(it);
- } else {
- ++ptr;
- }
- }
- return (int)(end - str);
-}
-
-
-static int nsvg__parseMatrix(float* xform, const char* str)
-{
- float t[6];
- int na = 0;
- int len = nsvg__parseTransformArgs(str, t, 6, &na);
- if (na != 6) return len;
- memcpy(xform, t, sizeof(float)*6);
- return len;
-}
-
-static int nsvg__parseTranslate(float* xform, const char* str)
-{
- float args[2];
- float t[6];
- int na = 0;
- int len = nsvg__parseTransformArgs(str, args, 2, &na);
- if (na == 1) args[1] = 0.0;
-
- nsvg__xformSetTranslation(t, args[0], args[1]);
- memcpy(xform, t, sizeof(float)*6);
- return len;
-}
-
-static int nsvg__parseScale(float* xform, const char* str)
-{
- float args[2];
- int na = 0;
- float t[6];
- int len = nsvg__parseTransformArgs(str, args, 2, &na);
- if (na == 1) args[1] = args[0];
- nsvg__xformSetScale(t, args[0], args[1]);
- memcpy(xform, t, sizeof(float)*6);
- return len;
-}
-
-static int nsvg__parseSkewX(float* xform, const char* str)
-{
- float args[1];
- int na = 0;
- float t[6];
- int len = nsvg__parseTransformArgs(str, args, 1, &na);
- nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI);
- memcpy(xform, t, sizeof(float)*6);
- return len;
-}
-
-static int nsvg__parseSkewY(float* xform, const char* str)
-{
- float args[1];
- int na = 0;
- float t[6];
- int len = nsvg__parseTransformArgs(str, args, 1, &na);
- nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI);
- memcpy(xform, t, sizeof(float)*6);
- return len;
-}
-
-static int nsvg__parseRotate(float* xform, const char* str)
-{
- float args[3];
- int na = 0;
- float m[6];
- float t[6];
- int len = nsvg__parseTransformArgs(str, args, 3, &na);
- if (na == 1)
- args[1] = args[2] = 0.0f;
- nsvg__xformIdentity(m);
-
- if (na > 1) {
- nsvg__xformSetTranslation(t, -args[1], -args[2]);
- nsvg__xformMultiply(m, t);
- }
-
- nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI);
- nsvg__xformMultiply(m, t);
-
- if (na > 1) {
- nsvg__xformSetTranslation(t, args[1], args[2]);
- nsvg__xformMultiply(m, t);
- }
-
- memcpy(xform, m, sizeof(float)*6);
-
- return len;
-}
-
-static void nsvg__parseTransform(float* xform, const char* str)
-{
- float t[6];
- int len;
- nsvg__xformIdentity(xform);
- while (*str)
- {
- if (strncmp(str, "matrix", 6) == 0)
- len = nsvg__parseMatrix(t, str);
- else if (strncmp(str, "translate", 9) == 0)
- len = nsvg__parseTranslate(t, str);
- else if (strncmp(str, "scale", 5) == 0)
- len = nsvg__parseScale(t, str);
- else if (strncmp(str, "rotate", 6) == 0)
- len = nsvg__parseRotate(t, str);
- else if (strncmp(str, "skewX", 5) == 0)
- len = nsvg__parseSkewX(t, str);
- else if (strncmp(str, "skewY", 5) == 0)
- len = nsvg__parseSkewY(t, str);
- else{
- ++str;
- continue;
- }
- if (len != 0) {
- str += len;
- } else {
- ++str;
- continue;
- }
-
- nsvg__xformPremultiply(xform, t);
- }
-}
-
-static void nsvg__parseUrl(char* id, const char* str)
-{
- int i = 0;
- str += 4; // "url(";
- if (*str && *str == '#')
- str++;
- while (i < 63 && *str && *str != ')') {
- id[i] = *str++;
- i++;
- }
- id[i] = '\0';
-}
-
-static char nsvg__parseLineCap(const char* str)
-{
- if (strcmp(str, "butt") == 0)
- return NSVG_CAP_BUTT;
- else if (strcmp(str, "round") == 0)
- return NSVG_CAP_ROUND;
- else if (strcmp(str, "square") == 0)
- return NSVG_CAP_SQUARE;
- // TODO: handle inherit.
- return NSVG_CAP_BUTT;
-}
-
-static char nsvg__parseLineJoin(const char* str)
-{
- if (strcmp(str, "miter") == 0)
- return NSVG_JOIN_MITER;
- else if (strcmp(str, "round") == 0)
- return NSVG_JOIN_ROUND;
- else if (strcmp(str, "bevel") == 0)
- return NSVG_JOIN_BEVEL;
- // TODO: handle inherit.
- return NSVG_JOIN_MITER;
-}
-
-static char nsvg__parseFillRule(const char* str)
-{
- if (strcmp(str, "nonzero") == 0)
- return NSVG_FILLRULE_NONZERO;
- else if (strcmp(str, "evenodd") == 0)
- return NSVG_FILLRULE_EVENODD;
- // TODO: handle inherit.
- return NSVG_FILLRULE_NONZERO;
-}
-
-static const char* nsvg__getNextDashItem(const char* s, char* it)
-{
- int n = 0;
- it[0] = '\0';
- // Skip white spaces and commas
- while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
- // Advance until whitespace, comma or end.
- while (*s && (!nsvg__isspace(*s) && *s != ',')) {
- if (n < 63)
- it[n++] = *s;
- s++;
- }
- it[n++] = '\0';
- return s;
-}
-
-static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray)
-{
- char item[64];
- int count = 0, i;
- float sum = 0.0f;
-
- // Handle "none"
- if (str[0] == 'n')
- return 0;
-
- // Parse dashes
- while (*str) {
- str = nsvg__getNextDashItem(str, item);
- if (!*item) break;
- if (count < NSVG_MAX_DASHES)
- strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p)));
- }
-
- for (i = 0; i < count; i++)
- sum += strokeDashArray[i];
- if (sum <= 1e-6f)
- count = 0;
-
- return count;
-}
-
-static void nsvg__parseStyle(NSVGparser* p, const char* str);
-
-static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
-{
- float xform[6];
- NSVGattrib* attr = nsvg__getAttr(p);
- if (!attr) return 0;
-
- if (strcmp(name, "style") == 0) {
- nsvg__parseStyle(p, value);
- } else if (strcmp(name, "display") == 0) {
- if (strcmp(value, "none") == 0)
- attr->visible = 0;
- // Don't reset ->visible on display:inline, one display:none hides the whole subtree
-
- } else if (strcmp(name, "fill") == 0) {
- if (strcmp(value, "none") == 0) {
- attr->hasFill = 0;
- } else if (strncmp(value, "url(", 4) == 0) {
- attr->hasFill = 2;
- nsvg__parseUrl(attr->fillGradient, value);
- } else {
- attr->hasFill = 1;
- attr->fillColor = nsvg__parseColor(value);
- }
- } else if (strcmp(name, "opacity") == 0) {
- attr->opacity = nsvg__parseOpacity(value);
- } else if (strcmp(name, "fill-opacity") == 0) {
- attr->fillOpacity = nsvg__parseOpacity(value);
- } else if (strcmp(name, "stroke") == 0) {
- if (strcmp(value, "none") == 0) {
- attr->hasStroke = 0;
- } else if (strncmp(value, "url(", 4) == 0) {
- attr->hasStroke = 2;
- nsvg__parseUrl(attr->strokeGradient, value);
- } else {
- attr->hasStroke = 1;
- attr->strokeColor = nsvg__parseColor(value);
- }
- } else if (strcmp(name, "stroke-width") == 0) {
- attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
- } else if (strcmp(name, "stroke-dasharray") == 0) {
- attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray);
- } else if (strcmp(name, "stroke-dashoffset") == 0) {
- attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
- } else if (strcmp(name, "stroke-opacity") == 0) {
- attr->strokeOpacity = nsvg__parseOpacity(value);
- } else if (strcmp(name, "stroke-linecap") == 0) {
- attr->strokeLineCap = nsvg__parseLineCap(value);
- } else if (strcmp(name, "stroke-linejoin") == 0) {
- attr->strokeLineJoin = nsvg__parseLineJoin(value);
- } else if (strcmp(name, "stroke-miterlimit") == 0) {
- attr->miterLimit = nsvg__parseMiterLimit(value);
- } else if (strcmp(name, "fill-rule") == 0) {
- attr->fillRule = nsvg__parseFillRule(value);
- } else if (strcmp(name, "font-size") == 0) {
- attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
- } else if (strcmp(name, "transform") == 0) {
- nsvg__parseTransform(xform, value);
- nsvg__xformPremultiply(attr->xform, xform);
- } else if (strcmp(name, "stop-color") == 0) {
- attr->stopColor = nsvg__parseColor(value);
- } else if (strcmp(name, "stop-opacity") == 0) {
- attr->stopOpacity = nsvg__parseOpacity(value);
- } else if (strcmp(name, "offset") == 0) {
- attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f);
- } else if (strcmp(name, "id") == 0) {
- strncpy(attr->id, value, 63);
- attr->id[63] = '\0';
- } else {
- return 0;
- }
- return 1;
-}
-
-static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end)
-{
- const char* str;
- const char* val;
- char name[512];
- char value[512];
- int n;
-
- str = start;
- while (str < end && *str != ':') ++str;
-
- val = str;
-
- // Right Trim
- while (str > start && (*str == ':' || nsvg__isspace(*str))) --str;
- ++str;
-
- n = (int)(str - start);
- if (n > 511) n = 511;
- if (n) memcpy(name, start, n);
- name[n] = 0;
-
- while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val;
-
- n = (int)(end - val);
- if (n > 511) n = 511;
- if (n) memcpy(value, val, n);
- value[n] = 0;
-
- return nsvg__parseAttr(p, name, value);
-}
-
-static void nsvg__parseStyle(NSVGparser* p, const char* str)
-{
- const char* start;
- const char* end;
-
- while (*str) {
- // Left Trim
- while(*str && nsvg__isspace(*str)) ++str;
- start = str;
- while(*str && *str != ';') ++str;
- end = str;
-
- // Right Trim
- while (end > start && (*end == ';' || nsvg__isspace(*end))) --end;
- ++end;
-
- nsvg__parseNameValue(p, start, end);
- if (*str) ++str;
- }
-}
-
-static void nsvg__parseAttribs(NSVGparser* p, const char** attr)
-{
- int i;
- for (i = 0; attr[i]; i += 2)
- {
- if (strcmp(attr[i], "style") == 0)
- nsvg__parseStyle(p, attr[i + 1]);
- else
- nsvg__parseAttr(p, attr[i], attr[i + 1]);
- }
-}
-
-static int nsvg__getArgsPerElement(char cmd)
-{
- switch (cmd) {
- case 'v':
- case 'V':
- case 'h':
- case 'H':
- return 1;
- case 'm':
- case 'M':
- case 'l':
- case 'L':
- case 't':
- case 'T':
- return 2;
- case 'q':
- case 'Q':
- case 's':
- case 'S':
- return 4;
- case 'c':
- case 'C':
- return 6;
- case 'a':
- case 'A':
- return 7;
- case 'z':
- case 'Z':
- return 0;
- }
- return -1;
-}
-
-static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
-{
- if (rel) {
- *cpx += args[0];
- *cpy += args[1];
- } else {
- *cpx = args[0];
- *cpy = args[1];
- }
- nsvg__moveTo(p, *cpx, *cpy);
-}
-
-static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
-{
- if (rel) {
- *cpx += args[0];
- *cpy += args[1];
- } else {
- *cpx = args[0];
- *cpy = args[1];
- }
- nsvg__lineTo(p, *cpx, *cpy);
-}
-
-static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
-{
- if (rel)
- *cpx += args[0];
- else
- *cpx = args[0];
- nsvg__lineTo(p, *cpx, *cpy);
-}
-
-static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
-{
- if (rel)
- *cpy += args[0];
- else
- *cpy = args[0];
- nsvg__lineTo(p, *cpx, *cpy);
-}
-
-static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy,
- float* cpx2, float* cpy2, float* args, int rel)
-{
- float x2, y2, cx1, cy1, cx2, cy2;
-
- if (rel) {
- cx1 = *cpx + args[0];
- cy1 = *cpy + args[1];
- cx2 = *cpx + args[2];
- cy2 = *cpy + args[3];
- x2 = *cpx + args[4];
- y2 = *cpy + args[5];
- } else {
- cx1 = args[0];
- cy1 = args[1];
- cx2 = args[2];
- cy2 = args[3];
- x2 = args[4];
- y2 = args[5];
- }
-
- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
-
- *cpx2 = cx2;
- *cpy2 = cy2;
- *cpx = x2;
- *cpy = y2;
-}
-
-static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy,
- float* cpx2, float* cpy2, float* args, int rel)
-{
- float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
-
- x1 = *cpx;
- y1 = *cpy;
- if (rel) {
- cx2 = *cpx + args[0];
- cy2 = *cpy + args[1];
- x2 = *cpx + args[2];
- y2 = *cpy + args[3];
- } else {
- cx2 = args[0];
- cy2 = args[1];
- x2 = args[2];
- y2 = args[3];
- }
-
- cx1 = 2*x1 - *cpx2;
- cy1 = 2*y1 - *cpy2;
-
- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
-
- *cpx2 = cx2;
- *cpy2 = cy2;
- *cpx = x2;
- *cpy = y2;
-}
-
-static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy,
- float* cpx2, float* cpy2, float* args, int rel)
-{
- float x1, y1, x2, y2, cx, cy;
- float cx1, cy1, cx2, cy2;
-
- x1 = *cpx;
- y1 = *cpy;
- if (rel) {
- cx = *cpx + args[0];
- cy = *cpy + args[1];
- x2 = *cpx + args[2];
- y2 = *cpy + args[3];
- } else {
- cx = args[0];
- cy = args[1];
- x2 = args[2];
- y2 = args[3];
- }
-
- // Convert to cubic bezier
- cx1 = x1 + 2.0f/3.0f*(cx - x1);
- cy1 = y1 + 2.0f/3.0f*(cy - y1);
- cx2 = x2 + 2.0f/3.0f*(cx - x2);
- cy2 = y2 + 2.0f/3.0f*(cy - y2);
-
- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
-
- *cpx2 = cx;
- *cpy2 = cy;
- *cpx = x2;
- *cpy = y2;
-}
-
-static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy,
- float* cpx2, float* cpy2, float* args, int rel)
-{
- float x1, y1, x2, y2, cx, cy;
- float cx1, cy1, cx2, cy2;
-
- x1 = *cpx;
- y1 = *cpy;
- if (rel) {
- x2 = *cpx + args[0];
- y2 = *cpy + args[1];
- } else {
- x2 = args[0];
- y2 = args[1];
- }
-
- cx = 2*x1 - *cpx2;
- cy = 2*y1 - *cpy2;
-
- // Convert to cubix bezier
- cx1 = x1 + 2.0f/3.0f*(cx - x1);
- cy1 = y1 + 2.0f/3.0f*(cy - y1);
- cx2 = x2 + 2.0f/3.0f*(cx - x2);
- cy2 = y2 + 2.0f/3.0f*(cy - y2);
-
- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
-
- *cpx2 = cx;
- *cpy2 = cy;
- *cpx = x2;
- *cpy = y2;
-}
-
-static float nsvg__sqr(float x) { return x*x; }
-static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); }
-
-static float nsvg__vecrat(float ux, float uy, float vx, float vy)
-{
- return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy));
-}
-
-static float nsvg__vecang(float ux, float uy, float vx, float vy)
-{
- float r = nsvg__vecrat(ux,uy, vx,vy);
- if (r < -1.0f) r = -1.0f;
- if (r > 1.0f) r = 1.0f;
- return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r);
-}
-
-static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
-{
- // Ported from canvg (https://code.google.com/p/canvg/)
- float rx, ry, rotx;
- float x1, y1, x2, y2, cx, cy, dx, dy, d;
- float x1p, y1p, cxp, cyp, s, sa, sb;
- float ux, uy, vx, vy, a1, da;
- float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6];
- float sinrx, cosrx;
- int fa, fs;
- int i, ndivs;
- float hda, kappa;
-
- rx = fabsf(args[0]); // y radius
- ry = fabsf(args[1]); // x radius
- rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle
- fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc
- fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction
- x1 = *cpx; // start point
- y1 = *cpy;
- if (rel) { // end point
- x2 = *cpx + args[5];
- y2 = *cpy + args[6];
- } else {
- x2 = args[5];
- y2 = args[6];
- }
-
- dx = x1 - x2;
- dy = y1 - y2;
- d = sqrtf(dx*dx + dy*dy);
- if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) {
- // The arc degenerates to a line
- nsvg__lineTo(p, x2, y2);
- *cpx = x2;
- *cpy = y2;
- return;
- }
-
- sinrx = sinf(rotx);
- cosrx = cosf(rotx);
-
- // Convert to center point parameterization.
- // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
- // 1) Compute x1', y1'
- x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f;
- y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f;
- d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry);
- if (d > 1) {
- d = sqrtf(d);
- rx *= d;
- ry *= d;
- }
- // 2) Compute cx', cy'
- s = 0.0f;
- sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p);
- sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p);
- if (sa < 0.0f) sa = 0.0f;
- if (sb > 0.0f)
- s = sqrtf(sa / sb);
- if (fa == fs)
- s = -s;
- cxp = s * rx * y1p / ry;
- cyp = s * -ry * x1p / rx;
-
- // 3) Compute cx,cy from cx',cy'
- cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp;
- cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp;
-
- // 4) Calculate theta1, and delta theta.
- ux = (x1p - cxp) / rx;
- uy = (y1p - cyp) / ry;
- vx = (-x1p - cxp) / rx;
- vy = (-y1p - cyp) / ry;
- a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle
- da = nsvg__vecang(ux,uy, vx,vy); // Delta angle
-
-// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
-// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
-
- if (fs == 0 && da > 0)
- da -= 2 * NSVG_PI;
- else if (fs == 1 && da < 0)
- da += 2 * NSVG_PI;
-
- // Approximate the arc using cubic spline segments.
- t[0] = cosrx; t[1] = sinrx;
- t[2] = -sinrx; t[3] = cosrx;
- t[4] = cx; t[5] = cy;
-
- // Split arc into max 90 degree segments.
- // The loop assumes an iteration per end point (including start and end), this +1.
- ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f);
- hda = (da / (float)ndivs) / 2.0f;
- // Fix for ticket #179: division by 0: avoid cotangens around 0 (infinite)
- if ((hda < 1e-3f) && (hda > -1e-3f))
- hda *= 0.5f;
- else
- hda = (1.0f - cosf(hda)) / sinf(hda);
- kappa = fabsf(4.0f / 3.0f * hda);
- if (da < 0.0f)
- kappa = -kappa;
-
- for (i = 0; i <= ndivs; i++) {
- a = a1 + da * ((float)i/(float)ndivs);
- dx = cosf(a);
- dy = sinf(a);
- nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position
- nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent
- if (i > 0)
- nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y);
- px = x;
- py = y;
- ptanx = tanx;
- ptany = tany;
- }
-
- *cpx = x2;
- *cpy = y2;
-}
-
-static void nsvg__parsePath(NSVGparser* p, const char** attr)
-{
- const char* s = NULL;
- char cmd = '\0';
- float args[10];
- int nargs;
- int rargs = 0;
- char initPoint;
- float cpx, cpy, cpx2, cpy2;
- const char* tmp[4];
- char closedFlag;
- int i;
- char item[64];
-
- for (i = 0; attr[i]; i += 2) {
- if (strcmp(attr[i], "d") == 0) {
- s = attr[i + 1];
- } else {
- tmp[0] = attr[i];
- tmp[1] = attr[i + 1];
- tmp[2] = 0;
- tmp[3] = 0;
- nsvg__parseAttribs(p, tmp);
- }
- }
-
- if (s) {
- nsvg__resetPath(p);
- cpx = 0; cpy = 0;
- cpx2 = 0; cpy2 = 0;
- initPoint = 0;
- closedFlag = 0;
- nargs = 0;
-
- while (*s) {
- s = nsvg__getNextPathItem(s, item);
- if (!*item) break;
- if (cmd != '\0' && nsvg__isCoordinate(item)) {
- if (nargs < 10)
- args[nargs++] = (float)nsvg__atof(item);
- if (nargs >= rargs) {
- switch (cmd) {
- case 'm':
- case 'M':
- nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0);
- // Moveto can be followed by multiple coordinate pairs,
- // which should be treated as linetos.
- cmd = (cmd == 'm') ? 'l' : 'L';
- rargs = nsvg__getArgsPerElement(cmd);
- cpx2 = cpx; cpy2 = cpy;
- initPoint = 1;
- break;
- case 'l':
- case 'L':
- nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
- break;
- case 'H':
- case 'h':
- nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
- break;
- case 'V':
- case 'v':
- nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
- break;
- case 'C':
- case 'c':
- nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0);
- break;
- case 'S':
- case 's':
- nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0);
- break;
- case 'Q':
- case 'q':
- nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0);
- break;
- case 'T':
- case 't':
- nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0);
- break;
- case 'A':
- case 'a':
- nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
- break;
- default:
- if (nargs >= 2) {
- cpx = args[nargs-2];
- cpy = args[nargs-1];
- cpx2 = cpx; cpy2 = cpy;
- }
- break;
- }
- nargs = 0;
- }
- } else {
- cmd = item[0];
- if (cmd == 'M' || cmd == 'm') {
- // Commit path.
- if (p->npts > 0)
- nsvg__addPath(p, closedFlag);
- // Start new subpath.
- nsvg__resetPath(p);
- closedFlag = 0;
- nargs = 0;
- } else if (initPoint == 0) {
- // Do not allow other commands until initial point has been set (moveTo called once).
- cmd = '\0';
- }
- if (cmd == 'Z' || cmd == 'z') {
- closedFlag = 1;
- // Commit path.
- if (p->npts > 0) {
- // Move current point to first point
- cpx = p->pts[0];
- cpy = p->pts[1];
- cpx2 = cpx; cpy2 = cpy;
- nsvg__addPath(p, closedFlag);
- }
- // Start new subpath.
- nsvg__resetPath(p);
- nsvg__moveTo(p, cpx, cpy);
- closedFlag = 0;
- nargs = 0;
- }
- rargs = nsvg__getArgsPerElement(cmd);
- if (rargs == -1) {
- // Command not recognized
- cmd = '\0';
- rargs = 0;
- }
- }
- }
- // Commit path.
- if (p->npts)
- nsvg__addPath(p, closedFlag);
- }
-
- nsvg__addShape(p);
-}
-
-static void nsvg__parseRect(NSVGparser* p, const char** attr)
-{
- float x = 0.0f;
- float y = 0.0f;
- float w = 0.0f;
- float h = 0.0f;
- float rx = -1.0f; // marks not set
- float ry = -1.0f;
- int i;
-
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
- if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
- if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p));
- if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p));
- if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
- if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
- }
- }
-
- if (rx < 0.0f && ry > 0.0f) rx = ry;
- if (ry < 0.0f && rx > 0.0f) ry = rx;
- if (rx < 0.0f) rx = 0.0f;
- if (ry < 0.0f) ry = 0.0f;
- if (rx > w/2.0f) rx = w/2.0f;
- if (ry > h/2.0f) ry = h/2.0f;
-
- if (w != 0.0f && h != 0.0f) {
- nsvg__resetPath(p);
-
- if (rx < 0.00001f || ry < 0.0001f) {
- nsvg__moveTo(p, x, y);
- nsvg__lineTo(p, x+w, y);
- nsvg__lineTo(p, x+w, y+h);
- nsvg__lineTo(p, x, y+h);
- } else {
- // Rounded rectangle
- nsvg__moveTo(p, x+rx, y);
- nsvg__lineTo(p, x+w-rx, y);
- nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry);
- nsvg__lineTo(p, x+w, y+h-ry);
- nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h);
- nsvg__lineTo(p, x+rx, y+h);
- nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry);
- nsvg__lineTo(p, x, y+ry);
- nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y);
- }
-
- nsvg__addPath(p, 1);
-
- nsvg__addShape(p);
- }
-}
-
-static void nsvg__parseCircle(NSVGparser* p, const char** attr)
-{
- float cx = 0.0f;
- float cy = 0.0f;
- float r = 0.0f;
- int i;
-
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
- if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
- if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p)));
- }
- }
-
- if (r > 0.0f) {
- nsvg__resetPath(p);
-
- nsvg__moveTo(p, cx+r, cy);
- nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r);
- nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy);
- nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r);
- nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy);
-
- nsvg__addPath(p, 1);
-
- nsvg__addShape(p);
- }
-}
-
-static void nsvg__parseEllipse(NSVGparser* p, const char** attr)
-{
- float cx = 0.0f;
- float cy = 0.0f;
- float rx = 0.0f;
- float ry = 0.0f;
- int i;
-
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
- if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
- if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
- if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
- }
- }
-
- if (rx > 0.0f && ry > 0.0f) {
-
- nsvg__resetPath(p);
-
- nsvg__moveTo(p, cx+rx, cy);
- nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry);
- nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy);
- nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);
- nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy);
-
- nsvg__addPath(p, 1);
-
- nsvg__addShape(p);
- }
-}
-
-static void nsvg__parseLine(NSVGparser* p, const char** attr)
-{
- float x1 = 0.0;
- float y1 = 0.0;
- float x2 = 0.0;
- float y2 = 0.0;
- int i;
-
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
- if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
- if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
- if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
- }
- }
-
- nsvg__resetPath(p);
-
- nsvg__moveTo(p, x1, y1);
- nsvg__lineTo(p, x2, y2);
-
- nsvg__addPath(p, 0);
-
- nsvg__addShape(p);
-}
-
-static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
-{
- int i;
- const char* s;
- float args[2];
- int nargs, npts = 0;
- char item[64];
-
- nsvg__resetPath(p);
-
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "points") == 0) {
- s = attr[i + 1];
- nargs = 0;
- while (*s) {
- s = nsvg__getNextPathItem(s, item);
- args[nargs++] = (float)nsvg__atof(item);
- if (nargs >= 2) {
- if (npts == 0)
- nsvg__moveTo(p, args[0], args[1]);
- else
- nsvg__lineTo(p, args[0], args[1]);
- nargs = 0;
- npts++;
- }
- }
- }
- }
- }
-
- nsvg__addPath(p, (char)closeFlag);
-
- nsvg__addShape(p);
-}
-
-static void nsvg__parseSVG(NSVGparser* p, const char** attr)
-{
- int i;
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "width") == 0) {
- p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
- } else if (strcmp(attr[i], "height") == 0) {
- p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
- } else if (strcmp(attr[i], "viewBox") == 0) {
- const char *s = attr[i + 1];
- char buf[64];
- s = nsvg__parseNumber(s, buf, 64);
- p->viewMinx = nsvg__atof(buf);
- while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
- if (!*s) return;
- s = nsvg__parseNumber(s, buf, 64);
- p->viewMiny = nsvg__atof(buf);
- while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
- if (!*s) return;
- s = nsvg__parseNumber(s, buf, 64);
- p->viewWidth = nsvg__atof(buf);
- while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
- if (!*s) return;
- s = nsvg__parseNumber(s, buf, 64);
- p->viewHeight = nsvg__atof(buf);
- } else if (strcmp(attr[i], "preserveAspectRatio") == 0) {
- if (strstr(attr[i + 1], "none") != 0) {
- // No uniform scaling
- p->alignType = NSVG_ALIGN_NONE;
- } else {
- // Parse X align
- if (strstr(attr[i + 1], "xMin") != 0)
- p->alignX = NSVG_ALIGN_MIN;
- else if (strstr(attr[i + 1], "xMid") != 0)
- p->alignX = NSVG_ALIGN_MID;
- else if (strstr(attr[i + 1], "xMax") != 0)
- p->alignX = NSVG_ALIGN_MAX;
- // Parse X align
- if (strstr(attr[i + 1], "yMin") != 0)
- p->alignY = NSVG_ALIGN_MIN;
- else if (strstr(attr[i + 1], "yMid") != 0)
- p->alignY = NSVG_ALIGN_MID;
- else if (strstr(attr[i + 1], "yMax") != 0)
- p->alignY = NSVG_ALIGN_MAX;
- // Parse meet/slice
- p->alignType = NSVG_ALIGN_MEET;
- if (strstr(attr[i + 1], "slice") != 0)
- p->alignType = NSVG_ALIGN_SLICE;
- }
- }
- }
- }
-}
-
-static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type)
-{
- int i;
- NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData));
- if (grad == NULL) return;
- memset(grad, 0, sizeof(NSVGgradientData));
- grad->units = NSVG_OBJECT_SPACE;
- grad->type = type;
- if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) {
- grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
- grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
- grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT);
- grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
- } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) {
- grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
- grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
- grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
- }
-
- nsvg__xformIdentity(grad->xform);
-
- for (i = 0; attr[i]; i += 2) {
- if (strcmp(attr[i], "id") == 0) {
- strncpy(grad->id, attr[i+1], 63);
- grad->id[63] = '\0';
- } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "gradientUnits") == 0) {
- if (strcmp(attr[i+1], "objectBoundingBox") == 0)
- grad->units = NSVG_OBJECT_SPACE;
- else
- grad->units = NSVG_USER_SPACE;
- } else if (strcmp(attr[i], "gradientTransform") == 0) {
- nsvg__parseTransform(grad->xform, attr[i + 1]);
- } else if (strcmp(attr[i], "cx") == 0) {
- grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "cy") == 0) {
- grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "r") == 0) {
- grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "fx") == 0) {
- grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "fy") == 0) {
- grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "x1") == 0) {
- grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "y1") == 0) {
- grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "x2") == 0) {
- grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "y2") == 0) {
- grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "spreadMethod") == 0) {
- if (strcmp(attr[i+1], "pad") == 0)
- grad->spread = NSVG_SPREAD_PAD;
- else if (strcmp(attr[i+1], "reflect") == 0)
- grad->spread = NSVG_SPREAD_REFLECT;
- else if (strcmp(attr[i+1], "repeat") == 0)
- grad->spread = NSVG_SPREAD_REPEAT;
- } else if (strcmp(attr[i], "xlink:href") == 0) {
- const char *href = attr[i+1];
- strncpy(grad->ref, href+1, 62);
- grad->ref[62] = '\0';
- }
- }
- }
-
- grad->next = p->gradients;
- p->gradients = grad;
-}
-
-static void nsvg__parseGradientStop(NSVGparser* p, const char** attr)
-{
- NSVGattrib* curAttr = nsvg__getAttr(p);
- NSVGgradientData* grad;
- NSVGgradientStop* stop;
- int i, idx;
-
- curAttr->stopOffset = 0;
- curAttr->stopColor = 0;
- curAttr->stopOpacity = 1.0f;
-
- for (i = 0; attr[i]; i += 2) {
- nsvg__parseAttr(p, attr[i], attr[i + 1]);
- }
-
- // Add stop to the last gradient.
- grad = p->gradients;
- if (grad == NULL) return;
-
- grad->nstops++;
- grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops);
- if (grad->stops == NULL) return;
-
- // Insert
- idx = grad->nstops-1;
- for (i = 0; i < grad->nstops-1; i++) {
- if (curAttr->stopOffset < grad->stops[i].offset) {
- idx = i;
- break;
- }
- }
- if (idx != grad->nstops-1) {
- for (i = grad->nstops-1; i > idx; i--)
- grad->stops[i] = grad->stops[i-1];
- }
-
- stop = &grad->stops[idx];
- stop->color = curAttr->stopColor;
- stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24;
- stop->offset = curAttr->stopOffset;
-}
-
-static void nsvg__startElement(void* ud, const char* el, const char** attr)
-{
- NSVGparser* p = (NSVGparser*)ud;
-
- if (p->defsFlag) {
- // Skip everything but gradients in defs
- if (strcmp(el, "linearGradient") == 0) {
- nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
- } else if (strcmp(el, "radialGradient") == 0) {
- nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
- } else if (strcmp(el, "stop") == 0) {
- nsvg__parseGradientStop(p, attr);
- }
- return;
- }
-
- if (strcmp(el, "g") == 0) {
- nsvg__pushAttr(p);
- nsvg__parseAttribs(p, attr);
- } else if (strcmp(el, "path") == 0) {
- if (p->pathFlag) // Do not allow nested paths.
- return;
- nsvg__pushAttr(p);
- nsvg__parsePath(p, attr);
- nsvg__popAttr(p);
- } else if (strcmp(el, "rect") == 0) {
- nsvg__pushAttr(p);
- nsvg__parseRect(p, attr);
- nsvg__popAttr(p);
- } else if (strcmp(el, "circle") == 0) {
- nsvg__pushAttr(p);
- nsvg__parseCircle(p, attr);
- nsvg__popAttr(p);
- } else if (strcmp(el, "ellipse") == 0) {
- nsvg__pushAttr(p);
- nsvg__parseEllipse(p, attr);
- nsvg__popAttr(p);
- } else if (strcmp(el, "line") == 0) {
- nsvg__pushAttr(p);
- nsvg__parseLine(p, attr);
- nsvg__popAttr(p);
- } else if (strcmp(el, "polyline") == 0) {
- nsvg__pushAttr(p);
- nsvg__parsePoly(p, attr, 0);
- nsvg__popAttr(p);
- } else if (strcmp(el, "polygon") == 0) {
- nsvg__pushAttr(p);
- nsvg__parsePoly(p, attr, 1);
- nsvg__popAttr(p);
- } else if (strcmp(el, "linearGradient") == 0) {
- nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
- } else if (strcmp(el, "radialGradient") == 0) {
- nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
- } else if (strcmp(el, "stop") == 0) {
- nsvg__parseGradientStop(p, attr);
- } else if (strcmp(el, "defs") == 0) {
- p->defsFlag = 1;
- } else if (strcmp(el, "svg") == 0) {
- nsvg__parseSVG(p, attr);
- }
-}
-
-static void nsvg__endElement(void* ud, const char* el)
-{
- NSVGparser* p = (NSVGparser*)ud;
-
- if (strcmp(el, "g") == 0) {
- nsvg__popAttr(p);
- } else if (strcmp(el, "path") == 0) {
- p->pathFlag = 0;
- } else if (strcmp(el, "defs") == 0) {
- p->defsFlag = 0;
- }
-}
-
-static void nsvg__content(void* ud, const char* s)
-{
- NSVG_NOTUSED(ud);
- NSVG_NOTUSED(s);
- // empty
-}
-
-static void nsvg__imageBounds(NSVGparser* p, float* bounds)
-{
- NSVGshape* shape;
- shape = p->image->shapes;
- if (shape == NULL) {
- bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
- return;
- }
- bounds[0] = shape->bounds[0];
- bounds[1] = shape->bounds[1];
- bounds[2] = shape->bounds[2];
- bounds[3] = shape->bounds[3];
- for (shape = shape->next; shape != NULL; shape = shape->next) {
- bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
- bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);
- bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);
- bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);
- }
-}
-
-static float nsvg__viewAlign(float content, float container, int type)
-{
- if (type == NSVG_ALIGN_MIN)
- return 0;
- else if (type == NSVG_ALIGN_MAX)
- return container - content;
- // mid
- return (container - content) * 0.5f;
-}
-
-static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)
-{
- float t[6];
- nsvg__xformSetTranslation(t, tx, ty);
- nsvg__xformMultiply (grad->xform, t);
-
- nsvg__xformSetScale(t, sx, sy);
- nsvg__xformMultiply (grad->xform, t);
-}
-
-static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
-{
- NSVGshape* shape;
- NSVGpath* path;
- float tx, ty, sx, sy, us, bounds[4], t[6], avgs;
- int i;
- float* pt;
-
- // Guess image size if not set completely.
- nsvg__imageBounds(p, bounds);
-
- if (p->viewWidth == 0) {
- if (p->image->width > 0) {
- p->viewWidth = p->image->width;
- } else {
- p->viewMinx = bounds[0];
- p->viewWidth = bounds[2] - bounds[0];
- }
- }
- if (p->viewHeight == 0) {
- if (p->image->height > 0) {
- p->viewHeight = p->image->height;
- } else {
- p->viewMiny = bounds[1];
- p->viewHeight = bounds[3] - bounds[1];
- }
- }
- if (p->image->width == 0)
- p->image->width = p->viewWidth;
- if (p->image->height == 0)
- p->image->height = p->viewHeight;
-
- tx = -p->viewMinx;
- ty = -p->viewMiny;
- sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0;
- sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0;
- // Unit scaling
- us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f);
-
- // Fix aspect ratio
- if (p->alignType == NSVG_ALIGN_MEET) {
- // fit whole image into viewbox
- sx = sy = nsvg__minf(sx, sy);
- tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
- ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
- } else if (p->alignType == NSVG_ALIGN_SLICE) {
- // fill whole viewbox with image
- sx = sy = nsvg__maxf(sx, sy);
- tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
- ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
- }
-
- // Transform
- sx *= us;
- sy *= us;
- avgs = (sx+sy) / 2.0f;
- for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
- shape->bounds[0] = (shape->bounds[0] + tx) * sx;
- shape->bounds[1] = (shape->bounds[1] + ty) * sy;
- shape->bounds[2] = (shape->bounds[2] + tx) * sx;
- shape->bounds[3] = (shape->bounds[3] + ty) * sy;
- for (path = shape->paths; path != NULL; path = path->next) {
- path->bounds[0] = (path->bounds[0] + tx) * sx;
- path->bounds[1] = (path->bounds[1] + ty) * sy;
- path->bounds[2] = (path->bounds[2] + tx) * sx;
- path->bounds[3] = (path->bounds[3] + ty) * sy;
- for (i =0; i < path->npts; i++) {
- pt = &path->pts[i*2];
- pt[0] = (pt[0] + tx) * sx;
- pt[1] = (pt[1] + ty) * sy;
- }
- }
-
- if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) {
- nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy);
- memcpy(t, shape->fill.gradient->xform, sizeof(float)*6);
- nsvg__xformInverse(shape->fill.gradient->xform, t);
- }
- if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) {
- nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy);
- memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6);
- nsvg__xformInverse(shape->stroke.gradient->xform, t);
- }
-
- shape->strokeWidth *= avgs;
- shape->strokeDashOffset *= avgs;
- for (i = 0; i < shape->strokeDashCount; i++)
- shape->strokeDashArray[i] *= avgs;
- }
-}
-
-NSVGimage* nsvgParse(char* input, const char* units, float dpi)
-{
- NSVGparser* p;
- NSVGimage* ret = 0;
-
- p = nsvg__createParser();
- if (p == NULL) {
- return NULL;
- }
- p->dpi = dpi;
-
- nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);
-
- // Scale to viewBox
- nsvg__scaleToViewbox(p, units);
-
- ret = p->image;
- p->image = NULL;
-
- nsvg__deleteParser(p);
-
- return ret;
-}
-
-NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
-{
- FILE* fp = NULL;
- size_t size;
- char* data = NULL;
- NSVGimage* image = NULL;
-
- fp = fopen(filename, "rb");
- if (!fp) goto error;
- fseek(fp, 0, SEEK_END);
- size = ftell(fp);
- fseek(fp, 0, SEEK_SET);
- data = (char*)malloc(size+1);
- if (data == NULL) goto error;
- if (fread(data, 1, size, fp) != size) goto error;
- data[size] = '\0'; // Must be null terminated.
- fclose(fp);
- image = nsvgParse(data, units, dpi);
- free(data);
-
- return image;
-
-error:
- if (fp) fclose(fp);
- if (data) free(data);
- if (image) nsvgDelete(image);
- return NULL;
-}
-
-NSVGpath* nsvgDuplicatePath(NSVGpath* p)
-{
- NSVGpath* res = NULL;
-
- if (p == NULL)
- return NULL;
-
- res = (NSVGpath*)malloc(sizeof(NSVGpath));
- if (res == NULL) goto error;
- memset(res, 0, sizeof(NSVGpath));
-
- res->pts = (float*)malloc(p->npts*2*sizeof(float));
- if (res->pts == NULL) goto error;
- memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2);
- res->npts = p->npts;
-
- memcpy(res->bounds, p->bounds, sizeof(p->bounds));
-
- res->closed = p->closed;
-
- return res;
-
-error:
- if (res != NULL) {
- free(res->pts);
- free(res);
- }
- return NULL;
-}
-
-void nsvgDelete(NSVGimage* image)
-{
- NSVGshape *snext, *shape;
- if (image == NULL) return;
- shape = image->shapes;
- while (shape != NULL) {
- snext = shape->next;
- nsvg__deletePaths(shape->paths);
- nsvg__deletePaint(&shape->fill);
- nsvg__deletePaint(&shape->stroke);
- free(shape);
- shape = snext;
- }
- free(image);
-}
-
-#endif // NANOSVG_IMPLEMENTATION
-
-#endif // NANOSVG_H
diff --git a/src/external/nanosvgrast.h b/src/external/nanosvgrast.h
deleted file mode 100644
index 6e23acb7b..000000000
--- a/src/external/nanosvgrast.h
+++ /dev/null
@@ -1,1458 +0,0 @@
-/*
- * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- *
- * The polygon rasterization is heavily based on stb_truetype rasterizer
- * by Sean Barrett - http://nothings.org/
- *
- */
-
-#ifndef NANOSVGRAST_H
-#define NANOSVGRAST_H
-
-#include "nanosvg.h"
-
-#ifndef NANOSVGRAST_CPLUSPLUS
-#ifdef __cplusplus
-extern "C" {
-#endif
-#endif
-
-typedef struct NSVGrasterizer NSVGrasterizer;
-
-/* Example Usage:
- // Load SVG
- NSVGimage* image;
- image = nsvgParseFromFile("test.svg", "px", 96);
-
- // Create rasterizer (can be used to render multiple images).
- struct NSVGrasterizer* rast = nsvgCreateRasterizer();
- // Allocate memory for image
- unsigned char* img = malloc(w*h*4);
- // Rasterize
- nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);
-*/
-
-// Allocated rasterizer context.
-NSVGrasterizer* nsvgCreateRasterizer(void);
-
-// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha)
-// r - pointer to rasterizer context
-// image - pointer to image to rasterize
-// tx,ty - image offset (applied after scaling)
-// scale - image scale
-// dst - pointer to destination image data, 4 bytes per pixel (RGBA)
-// w - width of the image to render
-// h - height of the image to render
-// stride - number of bytes per scaleline in the destination buffer
-void nsvgRasterize(NSVGrasterizer* r,
- NSVGimage* image, float tx, float ty, float scale,
- unsigned char* dst, int w, int h, int stride);
-
-// Deletes rasterizer context.
-void nsvgDeleteRasterizer(NSVGrasterizer*);
-
-
-#ifndef NANOSVGRAST_CPLUSPLUS
-#ifdef __cplusplus
-}
-#endif
-#endif
-
-#ifdef NANOSVGRAST_IMPLEMENTATION
-
-#include
-#include
-#include
-
-#define NSVG__SUBSAMPLES 5
-#define NSVG__FIXSHIFT 10
-#define NSVG__FIX (1 << NSVG__FIXSHIFT)
-#define NSVG__FIXMASK (NSVG__FIX-1)
-#define NSVG__MEMPAGE_SIZE 1024
-
-typedef struct NSVGedge {
- float x0,y0, x1,y1;
- int dir;
- struct NSVGedge* next;
-} NSVGedge;
-
-typedef struct NSVGpoint {
- float x, y;
- float dx, dy;
- float len;
- float dmx, dmy;
- unsigned char flags;
-} NSVGpoint;
-
-typedef struct NSVGactiveEdge {
- int x,dx;
- float ey;
- int dir;
- struct NSVGactiveEdge *next;
-} NSVGactiveEdge;
-
-typedef struct NSVGmemPage {
- unsigned char mem[NSVG__MEMPAGE_SIZE];
- int size;
- struct NSVGmemPage* next;
-} NSVGmemPage;
-
-typedef struct NSVGcachedPaint {
- char type;
- char spread;
- float xform[6];
- unsigned int colors[256];
-} NSVGcachedPaint;
-
-struct NSVGrasterizer
-{
- float px, py;
-
- float tessTol;
- float distTol;
-
- NSVGedge* edges;
- int nedges;
- int cedges;
-
- NSVGpoint* points;
- int npoints;
- int cpoints;
-
- NSVGpoint* points2;
- int npoints2;
- int cpoints2;
-
- NSVGactiveEdge* freelist;
- NSVGmemPage* pages;
- NSVGmemPage* curpage;
-
- unsigned char* scanline;
- int cscanline;
-
- unsigned char* bitmap;
- int width, height, stride;
-};
-
-NSVGrasterizer* nsvgCreateRasterizer(void)
-{
- NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer));
- if (r == NULL) goto error;
- memset(r, 0, sizeof(NSVGrasterizer));
-
- r->tessTol = 0.25f;
- r->distTol = 0.01f;
-
- return r;
-
-error:
- nsvgDeleteRasterizer(r);
- return NULL;
-}
-
-void nsvgDeleteRasterizer(NSVGrasterizer* r)
-{
- NSVGmemPage* p;
-
- if (r == NULL) return;
-
- p = r->pages;
- while (p != NULL) {
- NSVGmemPage* next = p->next;
- free(p);
- p = next;
- }
-
- if (r->edges) free(r->edges);
- if (r->points) free(r->points);
- if (r->points2) free(r->points2);
- if (r->scanline) free(r->scanline);
-
- free(r);
-}
-
-static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
-{
- NSVGmemPage *newp;
-
- // If using existing chain, return the next page in chain
- if (cur != NULL && cur->next != NULL) {
- return cur->next;
- }
-
- // Alloc new page
- newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage));
- if (newp == NULL) return NULL;
- memset(newp, 0, sizeof(NSVGmemPage));
-
- // Add to linked list
- if (cur != NULL)
- cur->next = newp;
- else
- r->pages = newp;
-
- return newp;
-}
-
-static void nsvg__resetPool(NSVGrasterizer* r)
-{
- NSVGmemPage* p = r->pages;
- while (p != NULL) {
- p->size = 0;
- p = p->next;
- }
- r->curpage = r->pages;
-}
-
-static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size)
-{
- unsigned char* buf;
- if (size > NSVG__MEMPAGE_SIZE) return NULL;
- if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
- r->curpage = nsvg__nextPage(r, r->curpage);
- }
- buf = &r->curpage->mem[r->curpage->size];
- r->curpage->size += size;
- return buf;
-}
-
-static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
-{
- float dx = x2 - x1;
- float dy = y2 - y1;
- return dx*dx + dy*dy < tol*tol;
-}
-
-static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
-{
- NSVGpoint* pt;
-
- if (r->npoints > 0) {
- pt = &r->points[r->npoints-1];
- if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
- pt->flags = (unsigned char)(pt->flags | flags);
- return;
- }
- }
-
- if (r->npoints+1 > r->cpoints) {
- r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
- r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
- if (r->points == NULL) return;
- }
-
- pt = &r->points[r->npoints];
- pt->x = x;
- pt->y = y;
- pt->flags = (unsigned char)flags;
- r->npoints++;
-}
-
-static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt)
-{
- if (r->npoints+1 > r->cpoints) {
- r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
- r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
- if (r->points == NULL) return;
- }
- r->points[r->npoints] = pt;
- r->npoints++;
-}
-
-static void nsvg__duplicatePoints(NSVGrasterizer* r)
-{
- if (r->npoints > r->cpoints2) {
- r->cpoints2 = r->npoints;
- r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2);
- if (r->points2 == NULL) return;
- }
-
- memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints);
- r->npoints2 = r->npoints;
-}
-
-static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1)
-{
- NSVGedge* e;
-
- // Skip horizontal edges
- if (y0 == y1)
- return;
-
- if (r->nedges+1 > r->cedges) {
- r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
- r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges);
- if (r->edges == NULL) return;
- }
-
- e = &r->edges[r->nedges];
- r->nedges++;
-
- if (y0 < y1) {
- e->x0 = x0;
- e->y0 = y0;
- e->x1 = x1;
- e->y1 = y1;
- e->dir = 1;
- } else {
- e->x0 = x1;
- e->y0 = y1;
- e->x1 = x0;
- e->y1 = y0;
- e->dir = -1;
- }
-}
-
-static float nsvg__normalize(float *x, float* y)
-{
- float d = sqrtf((*x)*(*x) + (*y)*(*y));
- if (d > 1e-6f) {
- float id = 1.0f / d;
- *x *= id;
- *y *= id;
- }
- return d;
-}
-
-static float nsvg__absf(float x) { return x < 0 ? -x : x; }
-
-static void nsvg__flattenCubicBez(NSVGrasterizer* r,
- float x1, float y1, float x2, float y2,
- float x3, float y3, float x4, float y4,
- int level, int type)
-{
- float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
- float dx,dy,d2,d3;
-
- if (level > 10) return;
-
- x12 = (x1+x2)*0.5f;
- y12 = (y1+y2)*0.5f;
- x23 = (x2+x3)*0.5f;
- y23 = (y2+y3)*0.5f;
- x34 = (x3+x4)*0.5f;
- y34 = (y3+y4)*0.5f;
- x123 = (x12+x23)*0.5f;
- y123 = (y12+y23)*0.5f;
-
- dx = x4 - x1;
- dy = y4 - y1;
- d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
- d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
-
- if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
- nsvg__addPathPoint(r, x4, y4, type);
- return;
- }
-
- x234 = (x23+x34)*0.5f;
- y234 = (y23+y34)*0.5f;
- x1234 = (x123+x234)*0.5f;
- y1234 = (y123+y234)*0.5f;
-
- nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
- nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
-}
-
-static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale)
-{
- int i, j;
- NSVGpath* path;
-
- for (path = shape->paths; path != NULL; path = path->next) {
- r->npoints = 0;
- // Flatten path
- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
- for (i = 0; i < path->npts-1; i += 3) {
- float* p = &path->pts[i*2];
- nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0);
- }
- // Close path
- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
- // Build edges
- for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
- nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
- }
-}
-
-enum NSVGpointFlags
-{
- NSVG_PT_CORNER = 0x01,
- NSVG_PT_BEVEL = 0x02,
- NSVG_PT_LEFT = 0x04
-};
-
-static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
-{
- float w = lineWidth * 0.5f;
- float dx = p1->x - p0->x;
- float dy = p1->y - p0->y;
- float len = nsvg__normalize(&dx, &dy);
- float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
- float dlx = dy, dly = -dx;
- float lx = px - dlx*w, ly = py - dly*w;
- float rx = px + dlx*w, ry = py + dly*w;
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
-{
- float w = lineWidth * 0.5f;
- float px = p->x, py = p->y;
- float dlx = dy, dly = -dx;
- float lx = px - dlx*w, ly = py - dly*w;
- float rx = px + dlx*w, ry = py + dly*w;
-
- nsvg__addEdge(r, lx, ly, rx, ry);
-
- if (connect) {
- nsvg__addEdge(r, left->x, left->y, lx, ly);
- nsvg__addEdge(r, rx, ry, right->x, right->y);
- }
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
-{
- float w = lineWidth * 0.5f;
- float px = p->x - dx*w, py = p->y - dy*w;
- float dlx = dy, dly = -dx;
- float lx = px - dlx*w, ly = py - dly*w;
- float rx = px + dlx*w, ry = py + dly*w;
-
- nsvg__addEdge(r, lx, ly, rx, ry);
-
- if (connect) {
- nsvg__addEdge(r, left->x, left->y, lx, ly);
- nsvg__addEdge(r, rx, ry, right->x, right->y);
- }
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-#ifndef NSVG_PI
-#define NSVG_PI (3.14159265358979323846264338327f)
-#endif
-
-static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect)
-{
- int i;
- float w = lineWidth * 0.5f;
- float px = p->x, py = p->y;
- float dlx = dy, dly = -dx;
- float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
-
- for (i = 0; i < ncap; i++) {
- float a = (float)i/(float)(ncap-1)*NSVG_PI;
- float ax = cosf(a) * w, ay = sinf(a) * w;
- float x = px - dlx*ax - dx*ay;
- float y = py - dly*ax - dy*ay;
-
- if (i > 0)
- nsvg__addEdge(r, prevx, prevy, x, y);
-
- prevx = x;
- prevy = y;
-
- if (i == 0) {
- lx = x; ly = y;
- } else if (i == ncap-1) {
- rx = x; ry = y;
- }
- }
-
- if (connect) {
- nsvg__addEdge(r, left->x, left->y, lx, ly);
- nsvg__addEdge(r, rx, ry, right->x, right->y);
- }
-
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
-{
- float w = lineWidth * 0.5f;
- float dlx0 = p0->dy, dly0 = -p0->dx;
- float dlx1 = p1->dy, dly1 = -p1->dx;
- float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
- float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
- float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
- float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
-
- nsvg__addEdge(r, lx0, ly0, left->x, left->y);
- nsvg__addEdge(r, lx1, ly1, lx0, ly0);
-
- nsvg__addEdge(r, right->x, right->y, rx0, ry0);
- nsvg__addEdge(r, rx0, ry0, rx1, ry1);
-
- left->x = lx1; left->y = ly1;
- right->x = rx1; right->y = ry1;
-}
-
-static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
-{
- float w = lineWidth * 0.5f;
- float dlx0 = p0->dy, dly0 = -p0->dx;
- float dlx1 = p1->dy, dly1 = -p1->dx;
- float lx0, rx0, lx1, rx1;
- float ly0, ry0, ly1, ry1;
-
- if (p1->flags & NSVG_PT_LEFT) {
- lx0 = lx1 = p1->x - p1->dmx * w;
- ly0 = ly1 = p1->y - p1->dmy * w;
- nsvg__addEdge(r, lx1, ly1, left->x, left->y);
-
- rx0 = p1->x + (dlx0 * w);
- ry0 = p1->y + (dly0 * w);
- rx1 = p1->x + (dlx1 * w);
- ry1 = p1->y + (dly1 * w);
- nsvg__addEdge(r, right->x, right->y, rx0, ry0);
- nsvg__addEdge(r, rx0, ry0, rx1, ry1);
- } else {
- lx0 = p1->x - (dlx0 * w);
- ly0 = p1->y - (dly0 * w);
- lx1 = p1->x - (dlx1 * w);
- ly1 = p1->y - (dly1 * w);
- nsvg__addEdge(r, lx0, ly0, left->x, left->y);
- nsvg__addEdge(r, lx1, ly1, lx0, ly0);
-
- rx0 = rx1 = p1->x + p1->dmx * w;
- ry0 = ry1 = p1->y + p1->dmy * w;
- nsvg__addEdge(r, right->x, right->y, rx1, ry1);
- }
-
- left->x = lx1; left->y = ly1;
- right->x = rx1; right->y = ry1;
-}
-
-static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap)
-{
- int i, n;
- float w = lineWidth * 0.5f;
- float dlx0 = p0->dy, dly0 = -p0->dx;
- float dlx1 = p1->dy, dly1 = -p1->dx;
- float a0 = atan2f(dly0, dlx0);
- float a1 = atan2f(dly1, dlx1);
- float da = a1 - a0;
- float lx, ly, rx, ry;
-
- if (da < NSVG_PI) da += NSVG_PI*2;
- if (da > NSVG_PI) da -= NSVG_PI*2;
-
- n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
- if (n < 2) n = 2;
- if (n > ncap) n = ncap;
-
- lx = left->x;
- ly = left->y;
- rx = right->x;
- ry = right->y;
-
- for (i = 0; i < n; i++) {
- float u = (float)i/(float)(n-1);
- float a = a0 + u*da;
- float ax = cosf(a) * w, ay = sinf(a) * w;
- float lx1 = p1->x - ax, ly1 = p1->y - ay;
- float rx1 = p1->x + ax, ry1 = p1->y + ay;
-
- nsvg__addEdge(r, lx1, ly1, lx, ly);
- nsvg__addEdge(r, rx, ry, rx1, ry1);
-
- lx = lx1; ly = ly1;
- rx = rx1; ry = ry1;
- }
-
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth)
-{
- float w = lineWidth * 0.5f;
- float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
- float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
-
- nsvg__addEdge(r, lx, ly, left->x, left->y);
- nsvg__addEdge(r, right->x, right->y, rx, ry);
-
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-static int nsvg__curveDivs(float r, float arc, float tol)
-{
- float da = acosf(r / (r + tol)) * 2.0f;
- int divs = (int)ceilf(arc / da);
- if (divs < 2) divs = 2;
- return divs;
-}
-
-static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth)
-{
- int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle.
- NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0};
- NSVGpoint* p0, *p1;
- int j, s, e;
-
- // Build stroke edges
- if (closed) {
- // Looping
- p0 = &points[npoints-1];
- p1 = &points[0];
- s = 0;
- e = npoints;
- } else {
- // Add cap
- p0 = &points[0];
- p1 = &points[1];
- s = 1;
- e = npoints-1;
- }
-
- if (closed) {
- nsvg__initClosed(&left, &right, p0, p1, lineWidth);
- firstLeft = left;
- firstRight = right;
- } else {
- // Add cap
- float dx = p1->x - p0->x;
- float dy = p1->y - p0->y;
- nsvg__normalize(&dx, &dy);
- if (lineCap == NSVG_CAP_BUTT)
- nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
- else if (lineCap == NSVG_CAP_SQUARE)
- nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
- else if (lineCap == NSVG_CAP_ROUND)
- nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
- }
-
- for (j = s; j < e; ++j) {
- if (p1->flags & NSVG_PT_CORNER) {
- if (lineJoin == NSVG_JOIN_ROUND)
- nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
- else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))
- nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
- else
- nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
- } else {
- nsvg__straightJoin(r, &left, &right, p1, lineWidth);
- }
- p0 = p1++;
- }
-
- if (closed) {
- // Loop it
- nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
- nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
- } else {
- // Add cap
- float dx = p1->x - p0->x;
- float dy = p1->y - p0->y;
- nsvg__normalize(&dx, &dy);
- if (lineCap == NSVG_CAP_BUTT)
- nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
- else if (lineCap == NSVG_CAP_SQUARE)
- nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
- else if (lineCap == NSVG_CAP_ROUND)
- nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
- }
-}
-
-static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin)
-{
- int i, j;
- NSVGpoint* p0, *p1;
-
- p0 = &r->points[r->npoints-1];
- p1 = &r->points[0];
- for (i = 0; i < r->npoints; i++) {
- // Calculate segment direction and length
- p0->dx = p1->x - p0->x;
- p0->dy = p1->y - p0->y;
- p0->len = nsvg__normalize(&p0->dx, &p0->dy);
- // Advance
- p0 = p1++;
- }
-
- // calculate joins
- p0 = &r->points[r->npoints-1];
- p1 = &r->points[0];
- for (j = 0; j < r->npoints; j++) {
- float dlx0, dly0, dlx1, dly1, dmr2, cross;
- dlx0 = p0->dy;
- dly0 = -p0->dx;
- dlx1 = p1->dy;
- dly1 = -p1->dx;
- // Calculate extrusions
- p1->dmx = (dlx0 + dlx1) * 0.5f;
- p1->dmy = (dly0 + dly1) * 0.5f;
- dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
- if (dmr2 > 0.000001f) {
- float s2 = 1.0f / dmr2;
- if (s2 > 600.0f) {
- s2 = 600.0f;
- }
- p1->dmx *= s2;
- p1->dmy *= s2;
- }
-
- // Clear flags, but keep the corner.
- p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
-
- // Keep track of left turns.
- cross = p1->dx * p0->dy - p0->dx * p1->dy;
- if (cross > 0.0f)
- p1->flags |= NSVG_PT_LEFT;
-
- // Check to see if the corner needs to be beveled.
- if (p1->flags & NSVG_PT_CORNER) {
- if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {
- p1->flags |= NSVG_PT_BEVEL;
- }
- }
-
- p0 = p1++;
- }
-}
-
-static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale)
-{
- int i, j, closed;
- NSVGpath* path;
- NSVGpoint* p0, *p1;
- float miterLimit = shape->miterLimit;
- int lineJoin = shape->strokeLineJoin;
- int lineCap = shape->strokeLineCap;
- float lineWidth = shape->strokeWidth * scale;
-
- for (path = shape->paths; path != NULL; path = path->next) {
- // Flatten path
- r->npoints = 0;
- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER);
- for (i = 0; i < path->npts-1; i += 3) {
- float* p = &path->pts[i*2];
- nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER);
- }
- if (r->npoints < 2)
- continue;
-
- closed = path->closed;
-
- // If the first and last points are the same, remove the last, mark as closed path.
- p0 = &r->points[r->npoints-1];
- p1 = &r->points[0];
- if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
- r->npoints--;
- p0 = &r->points[r->npoints-1];
- closed = 1;
- }
-
- if (shape->strokeDashCount > 0) {
- int idash = 0, dashState = 1;
- float totalDist = 0, dashLen, allDashLen, dashOffset;
- NSVGpoint cur;
-
- if (closed)
- nsvg__appendPathPoint(r, r->points[0]);
-
- // Duplicate points -> points2.
- nsvg__duplicatePoints(r);
-
- r->npoints = 0;
- cur = r->points2[0];
- nsvg__appendPathPoint(r, cur);
-
- // Figure out dash offset.
- allDashLen = 0;
- for (j = 0; j < shape->strokeDashCount; j++)
- allDashLen += shape->strokeDashArray[j];
- if (shape->strokeDashCount & 1)
- allDashLen *= 2.0f;
- // Find location inside pattern
- dashOffset = fmodf(shape->strokeDashOffset, allDashLen);
- if (dashOffset < 0.0f)
- dashOffset += allDashLen;
-
- while (dashOffset > shape->strokeDashArray[idash]) {
- dashOffset -= shape->strokeDashArray[idash];
- idash = (idash + 1) % shape->strokeDashCount;
- }
- dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale;
-
- for (j = 1; j < r->npoints2; ) {
- float dx = r->points2[j].x - cur.x;
- float dy = r->points2[j].y - cur.y;
- float dist = sqrtf(dx*dx + dy*dy);
-
- if ((totalDist + dist) > dashLen) {
- // Calculate intermediate point
- float d = (dashLen - totalDist) / dist;
- float x = cur.x + dx * d;
- float y = cur.y + dy * d;
- nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);
-
- // Stroke
- if (r->npoints > 1 && dashState) {
- nsvg__prepareStroke(r, miterLimit, lineJoin);
- nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
- }
- // Advance dash pattern
- dashState = !dashState;
- idash = (idash+1) % shape->strokeDashCount;
- dashLen = shape->strokeDashArray[idash] * scale;
- // Restart
- cur.x = x;
- cur.y = y;
- cur.flags = NSVG_PT_CORNER;
- totalDist = 0.0f;
- r->npoints = 0;
- nsvg__appendPathPoint(r, cur);
- } else {
- totalDist += dist;
- cur = r->points2[j];
- nsvg__appendPathPoint(r, cur);
- j++;
- }
- }
- // Stroke any leftover path
- if (r->npoints > 1 && dashState)
- nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
- } else {
- nsvg__prepareStroke(r, miterLimit, lineJoin);
- nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);
- }
- }
-}
-
-static int nsvg__cmpEdge(const void *p, const void *q)
-{
- const NSVGedge* a = (const NSVGedge*)p;
- const NSVGedge* b = (const NSVGedge*)q;
-
- if (a->y0 < b->y0) return -1;
- if (a->y0 > b->y0) return 1;
- return 0;
-}
-
-
-static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint)
-{
- NSVGactiveEdge* z;
-
- if (r->freelist != NULL) {
- // Restore from freelist.
- z = r->freelist;
- r->freelist = z->next;
- } else {
- // Alloc new edge.
- z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge));
- if (z == NULL) return NULL;
- }
-
- float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
-// STBTT_assert(e->y0 <= start_point);
- // round dx down to avoid going too far
- if (dxdy < 0)
- z->dx = (int)(-floorf(NSVG__FIX * -dxdy));
- else
- z->dx = (int)floorf(NSVG__FIX * dxdy);
- z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
-// z->x -= off_x * FIX;
- z->ey = e->y1;
- z->next = 0;
- z->dir = e->dir;
-
- return z;
-}
-
-static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
-{
- z->next = r->freelist;
- r->freelist = z;
-}
-
-static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax)
-{
- int i = x0 >> NSVG__FIXSHIFT;
- int j = x1 >> NSVG__FIXSHIFT;
- if (i < *xmin) *xmin = i;
- if (j > *xmax) *xmax = j;
- if (i < len && j >= 0) {
- if (i == j) {
- // x0,x1 are the same pixel, so compute combined coverage
- scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
- } else {
- if (i >= 0) // add antialiasing for x0
- scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
- else
- i = -1; // clip
-
- if (j < len) // add antialiasing for x1
- scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
- else
- j = len; // clip
-
- for (++i; i < j; ++i) // fill pixels between x0 and x1
- scanline[i] = (unsigned char)(scanline[i] + maxWeight);
- }
- }
-}
-
-// note: this routine clips fills that extend off the edges... ideally this
-// wouldn't happen, but it could happen if the truetype glyph bounding boxes
-// are wrong, or if the user supplies a too-small bitmap
-static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule)
-{
- // non-zero winding fill
- int x0 = 0, w = 0;
-
- if (fillRule == NSVG_FILLRULE_NONZERO) {
- // Non-zero
- while (e != NULL) {
- if (w == 0) {
- // if we're currently at zero, we need to record the edge start point
- x0 = e->x; w += e->dir;
- } else {
- int x1 = e->x; w += e->dir;
- // if we went to zero, we need to draw
- if (w == 0)
- nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
- }
- e = e->next;
- }
- } else if (fillRule == NSVG_FILLRULE_EVENODD) {
- // Even-odd
- while (e != NULL) {
- if (w == 0) {
- // if we're currently at zero, we need to record the edge start point
- x0 = e->x; w = 1;
- } else {
- int x1 = e->x; w = 0;
- nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
- }
- e = e->next;
- }
- }
-}
-
-static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
-
-static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
-{
- return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24);
-}
-
-static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u)
-{
- int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
- int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
- int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
- int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
- int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
- return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
-}
-
-static unsigned int nsvg__applyOpacity(unsigned int c, float u)
-{
- int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
- int r = (c) & 0xff;
- int g = (c>>8) & 0xff;
- int b = (c>>16) & 0xff;
- int a = (((c>>24) & 0xff)*iu) >> 8;
- return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
-}
-
-static inline int nsvg__div255(int x)
-{
- return ((x+1) * 257) >> 16;
-}
-
-static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y,
- float tx, float ty, float scale, NSVGcachedPaint* cache)
-{
-
- if (cache->type == NSVG_PAINT_COLOR) {
- int i, cr, cg, cb, ca;
- cr = cache->colors[0] & 0xff;
- cg = (cache->colors[0] >> 8) & 0xff;
- cb = (cache->colors[0] >> 16) & 0xff;
- ca = (cache->colors[0] >> 24) & 0xff;
-
- for (i = 0; i < count; i++) {
- int r,g,b;
- int a = nsvg__div255((int)cover[0] * ca);
- int ia = 255 - a;
- // Premultiply
- r = nsvg__div255(cr * a);
- g = nsvg__div255(cg * a);
- b = nsvg__div255(cb * a);
-
- // Blend over
- r += nsvg__div255(ia * (int)dst[0]);
- g += nsvg__div255(ia * (int)dst[1]);
- b += nsvg__div255(ia * (int)dst[2]);
- a += nsvg__div255(ia * (int)dst[3]);
-
- dst[0] = (unsigned char)r;
- dst[1] = (unsigned char)g;
- dst[2] = (unsigned char)b;
- dst[3] = (unsigned char)a;
-
- cover++;
- dst += 4;
- }
- } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {
- // TODO: spread modes.
- // TODO: plenty of opportunities to optimize.
- float fx, fy, dx, gy;
- float* t = cache->xform;
- int i, cr, cg, cb, ca;
- unsigned int c;
-
- fx = ((float)x - tx) / scale;
- fy = ((float)y - ty) / scale;
- dx = 1.0f / scale;
-
- for (i = 0; i < count; i++) {
- int r,g,b,a,ia;
- gy = fx*t[1] + fy*t[3] + t[5];
- c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
- cr = (c) & 0xff;
- cg = (c >> 8) & 0xff;
- cb = (c >> 16) & 0xff;
- ca = (c >> 24) & 0xff;
-
- a = nsvg__div255((int)cover[0] * ca);
- ia = 255 - a;
-
- // Premultiply
- r = nsvg__div255(cr * a);
- g = nsvg__div255(cg * a);
- b = nsvg__div255(cb * a);
-
- // Blend over
- r += nsvg__div255(ia * (int)dst[0]);
- g += nsvg__div255(ia * (int)dst[1]);
- b += nsvg__div255(ia * (int)dst[2]);
- a += nsvg__div255(ia * (int)dst[3]);
-
- dst[0] = (unsigned char)r;
- dst[1] = (unsigned char)g;
- dst[2] = (unsigned char)b;
- dst[3] = (unsigned char)a;
-
- cover++;
- dst += 4;
- fx += dx;
- }
- } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {
- // TODO: spread modes.
- // TODO: plenty of opportunities to optimize.
- // TODO: focus (fx,fy)
- float fx, fy, dx, gx, gy, gd;
- float* t = cache->xform;
- int i, cr, cg, cb, ca;
- unsigned int c;
-
- fx = ((float)x - tx) / scale;
- fy = ((float)y - ty) / scale;
- dx = 1.0f / scale;
-
- for (i = 0; i < count; i++) {
- int r,g,b,a,ia;
- gx = fx*t[0] + fy*t[2] + t[4];
- gy = fx*t[1] + fy*t[3] + t[5];
- gd = sqrtf(gx*gx + gy*gy);
- c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
- cr = (c) & 0xff;
- cg = (c >> 8) & 0xff;
- cb = (c >> 16) & 0xff;
- ca = (c >> 24) & 0xff;
-
- a = nsvg__div255((int)cover[0] * ca);
- ia = 255 - a;
-
- // Premultiply
- r = nsvg__div255(cr * a);
- g = nsvg__div255(cg * a);
- b = nsvg__div255(cb * a);
-
- // Blend over
- r += nsvg__div255(ia * (int)dst[0]);
- g += nsvg__div255(ia * (int)dst[1]);
- b += nsvg__div255(ia * (int)dst[2]);
- a += nsvg__div255(ia * (int)dst[3]);
-
- dst[0] = (unsigned char)r;
- dst[1] = (unsigned char)g;
- dst[2] = (unsigned char)b;
- dst[3] = (unsigned char)a;
-
- cover++;
- dst += 4;
- fx += dx;
- }
- }
-}
-
-static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule)
-{
- NSVGactiveEdge *active = NULL;
- int y, s;
- int e = 0;
- int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline
- int xmin, xmax;
-
- for (y = 0; y < r->height; y++) {
- memset(r->scanline, 0, r->width);
- xmin = r->width;
- xmax = 0;
- for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
- // find center of pixel for this scanline
- float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
- NSVGactiveEdge **step = &active;
-
- // update all active edges;
- // remove all active edges that terminate before the center of this scanline
- while (*step) {
- NSVGactiveEdge *z = *step;
- if (z->ey <= scany) {
- *step = z->next; // delete from list
-// NSVG__assert(z->valid);
- nsvg__freeActive(r, z);
- } else {
- z->x += z->dx; // advance to position for current scanline
- step = &((*step)->next); // advance through list
- }
- }
-
- // resort the list if needed
- for (;;) {
- int changed = 0;
- step = &active;
- while (*step && (*step)->next) {
- if ((*step)->x > (*step)->next->x) {
- NSVGactiveEdge* t = *step;
- NSVGactiveEdge* q = t->next;
- t->next = q->next;
- q->next = t;
- *step = q;
- changed = 1;
- }
- step = &(*step)->next;
- }
- if (!changed) break;
- }
-
- // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
- while (e < r->nedges && r->edges[e].y0 <= scany) {
- if (r->edges[e].y1 > scany) {
- NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
- if (z == NULL) break;
- // find insertion point
- if (active == NULL) {
- active = z;
- } else if (z->x < active->x) {
- // insert at front
- z->next = active;
- active = z;
- } else {
- // find thing to insert AFTER
- NSVGactiveEdge* p = active;
- while (p->next && p->next->x < z->x)
- p = p->next;
- // at this point, p->next->x is NOT < z->x
- z->next = p->next;
- p->next = z;
- }
- }
- e++;
- }
-
- // now process all active edges in non-zero fashion
- if (active != NULL)
- nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);
- }
- // Blit
- if (xmin < 0) xmin = 0;
- if (xmax > r->width-1) xmax = r->width-1;
- if (xmin <= xmax) {
- nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache);
- }
- }
-
-}
-
-static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
-{
- int x,y;
-
- // Unpremultiply
- for (y = 0; y < h; y++) {
- unsigned char *row = &image[y*stride];
- for (x = 0; x < w; x++) {
- int r = row[0], g = row[1], b = row[2], a = row[3];
- if (a != 0) {
- row[0] = (unsigned char)(r*255/a);
- row[1] = (unsigned char)(g*255/a);
- row[2] = (unsigned char)(b*255/a);
- }
- row += 4;
- }
- }
-
- // Defringe
- for (y = 0; y < h; y++) {
- unsigned char *row = &image[y*stride];
- for (x = 0; x < w; x++) {
- int r = 0, g = 0, b = 0, a = row[3], n = 0;
- if (a == 0) {
- if (x-1 > 0 && row[-1] != 0) {
- r += row[-4];
- g += row[-3];
- b += row[-2];
- n++;
- }
- if (x+1 < w && row[7] != 0) {
- r += row[4];
- g += row[5];
- b += row[6];
- n++;
- }
- if (y-1 > 0 && row[-stride+3] != 0) {
- r += row[-stride];
- g += row[-stride+1];
- b += row[-stride+2];
- n++;
- }
- if (y+1 < h && row[stride+3] != 0) {
- r += row[stride];
- g += row[stride+1];
- b += row[stride+2];
- n++;
- }
- if (n > 0) {
- row[0] = (unsigned char)(r/n);
- row[1] = (unsigned char)(g/n);
- row[2] = (unsigned char)(b/n);
- }
- }
- row += 4;
- }
- }
-}
-
-
-static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity)
-{
- int i, j;
- NSVGgradient* grad;
-
- cache->type = paint->type;
-
- if (paint->type == NSVG_PAINT_COLOR) {
- cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
- return;
- }
-
- grad = paint->gradient;
-
- cache->spread = grad->spread;
- memcpy(cache->xform, grad->xform, sizeof(float)*6);
-
- if (grad->nstops == 0) {
- for (i = 0; i < 256; i++)
- cache->colors[i] = 0;
- } if (grad->nstops == 1) {
- for (i = 0; i < 256; i++)
- cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
- } else {
- unsigned int ca, cb = 0;
- float ua, ub, du, u;
- int ia, ib, count;
-
- ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
- ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
- ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
- ia = (int)(ua * 255.0f);
- ib = (int)(ub * 255.0f);
- for (i = 0; i < ia; i++) {
- cache->colors[i] = ca;
- }
-
- for (i = 0; i < grad->nstops-1; i++) {
- ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
- cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
- ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
- ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
- ia = (int)(ua * 255.0f);
- ib = (int)(ub * 255.0f);
- count = ib - ia;
- if (count <= 0) continue;
- u = 0;
- du = 1.0f / (float)count;
- for (j = 0; j < count; j++) {
- cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
- u += du;
- }
- }
-
- for (i = ib; i < 256; i++)
- cache->colors[i] = cb;
- }
-
-}
-
-/*
-static void dumpEdges(NSVGrasterizer* r, const char* name)
-{
- float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
- NSVGedge *e = NULL;
- int i;
- if (r->nedges == 0) return;
- FILE* fp = fopen(name, "w");
- if (fp == NULL) return;
-
- xmin = xmax = r->edges[0].x0;
- ymin = ymax = r->edges[0].y0;
- for (i = 0; i < r->nedges; i++) {
- e = &r->edges[i];
- xmin = nsvg__minf(xmin, e->x0);
- xmin = nsvg__minf(xmin, e->x1);
- xmax = nsvg__maxf(xmax, e->x0);
- xmax = nsvg__maxf(xmax, e->x1);
- ymin = nsvg__minf(ymin, e->y0);
- ymin = nsvg__minf(ymin, e->y1);
- ymax = nsvg__maxf(ymax, e->y0);
- ymax = nsvg__maxf(ymax, e->y1);
- }
-
- fprintf(fp, "");
- fclose(fp);
-}
-*/
-
-void nsvgRasterize(NSVGrasterizer* r,
- NSVGimage* image, float tx, float ty, float scale,
- unsigned char* dst, int w, int h, int stride)
-{
- NSVGshape *shape = NULL;
- NSVGedge *e = NULL;
- NSVGcachedPaint cache;
- int i;
-
- r->bitmap = dst;
- r->width = w;
- r->height = h;
- r->stride = stride;
-
- if (w > r->cscanline) {
- r->cscanline = w;
- r->scanline = (unsigned char*)realloc(r->scanline, w);
- if (r->scanline == NULL) return;
- }
-
- for (i = 0; i < h; i++)
- memset(&dst[i*stride], 0, w*4);
-
- for (shape = image->shapes; shape != NULL; shape = shape->next) {
- if (!(shape->flags & NSVG_FLAGS_VISIBLE))
- continue;
-
- if (shape->fill.type != NSVG_PAINT_NONE) {
- nsvg__resetPool(r);
- r->freelist = NULL;
- r->nedges = 0;
-
- nsvg__flattenShape(r, shape, scale);
-
- // Scale and translate edges
- for (i = 0; i < r->nedges; i++) {
- e = &r->edges[i];
- e->x0 = tx + e->x0;
- e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
- e->x1 = tx + e->x1;
- e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
- }
-
- // Rasterize edges
- if (r->nedges != 0)
- qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
-
- // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
- nsvg__initPaint(&cache, &shape->fill, shape->opacity);
-
- nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule);
- }
- if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
- nsvg__resetPool(r);
- r->freelist = NULL;
- r->nedges = 0;
-
- nsvg__flattenShapeStroke(r, shape, scale);
-
-// dumpEdges(r, "edge.svg");
-
- // Scale and translate edges
- for (i = 0; i < r->nedges; i++) {
- e = &r->edges[i];
- e->x0 = tx + e->x0;
- e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
- e->x1 = tx + e->x1;
- e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
- }
-
- // Rasterize edges
- if (r->nedges != 0)
- qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
-
- // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
- nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
-
- nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
- }
- }
-
- nsvg__unpremultiplyAlpha(dst, w, h, stride);
-
- r->bitmap = NULL;
- r->width = 0;
- r->height = 0;
- r->stride = 0;
-}
-
-#endif // NANOSVGRAST_IMPLEMENTATION
-
-#endif // NANOSVGRAST_H
diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c
index 6318931cc..88438c9b0 100644
--- a/src/platforms/rcore_android.c
+++ b/src/platforms/rcore_android.c
@@ -704,7 +704,6 @@ void PollInputEvents(void)
}
}
-
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c
index c6685846c..d42274d14 100644
--- a/src/platforms/rcore_desktop_glfw.c
+++ b/src/platforms/rcore_desktop_glfw.c
@@ -1234,7 +1234,6 @@ void PollInputEvents(void)
glfwSetWindowShouldClose(platform.handle, GLFW_FALSE);
}
-
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
@@ -1447,7 +1446,7 @@ int InitPlatform(void)
}
}
- TRACELOG(LOG_WARNING, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
+ TRACELOG(LOG_INFO, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
// NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example,
// for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3),
diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c
index ef01820cb..20bff2128 100644
--- a/src/platforms/rcore_desktop_rgfw.c
+++ b/src/platforms/rcore_desktop_rgfw.c
@@ -1,6 +1,6 @@
/**********************************************************************************************
*
-* rcore_desktop_rgfw template - Functions to manage window, graphics device and inputs
+* rcore_desktop_rgfw - Functions to manage window, graphics device and inputs
*
* PLATFORM: RGFW
* - Windows (Win32, Win64)
@@ -69,6 +69,7 @@ void CloseWindow(void);
#define CloseWindow CloseWindow_win32
#define ShowCursor __imp_ShowCursor
#define _APISETSTRING_
+ __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
#endif
#if defined(__APPLE__)
@@ -76,8 +77,6 @@ void CloseWindow(void);
#define Size NSSIZE
#endif
-__declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
-
#include "../external/RGFW.h"
#if defined(__WIN32) || defined(__WIN64)
@@ -289,7 +288,6 @@ void SetWindowState(unsigned int flags)
}
if (flags & FLAG_WINDOW_RESIZABLE)
{
- printf("%i %i\n", platform.window->r.w, platform.window->r.h);
RGFW_window_setMaxSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h));
RGFW_window_setMinSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h));
}
@@ -688,7 +686,7 @@ void DisableCursor(void)
{
RGFW_disableCursor = true;
- RGFW_window_mouseHold(platform.window, RGFW_AREA(CORE.Window.screen.width / 2, CORE.Window.screen.height / 2));
+ RGFW_window_mouseHold(platform.window, RGFW_AREA(0, 0));
HideCursor();
}
@@ -872,9 +870,8 @@ void PollInputEvents(void)
//-----------------------------------------------------------------------------
CORE.Window.resizedLastFrame = false;
-
- #define RGFW_HOLD_MOUSE (1L<<2)
- #if defined(RGFW_X11) //|| defined(RGFW_MACOS)
+ CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
+ #define RGFW_HOLD_MOUSE (1L<<2)
if (platform.window->_winArgs & RGFW_HOLD_MOUSE)
{
CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
@@ -884,11 +881,9 @@ void PollInputEvents(void)
{
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
}
-#endif
while (RGFW_window_checkEvent(platform.window))
{
-
if ((platform.window->event.type >= RGFW_jsButtonPressed) && (platform.window->event.type <= RGFW_jsAxisMove))
{
if (!CORE.Input.Gamepad.ready[platform.window->event.joystick])
@@ -1030,15 +1025,8 @@ void PollInputEvents(void)
{
if (platform.window->_winArgs & RGFW_HOLD_MOUSE)
{
- CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
-
- if (event->point.x)
- CORE.Input.Mouse.previousPosition.x = CORE.Input.Mouse.currentPosition.x;
- if (event->point.y)
- CORE.Input.Mouse.previousPosition.y = CORE.Input.Mouse.currentPosition.y;
-
- CORE.Input.Mouse.currentPosition.x = (float)event->point.x;
- CORE.Input.Mouse.currentPosition.y = (float)event->point.y;
+ CORE.Input.Mouse.currentPosition.x += (float)event->point.x;
+ CORE.Input.Mouse.currentPosition.y += (float)event->point.y;
}
else
{
@@ -1205,7 +1193,6 @@ void PollInputEvents(void)
//-----------------------------------------------------------------------------
}
-
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
@@ -1262,7 +1249,6 @@ int InitPlatform(void)
*/
SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
-
if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
RGFW_window_makeCurrent(platform.window);
diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c
index 794f9e6a0..90372c2f6 100644
--- a/src/platforms/rcore_desktop_sdl.c
+++ b/src/platforms/rcore_desktop_sdl.c
@@ -57,6 +57,13 @@
#include "SDL_opengl.h" // SDL OpenGL functionality (if required, instead of internal renderer)
#endif
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#ifndef MAX_CLIPBOARD_BUFFER_LENGTH
+ #define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText()
+#endif
+
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
@@ -852,10 +859,22 @@ void SetClipboardText(const char *text)
}
// Get clipboard text content
-// NOTE: returned string must be freed with SDL_free()
const char *GetClipboardText(void)
{
- return SDL_GetClipboardText();
+ static char buffer[MAX_CLIPBOARD_BUFFER_LENGTH] = { 0 };
+
+ char *clipboard = SDL_GetClipboardText();
+
+ int clipboardSize = snprintf(buffer, sizeof(buffer), "%s", clipboard);
+ if (clipboardSize >= MAX_CLIPBOARD_BUFFER_LENGTH)
+ {
+ char *truncate = buffer + MAX_CLIPBOARD_BUFFER_LENGTH - 4;
+ sprintf(truncate, "...");
+ }
+
+ SDL_free(clipboard);
+
+ return buffer;
}
// Show mouse cursor
@@ -1589,8 +1608,8 @@ int InitPlatform(void)
// Initialize storage system
//----------------------------------------------------------------------------
// Define base path for storage
- CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();
- CHDIR(CORE.Storage.basePath);
+ CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();
+ CHDIR(CORE.Storage.basePath);
//----------------------------------------------------------------------------
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully");
diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c
index ee2875838..e77457b1b 100644
--- a/src/platforms/rcore_drm.c
+++ b/src/platforms/rcore_drm.c
@@ -1480,7 +1480,6 @@ static void ConfigureEvdevDevice(char *device)
TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
}
-
if (TEST_BIT(evBits, EV_KEY))
{
// The first 32 keys as defined in input-event-codes.h are pretty much
diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c
index 938f4ed7d..6bc3432eb 100644
--- a/src/platforms/rcore_template.c
+++ b/src/platforms/rcore_template.c
@@ -430,7 +430,6 @@ void PollInputEvents(void)
// TODO: Poll input events for current platform
}
-
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c
index ff7a92dbc..35c15a6b6 100644
--- a/src/platforms/rcore_web.c
+++ b/src/platforms/rcore_web.c
@@ -935,7 +935,6 @@ void PollInputEvents(void)
// so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed!
//for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 };
-
// Gamepad support using emscripten API
// NOTE: GLFW3 joystick functionality not available in web
diff --git a/src/raylib.h b/src/raylib.h
index 08121c50c..e0c74af30 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -1312,7 +1312,6 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2);
// NOTE: These functions do not require GPU access
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
-RLAPI Image LoadImageSvg(const char *fileNameOrString, int width, int height); // Load image from SVG file data or string with specified size
RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data)
RLAPI Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames); // Load image sequence from memory buffer
RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png'
diff --git a/src/rcamera.h b/src/rcamera.h
index c7f6fed3a..bd2b36e03 100644
--- a/src/rcamera.h
+++ b/src/rcamera.h
@@ -162,7 +162,6 @@ RLAPI Matrix GetCameraProjectionMatrix(Camera* camera, float aspect);
#endif // RCAMERA_H
-
/***********************************************************************************
*
* CAMERA IMPLEMENTATION
@@ -444,11 +443,17 @@ void UpdateCamera(Camera *camera, int mode)
bool lockView = ((mode == CAMERA_FREE) || (mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL));
bool rotateUp = false;
+ // Camera speeds based on frame time
+ float cameraMoveSpeed = CAMERA_MOVE_SPEED*GetFrameTime();
+ float cameraRotationSpeed = CAMERA_ROTATION_SPEED*GetFrameTime();
+ float cameraPanSpeed = CAMERA_PAN_SPEED*GetFrameTime();
+ float cameraOrbitalSpeed = CAMERA_ORBITAL_SPEED*GetFrameTime();
+
if (mode == CAMERA_CUSTOM) {}
else if (mode == CAMERA_ORBITAL)
{
// Orbital can just orbit
- Matrix rotation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED*GetFrameTime());
+ Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed);
Vector3 view = Vector3Subtract(camera->position, camera->target);
view = Vector3Transform(view, rotation);
camera->position = Vector3Add(camera->target, view);
@@ -456,22 +461,22 @@ void UpdateCamera(Camera *camera, int mode)
else
{
// Camera rotation
- if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);
- if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);
- if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget);
- if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget);
- if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED);
- if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED);
+ if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp);
+ if (IsKeyDown(KEY_UP)) CameraPitch(camera, cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp);
+ if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -cameraRotationSpeed, rotateAroundTarget);
+ if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, cameraRotationSpeed, rotateAroundTarget);
+ if (IsKeyDown(KEY_Q)) CameraRoll(camera, -cameraRotationSpeed);
+ if (IsKeyDown(KEY_E)) CameraRoll(camera, cameraRotationSpeed);
// Camera movement
// Camera pan (for CAMERA_FREE)
if ((mode == CAMERA_FREE) && (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE)))
{
const Vector2 mouseDelta = GetMouseDelta();
- if (mouseDelta.x > 0.0f) CameraMoveRight(camera, CAMERA_PAN_SPEED, moveInWorldPlane);
- if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -CAMERA_PAN_SPEED, moveInWorldPlane);
- if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -CAMERA_PAN_SPEED);
- if (mouseDelta.y < 0.0f) CameraMoveUp(camera, CAMERA_PAN_SPEED);
+ if (mouseDelta.x > 0.0f) CameraMoveRight(camera, cameraPanSpeed, moveInWorldPlane);
+ if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -cameraPanSpeed, moveInWorldPlane);
+ if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -cameraPanSpeed);
+ if (mouseDelta.y < 0.0f) CameraMoveUp(camera, cameraPanSpeed);
}
else
{
@@ -481,7 +486,6 @@ void UpdateCamera(Camera *camera, int mode)
}
// Keyboard support
- float cameraMoveSpeed = CAMERA_MOVE_SPEED*GetFrameTime();
if (IsKeyDown(KEY_W)) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane);
if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane);
if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane);
diff --git a/src/rcore.c b/src/rcore.c
index 3cdacbd96..e154d6173 100644
--- a/src/rcore.c
+++ b/src/rcore.c
@@ -578,7 +578,6 @@ const char *TextFormat(const char *text, ...); // Formatting of tex
//void DisableCursor(void)
// Initialize window and OpenGL context
-// NOTE: data parameter could be used to pass any kind of required data to the initialization
void InitWindow(int width, int height, const char *title)
{
TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
diff --git a/src/rlgl.h b/src/rlgl.h
index 843c46a2a..1695c2f56 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -345,15 +345,17 @@
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES
-#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6
+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6
#endif
+
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
#endif
-
+#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -4172,7 +4174,7 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT);
glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2);
-#ifdef RL_SUPPORT_MESH_ANIMATION_VBO
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS);
glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS);
#endif
diff --git a/src/rmodels.c b/src/rmodels.c
index d5c2f9954..92be04fca 100644
--- a/src/rmodels.c
+++ b/src/rmodels.c
@@ -702,7 +702,6 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl
rlPopMatrix();
}
-
// Draw a wired cylinder with base at startPos and top at endPos
// NOTE: It could be also used for pyramid and cone
void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
@@ -1253,9 +1252,11 @@ void UploadMesh(Mesh *mesh, bool dynamic)
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices
+
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0; // Vertex buffer: boneIds
mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0; // Vertex buffer: boneWeights
-
+#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
mesh->vaoId = rlLoadVertexArray();
@@ -1342,7 +1343,7 @@ void UploadMesh(Mesh *mesh, bool dynamic)
rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
}
-#ifdef RL_SUPPORT_MESH_ANIMATION_VBO
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
if (mesh->boneIds != NULL)
{
// Enable vertex attribute: boneIds (shader-location = 6)
@@ -1489,7 +1490,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
// Upload model normal matrix (if locations available)
if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
-#ifdef RL_SUPPORT_MESH_ANIMATION_VBO
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
// Upload Bone Transforms
if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices)
{
@@ -1575,7 +1576,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
}
-#ifdef RL_SUPPORT_MESH_ANIMATION_VBO
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
// Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
{
@@ -1735,7 +1736,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
// Upload model normal matrix (if locations available)
if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
-#ifdef RL_SUPPORT_MESH_ANIMATION_VBO
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
// Upload Bone Transforms
if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices)
{
@@ -1819,7 +1820,8 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
}
-
+
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
// Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
{
@@ -1835,6 +1837,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
}
+#endif
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
}
@@ -2093,7 +2096,6 @@ bool ExportMeshAsCode(Mesh mesh, const char *fileName)
return success;
}
-
#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
// Process obj materials
static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, int materialCount)
@@ -5224,17 +5226,19 @@ static Model LoadGLTF(const char *fileName)
***********************************************************************************************/
// Macro to simplify attributes loading code
- #define LOAD_ATTRIBUTE(accesor, numComp, dataType, dstPtr) \
+ #define LOAD_ATTRIBUTE(accesor, numComp, srcType, dstPtr) LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, srcType)
+
+ #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \
{ \
int n = 0; \
- dataType *buffer = (dataType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(dataType) + accesor->offset/sizeof(dataType); \
+ srcType *buffer = (srcType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(srcType) + accesor->offset/sizeof(srcType); \
for (unsigned int k = 0; k < accesor->count; k++) \
{\
for (int l = 0; l < numComp; l++) \
{\
- dstPtr[numComp*k + l] = buffer[n + l];\
+ dstPtr[numComp*k + l] = (dstType)buffer[n + l];\
}\
- n += (int)(accesor->stride/sizeof(dataType));\
+ n += (int)(accesor->stride/sizeof(srcType));\
}\
}
@@ -5675,8 +5679,6 @@ static Model LoadGLTF(const char *fileName)
else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
}
else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
-
-
}
// NOTE: Attributes related to animations are processed separately
@@ -5697,23 +5699,25 @@ static Model LoadGLTF(const char *fileName)
// Load unsigned short data type into mesh.indices
LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices)
}
+ else if (attribute->component_type == cgltf_component_type_r_8u)
+ {
+ // Init raylib mesh indices to copy glTF attribute data
+ model.meshes[meshIndex].indices = RL_MALLOC(attribute->count * sizeof(unsigned short));
+ LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, unsigned short)
+
+ }
else if (attribute->component_type == cgltf_component_type_r_32u)
{
// Init raylib mesh indices to copy glTF attribute data
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
-
- // Load data into a temp buffer to be converted to raylib data type
- unsigned int *temp = RL_MALLOC(attribute->count*sizeof(unsigned int));
- LOAD_ATTRIBUTE(attribute, 1, unsigned int, temp);
-
- // Convert data to raylib indices data type (unsigned short)
- for (unsigned int d = 0; d < attribute->count; d++) model.meshes[meshIndex].indices[d] = (unsigned short)temp[d];
+ LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short);
TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
-
- RL_FREE(temp);
}
- else TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName);
+ else
+ {
+ TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName);
+ }
}
else model.meshes[meshIndex].triangleCount = model.meshes[meshIndex].vertexCount/3; // Unindexed mesh
@@ -5745,7 +5749,7 @@ static Model LoadGLTF(const char *fileName)
// - Only supports linear interpolation (default method in Blender when checked "Always Sample Animations" when exporting a GLTF file)
// - Only supports translation/rotation/scale animation channel.path, weights not considered (i.e. morph targets)
//----------------------------------------------------------------------------------------------------
- if (data->skins_count == 1)
+ if (data->skins_count > 0)
{
cgltf_skin skin = data->skins[0];
model.bones = LoadBoneInfoGLTF(skin, &model.boneCount);
@@ -5765,9 +5769,9 @@ static Model LoadGLTF(const char *fileName)
MatrixDecompose(worldMatrix, &(model.bindPose[i].translation), &(model.bindPose[i].rotation), &(model.bindPose[i].scale));
}
}
- else if (data->skins_count > 1)
+ if (data->skins_count > 1)
{
- TRACELOG(LOG_ERROR, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count);
+ TRACELOG(LOG_WARNING, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count);
}
meshIndex = 0;
@@ -6088,7 +6092,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
if (result == cgltf_result_success)
{
- if (data->skins_count == 1)
+ if (data->skins_count > 0)
{
cgltf_skin skin = data->skins[0];
*animCount = (int)data->animations_count;
@@ -6223,7 +6227,11 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
RL_FREE(boneChannels);
}
}
- else TRACELOG(LOG_ERROR, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count);
+
+ if (data->skins_count > 1)
+ {
+ TRACELOG(LOG_WARNING, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count);
+ }
cgltf_free(data);
}
diff --git a/src/rshapes.c b/src/rshapes.c
index 66dfbf3b6..e9b5ca87b 100644
--- a/src/rshapes.c
+++ b/src/rshapes.c
@@ -828,8 +828,8 @@ void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color)
{
if ((lineThick > rec.width) || (lineThick > rec.height))
{
- if (rec.width > rec.height) lineThick = rec.height/2;
- else if (rec.width < rec.height) lineThick = rec.width/2;
+ if (rec.width >= rec.height) lineThick = rec.height/2;
+ else if (rec.width <= rec.height) lineThick = rec.width/2;
}
// When rec = { x, y, 8.0f, 6.0f } and lineThick = 2, the following
diff --git a/src/rtext.c b/src/rtext.c
index e4c89d5f1..0595e7fbe 100644
--- a/src/rtext.c
+++ b/src/rtext.c
@@ -1302,15 +1302,15 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
{
byteCounter++;
- int next = 0;
- letter = GetCodepointNext(&text[i], &next);
+ int codepointByteCount = 0;
+ letter = GetCodepointNext(&text[i], &codepointByteCount);
index = GetGlyphIndex(font, letter);
- i += next;
+ i += codepointByteCount;
if (letter != '\n')
{
- if (font.glyphs[index].advanceX != 0) textWidth += font.glyphs[index].advanceX;
+ if (font.glyphs[index].advanceX > 0) textWidth += font.glyphs[index].advanceX;
else textWidth += (font.recs[index].width + font.glyphs[index].offsetX);
}
else
@@ -1930,7 +1930,8 @@ int GetCodepointCount(const char *text)
const char *CodepointToUTF8(int codepoint, int *utf8Size)
{
static char utf8[6] = { 0 };
- int size = 0; // Byte size of codepoint
+ memset(utf8, 0, 6); // Clear static array
+ int size = 0; // Byte size of codepoint
if (codepoint <= 0x7f)
{
diff --git a/src/rtextures.c b/src/rtextures.c
index 6d3c21cf4..84264369d 100644
--- a/src/rtextures.c
+++ b/src/rtextures.c
@@ -225,14 +225,6 @@
#pragma GCC diagnostic pop
#endif
-#if defined(SUPPORT_FILEFORMAT_SVG)
- #define NANOSVG_IMPLEMENTATION // Expands implementation
- #include "external/nanosvg.h"
-
- #define NANOSVGRAST_IMPLEMENTATION
- #include "external/nanosvgrast.h"
-#endif
-
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@@ -335,84 +327,6 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
return image;
}
-// Load an image from a SVG file or string with custom size
-Image LoadImageSvg(const char *fileNameOrString, int width, int height)
-{
- Image image = { 0 };
-
-#if defined(SUPPORT_FILEFORMAT_SVG)
- bool isSvgStringValid = false;
-
- // Validate fileName or string
- if (fileNameOrString != NULL)
- {
- int dataSize = 0;
- unsigned char *fileData = NULL;
-
- if (FileExists(fileNameOrString))
- {
- fileData = LoadFileData(fileNameOrString, &dataSize);
- isSvgStringValid = true;
- }
- else
- {
- // Validate fileData as valid SVG string data
- //