diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml
index 9e87b5870..7a92c208a 100644
--- a/.github/workflows/build_windows.yml
+++ b/.github/workflows/build_windows.yml
@@ -40,10 +40,10 @@ jobs:
ziptarget: "win64"
- compiler: msvc16
ARCH: "x86"
- VSARCHPATH: "Win32"
+ VSARCHPATH: "Win32"
ziptarget: "win32"
- compiler: msvc16
- ARCH: "x64"
+ ARCH: "x64"
VSARCHPATH: "x64"
ziptarget: "win64"
- compiler: msvc16
@@ -61,7 +61,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@master
-
+
- name: Setup Release Version
run: |
echo "RELEASE_NAME=raylib-${{ github.event.release.tag_name }}_${{ matrix.ziptarget }}_${{ matrix.compiler }}" >> $GITHUB_ENV
@@ -69,7 +69,7 @@ jobs:
if: github.event_name == 'release' && github.event.action == 'published'
- name: Setup Environment
- run: |
+ run: |
dir
mkdir build
cd build
@@ -98,7 +98,7 @@ jobs:
if: |
matrix.compiler == 'mingw-w64' &&
matrix.arch == 'i686'
-
+
- name: Build Library (MinGW-w64 64bit)
run: |
cd src
@@ -144,7 +144,7 @@ jobs:
with:
name: ${{ env.RELEASE_NAME }}.zip
path: ./build/${{ env.RELEASE_NAME }}.zip
-
+
- name: Upload Artifact to Release
uses: softprops/action-gh-release@v1
with:
diff --git a/BINDINGS.md b/BINDINGS.md
index 7770f41c2..f2ffaea9e 100644
--- a/BINDINGS.md
+++ b/BINDINGS.md
@@ -31,6 +31,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [rayex](https://github.com/shiryel/rayex) | 3.7 | [elixir](https://elixir-lang.org) | Apache-2.0 |
| [raylib-factor](https://github.com/factor/factor/blob/master/extra/raylib/raylib.factor) | 4.5 | [Factor](https://factorcode.org) | BSD |
| [raylib-freebasic](https://github.com/WIITD/raylib-freebasic) | **5.0** | [FreeBASIC](https://www.freebasic.net) | MIT |
+| [raylib.f](https://github.com/cthulhuology/raylib.f) | **5.5** | [Forth](https://forth.com) | Zlib |
| [fortran-raylib](https://github.com/interkosmos/fortran-raylib) | **5.5** | [Fortran](https://fortran-lang.org) | ISC |
| [raylib-go](https://github.com/gen2brain/raylib-go) | **5.5** | [Go](https://golang.org) | Zlib |
| [raylib-guile](https://github.com/petelliott/raylib-guile) | **auto** | [Guile](https://www.gnu.org/software/guile) | Zlib |
diff --git a/examples/Makefile b/examples/Makefile
index a9732679d..b5e968079 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -486,7 +486,19 @@ endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
# Libraries for DRM compiling
# NOTE: Required packages: libasound2-dev (ALSA)
- LDLIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lgbm -ldrm -ldl -latomic
+ LDLIBS = -lraylib -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl -latomic
+ # TODO: Examples compilation does not define GRAPHICS, is it required?
+ #ifeq ($(GRAPHICS),GRAPHICS_API_OPENGL_ES2)
+ # LDLIBS += -lGLESv2 -lEGL
+ #endif
+endif
+ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32)
+ # Libraries for Windows desktop compilation
+ LDFLAGS += -L..\src
+ LDLIBS = -lraylib -lgdi32 -lwinmm -lshcore
+ ifneq ($(GRAPHICS),GRAPHICS_API_OPENGL_11_SOFTWARE)
+ LDLIBS += -lopengl32
+ endif
endif
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
# Libraries for web (HTML5) compiling
@@ -562,8 +574,11 @@ SHAPES = \
shapes/shapes_following_eyes \
shapes/shapes_kaleidoscope \
shapes/shapes_lines_bezier \
+ shapes/shapes_lines_drawing \
shapes/shapes_logo_raylib \
shapes/shapes_logo_raylib_anim \
+ shapes/shapes_math_angle_rotation \
+ shapes/shapes_math_sine_cosine \
shapes/shapes_mouse_trail \
shapes/shapes_pie_chart \
shapes/shapes_rectangle_advanced \
@@ -631,6 +646,7 @@ MODELS = \
models/models_bone_socket \
models/models_box_collisions \
models/models_cubicmap_rendering \
+ models/models_decals \
models/models_first_person_maze \
models/models_geometric_shapes \
models/models_heightmap_rendering \
@@ -654,6 +670,7 @@ SHADERS = \
shaders/shaders_ascii_rendering \
shaders/shaders_basic_lighting \
shaders/shaders_basic_pbr \
+ shaders/shaders_color_correction \
shaders/shaders_custom_uniform \
shaders/shaders_deferred_rendering \
shaders/shaders_depth_rendering \
@@ -664,6 +681,7 @@ SHADERS = \
shaders/shaders_hybrid_rendering \
shaders/shaders_julia_set \
shaders/shaders_lightmap_rendering \
+ shaders/shaders_mandelbrot_set \
shaders/shaders_mesh_instancing \
shaders/shaders_model_shader \
shaders/shaders_multi_sample2d \
diff --git a/examples/Makefile.Web b/examples/Makefile.Web
index 88843af09..07f8d8fb8 100644
--- a/examples/Makefile.Web
+++ b/examples/Makefile.Web
@@ -562,8 +562,11 @@ SHAPES = \
shapes/shapes_following_eyes \
shapes/shapes_kaleidoscope \
shapes/shapes_lines_bezier \
+ shapes/shapes_lines_drawing \
shapes/shapes_logo_raylib \
shapes/shapes_logo_raylib_anim \
+ shapes/shapes_math_angle_rotation \
+ shapes/shapes_math_sine_cosine \
shapes/shapes_mouse_trail \
shapes/shapes_pie_chart \
shapes/shapes_rectangle_advanced \
@@ -631,6 +634,7 @@ MODELS = \
models/models_bone_socket \
models/models_box_collisions \
models/models_cubicmap_rendering \
+ models/models_decals \
models/models_first_person_maze \
models/models_geometric_shapes \
models/models_heightmap_rendering \
@@ -654,6 +658,7 @@ SHADERS = \
shaders/shaders_ascii_rendering \
shaders/shaders_basic_lighting \
shaders/shaders_basic_pbr \
+ shaders/shaders_color_correction \
shaders/shaders_custom_uniform \
shaders/shaders_deferred_rendering \
shaders/shaders_depth_rendering \
@@ -664,6 +669,7 @@ SHADERS = \
shaders/shaders_hybrid_rendering \
shaders/shaders_julia_set \
shaders/shaders_lightmap_rendering \
+ shaders/shaders_mandelbrot_set \
shaders/shaders_mesh_instancing \
shaders/shaders_model_shader \
shaders/shaders_multi_sample2d \
@@ -892,12 +898,21 @@ shapes/shapes_kaleidoscope: shapes/shapes_kaleidoscope.c
shapes/shapes_lines_bezier: shapes/shapes_lines_bezier.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+shapes/shapes_lines_drawing: shapes/shapes_lines_drawing.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
shapes/shapes_logo_raylib: shapes/shapes_logo_raylib.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
shapes/shapes_logo_raylib_anim: shapes/shapes_logo_raylib_anim.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+shapes/shapes_math_angle_rotation: shapes/shapes_math_angle_rotation.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
+shapes/shapes_math_sine_cosine: shapes/shapes_math_sine_cosine.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
+
shapes/shapes_mouse_trail: shapes/shapes_mouse_trail.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
@@ -1151,6 +1166,12 @@ models/models_cubicmap_rendering: models/models_cubicmap_rendering.c
--preload-file models/resources/cubicmap.png@resources/cubicmap.png \
--preload-file models/resources/cubicmap_atlas.png@resources/cubicmap_atlas.png
+models/models_decals: models/models_decals.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
+ --preload-file models/resources/models/obj/character.obj@resources/models/obj/character.obj \
+ --preload-file models/resources/models/obj/character_diffuse.png@resources/models/obj/character_diffuse.png \
+ --preload-file models/resources/raylib_logo.png@resources/raylib_logo.png
+
models/models_first_person_maze: models/models_first_person_maze.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file models/resources/cubicmap.png@resources/cubicmap.png \
@@ -1256,6 +1277,14 @@ shaders/shaders_basic_pbr: shaders/shaders_basic_pbr.c
--preload-file shaders/resources/road_mra.png@resources/road_mra.png \
--preload-file shaders/resources/road_n.png@resources/road_n.png
+shaders/shaders_color_correction: shaders/shaders_color_correction.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
+ --preload-file shaders/resources/parrots.png@resources/parrots.png \
+ --preload-file shaders/resources/cat.png@resources/cat.png \
+ --preload-file shaders/resources/mandrill.png@resources/mandrill.png \
+ --preload-file shaders/resources/fudesumi.png@resources/fudesumi.png \
+ --preload-file shaders/resources/shaders/glsl100/color_correction.fs@resources/shaders/glsl100/color_correction.fs
+
shaders/shaders_custom_uniform: shaders/shaders_custom_uniform.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file shaders/resources/models/barracks.obj@resources/models/barracks.obj \
@@ -1307,6 +1336,10 @@ shaders/shaders_lightmap_rendering: shaders/shaders_lightmap_rendering.c
--preload-file shaders/resources/cubicmap_atlas.png@resources/cubicmap_atlas.png \
--preload-file shaders/resources/spark_flame.png@resources/spark_flame.png
+shaders/shaders_mandelbrot_set: shaders/shaders_mandelbrot_set.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
+ --preload-file shaders/resources/shaders/glsl100/mandelbrot_set.fs@resources/shaders/glsl100/mandelbrot_set.fs
+
shaders/shaders_mesh_instancing: shaders/shaders_mesh_instancing.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file shaders/resources/shaders/glsl100/lighting_instancing.vs@resources/shaders/glsl100/lighting_instancing.vs \
diff --git a/examples/README.md b/examples/README.md
index b40966a5a..4d0b25d56 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -17,9 +17,9 @@ You may find it easier to use than other toolchains, especially when it comes to
- `zig build [module]` to compile all examples for a module (e.g. `zig build core`)
- `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`)
-## EXAMPLES COLLECTION [TOTAL: 185]
+## EXAMPLES COLLECTION [TOTAL: 192]
-### category: core [44]
+### category: core [45]
Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality.
@@ -69,8 +69,9 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c
| [core_highdpi_testbed](core/core_highdpi_testbed.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_screen_recording](core/core_screen_recording.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_clipboard_text](core/core_clipboard_text.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) |
+| [core_text_file_loading](core/core_text_file_loading.c) |
| ⭐☆☆☆ | 5.5 | 5.6 | [Aanjishnu Bhattacharyya](https://github.com/NimComPoo-04) |
-### category: shapes [31]
+### category: shapes [34]
Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module.
@@ -104,9 +105,12 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes](
| [shapes_pie_chart](shapes/shapes_pie_chart.c) |
| ⭐⭐⭐☆ | 5.5 | 5.6 | [Gideon Serfontein](https://github.com/GideonSerf) |
| [shapes_kaleidoscope](shapes/shapes_kaleidoscope.c) |
| ⭐⭐☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) |
| [shapes_clock_of_clocks](shapes/shapes_clock_of_clocks.c) |
| ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
-| [shapes_mouse_trail](shapes/shapes_mouse_trail.c) |
| ⭐☆☆☆ | 5.6 | 5.6-dev | [[Balamurugan R]](https://github.com/[Bala050814]) |
+| [shapes_math_sine_cosine](shapes/shapes_math_sine_cosine.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) |
+| [shapes_mouse_trail](shapes/shapes_mouse_trail.c) |
| ⭐☆☆☆ | 5.6 | 5.6-dev | [Balamurugan R](https://github.com/Bala050814) |
| [shapes_simple_particles](shapes/shapes_simple_particles.c) |
| ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
| [shapes_starfield_effect](shapes/shapes_starfield_effect.c) |
| ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
+| [shapes_lines_drawing](shapes/shapes_lines_drawing.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6 | [Robin](https://github.com/RobinsAviary) |
+| [shapes_math_angle_rotation](shapes/shapes_math_angle_rotation.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6 | [Kris](https://github.com/krispy-snacc) |
### category: textures [26]
@@ -163,7 +167,7 @@ Examples using raylib text functionality, including sprite fonts loading/generat
| [text_inline_styling](text/text_inline_styling.c) |
| ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Wagner Barongello](https://github.com/SultansOfCode) |
| [text_words_alignment](text/text_words_alignment.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
-### category: models [25]
+### category: models [26]
Examples using raylib models functionality, including models loading/generation and drawing, provided by raylib [models](../src/rmodels.c) module.
@@ -194,8 +198,9 @@ Examples using raylib models functionality, including models loading/generation
| [models_tesseract_view](models/models_tesseract_view.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Timothy van der Valk](https://github.com/arceryz) |
| [models_basic_voxel](models/models_basic_voxel.c) |
| ⭐⭐☆☆ | 5.5 | 5.5 | [Tim Little](https://github.com/timlittle) |
| [models_rotating_cube](models/models_rotating_cube.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) |
+| [models_decals](models/models_decals.c) |
| ⭐⭐⭐⭐️ | 5.6-dev | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
-### category: shaders [30]
+### category: shaders [32]
Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.c) module.
@@ -213,6 +218,8 @@ Examples using raylib shaders functionality, including shaders loading, paramete
| [shaders_texture_outline](shaders/shaders_texture_outline.c) |
| ⭐⭐⭐☆ | 4.0 | 4.0 | [Serenity Skiff](https://github.com/GoldenThumbs) |
| [shaders_texture_waves](shaders/shaders_texture_waves.c) |
| ⭐⭐☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) |
| [shaders_julia_set](shaders/shaders_julia_set.c) |
| ⭐⭐⭐☆ | 2.5 | 4.0 | [Josh Colclough](https://github.com/joshcol9232) |
+| [shaders_mandelbrot_set](shaders/shaders_mandelbrot_set.c) |
| ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
+| [shaders_color_correction](shaders/shaders_color_correction.c) |
| ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
| [shaders_eratosthenes_sieve](shaders/shaders_eratosthenes_sieve.c) |
| ⭐⭐⭐☆ | 2.5 | 4.0 | [ProfJski](https://github.com/ProfJski) |
| [shaders_fog_rendering](shaders/shaders_fog_rendering.c) |
| ⭐⭐⭐☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
| [shaders_simple_mask](shaders/shaders_simple_mask.c) |
| ⭐⭐☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
diff --git a/examples/core/core_3d_camera_first_person.c b/examples/core/core_3d_camera_first_person.c
index 8f4dc70fb..64368c4aa 100644
--- a/examples/core/core_3d_camera_first_person.c
+++ b/examples/core/core_3d_camera_first_person.c
@@ -119,7 +119,6 @@ int main(void)
// Some default standard keyboard/mouse inputs are hardcoded to simplify use
// For advanced camera controls, it's recommended to compute camera movement manually
UpdateCamera(&camera, cameraMode); // Update camera
-
/*
// Camera PRO usage example (EXPERIMENTAL)
// This new camera function allows custom movement/rotation values to be directly provided
diff --git a/examples/core/core_render_texture.c b/examples/core/core_render_texture.c
index 47dc66e0f..e30220a73 100644
--- a/examples/core/core_render_texture.c
+++ b/examples/core/core_render_texture.c
@@ -26,7 +26,7 @@ int main(void)
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - render texture");
-
+
// Define a render texture to render
int renderTextureWidth = 300;
int renderTextureHeight = 300;
@@ -62,14 +62,14 @@ int main(void)
//-----------------------------------------------------
// Draw our scene to the render texture
BeginTextureMode(target);
-
+
ClearBackground(SKYBLUE);
-
+
DrawRectangle(0, 0, 20, 20, RED);
DrawCircleV(ballPosition, (float)ballRadius, MAROON);
-
+
EndTextureMode();
-
+
// Draw render texture to main framebuffer
BeginDrawing();
@@ -77,14 +77,14 @@ int main(void)
// Draw our render texture with rotation applied
// NOTE 1: We set the origin of the texture to the center of the render texture
- // NOTE 2: We flip vertically the texture setting negative source rectangle height
- DrawTexturePro(target.texture,
+ // NOTE 2: We flip vertically the texture setting negative source rectangle height
+ DrawTexturePro(target.texture,
(Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height },
(Rectangle){ screenWidth/2.0f, screenHeight/2.0f, (float)target.texture.width, (float)target.texture.height },
(Vector2){ target.texture.width/2.0f, target.texture.height/2.0f }, rotation, WHITE);
DrawText("DRAWING BOUNCING BALL INSIDE RENDER TEXTURE!", 10, screenHeight - 40, 20, BLACK);
-
+
DrawFPS(10, 10);
diff --git a/examples/core/core_text_file_loading.c b/examples/core/core_text_file_loading.c
index 4b334e811..ed48f7d36 100644
--- a/examples/core/core_text_file_loading.c
+++ b/examples/core/core_text_file_loading.c
@@ -64,7 +64,7 @@ int main(void)
if (lines[i][j] == ' ')
{
// Making a C Style string by adding a '\0' at the required location so that we can use the MeasureText function
- lines[i][j] = '\0';
+ lines[i][j] = '\0';
// Checking if the text has crossed the wrapWidth, then going back and inserting a newline
if (MeasureText(lines[i] + lastWrapStart, fontSize) > wrapWidth)
@@ -88,16 +88,16 @@ int main(void)
for (int i = 0; i < lineCount; i++)
{
- Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2);
- textHeight += size.y + 10;
+ Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2);
+ textHeight += (int)size.y + 10;
}
// A simple scrollbar on the side to show how far we have red into the file
Rectangle scrollBar = {
- .x = screenWidth - 5,
+ .x = (float)screenWidth - 5,
.y = 0,
.width = 5,
- .height = screenHeight*100/(textHeight - screenHeight) // Scrollbar height is just a percentage
+ .height = screenHeight*100.0f/(textHeight - screenHeight) // Scrollbar height is just a percentage
};
SetTargetFPS(60);
@@ -112,13 +112,13 @@ int main(void)
cam.target.y -= scroll*fontSize*1.5f; // Choosing an arbitrary speed for scroll
if (cam.target.y < 0) cam.target.y = 0; // Snapping to 0 if we go too far back
-
- // Ensuring that the camera does not scroll past all text
+
+ // Ensuring that the camera does not scroll past all text
if (cam.target.y > textHeight - screenHeight + textTop)
- cam.target.y = textHeight - screenHeight + textTop;
+ cam.target.y = (float)textHeight - screenHeight + textTop;
// Computing the position of the scrollBar depending on the percentage of text covered
- scrollBar.y = Lerp(textTop, screenHeight - scrollBar.height, (cam.target.y - textTop)/(textHeight - screenHeight));
+ scrollBar.y = Lerp((float)textTop, (float)screenHeight - scrollBar.height, (float)(cam.target.y - textTop)/(textHeight - screenHeight));
//----------------------------------------------------------------------------------
// Draw
@@ -132,13 +132,13 @@ int main(void)
for (int i = 0, t = textTop; i < lineCount; i++)
{
// Each time we go through and calculate the height of the text to move the cursor appropriately
- Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2);
-
+ Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2);
+
DrawText(lines[i], 10, t, fontSize, RED);
- // Inserting extra space for real newlines,
+ // Inserting extra space for real newlines,
// wrapped lines are rendered closer together
- t += size.y + 10;
+ t += (int)size.y + 10;
}
EndMode2D();
diff --git a/examples/examples_list.txt b/examples/examples_list.txt
index 9989f940f..7c8709785 100644
--- a/examples/examples_list.txt
+++ b/examples/examples_list.txt
@@ -51,6 +51,7 @@ core;core_directory_files;★☆☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal
core;core_highdpi_testbed;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
core;core_screen_recording;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
core;core_clipboard_text;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary
+core;core_text_file_loading;★☆☆☆;5.5;5.6;0;0;"Aanjishnu Bhattacharyya";@NimComPoo-04
shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ramon Santamaria";@raysan5
shapes;shapes_bouncing_ball;★☆☆☆;2.5;2.5;2013;2025;"Ramon Santamaria";@raysan5
shapes;shapes_bullet_hell;★☆☆☆;5.6;5.6;2025;2025;"Zero";@zerohorsepower
@@ -79,9 +80,12 @@ shapes;shapes_vector_angle;★★☆☆;1.0;5.0;2023;2025;"Ramon Santamaria";@ra
shapes;shapes_pie_chart;★★★☆;5.5;5.6;2025;2025;"Gideon Serfontein";@GideonSerf
shapes;shapes_kaleidoscope;★★☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal
shapes;shapes_clock_of_clocks;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates
+shapes;shapes_math_sine_cosine;★★☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe
shapes;shapes_mouse_trail;★☆☆☆;5.6;5.6-dev;2025;2025;"Balamurugan R";@Bala050814
shapes;shapes_simple_particles;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
shapes;shapes_starfield_effect;★★☆☆;5.5;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates
+shapes;shapes_lines_drawing;★☆☆☆;5.6-dev;5.6;2025;2025;"Robin";@RobinsAviary
+shapes;shapes_math_angle_rotation;★☆☆☆;5.6-dev;5.6;2025;2025;"Kris";@krispy-snacc
textures;textures_logo_raylib;★☆☆☆;1.0;1.0;2014;2025;"Ramon Santamaria";@raysan5
textures;textures_srcrec_dstrec;★★★☆;1.3;1.3;2015;2025;"Ramon Santamaria";@raysan5
textures;textures_image_drawing;★★☆☆;1.4;1.4;2016;2025;"Ramon Santamaria";@raysan5
@@ -148,6 +152,7 @@ models;models_bone_socket;★★★★;4.5;4.5;2024;2025;"iP";@ipzaur
models;models_tesseract_view;★★☆☆;5.6-dev;5.6-dev;2024;2025;"Timothy van der Valk";@arceryz
models;models_basic_voxel;★★☆☆;5.5;5.5;2025;2025;"Tim Little";@timlittle
models;models_rotating_cube;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Jopestpe";@jopestpe
+models;models_decals;★★★★;5.6-dev;5.6-dev;2025;2025;"JP Mortiboys";@themushroompirates
shaders;shaders_ascii_rendering;★★☆☆;5.5;5.6;2025;2025;"Maicon Santana";@maiconpintoabreu
shaders;shaders_basic_lighting;★★★★;3.0;4.2;2019;2025;"Chris Camacho";@chriscamacho
shaders;shaders_model_shader;★★☆☆;1.3;3.7;2014;2025;"Ramon Santamaria";@raysan5
@@ -160,6 +165,8 @@ shaders;shaders_texture_rendering;★★☆☆;2.0;3.7;2019;2025;"Michał Ciesie
shaders;shaders_texture_outline;★★★☆;4.0;4.0;2021;2025;"Serenity Skiff";@GoldenThumbs
shaders;shaders_texture_waves;★★☆☆;2.5;3.7;2019;2025;"Anata";@anatagawa
shaders;shaders_julia_set;★★★☆;2.5;4.0;2019;2025;"Josh Colclough";@joshcol9232
+shaders;shaders_mandelbrot_set;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
+shaders;shaders_color_correction;★★☆☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
shaders;shaders_eratosthenes_sieve;★★★☆;2.5;4.0;2019;2025;"ProfJski";@ProfJski
shaders;shaders_fog_rendering;★★★☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho
shaders;shaders_simple_mask;★★☆☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho
diff --git a/examples/examples_template.c b/examples/examples_template.c
index 39a19351d..211749e82 100644
--- a/examples/examples_template.c
+++ b/examples/examples_template.c
@@ -36,7 +36,7 @@
10. Have fun!
- The following files must be updated when adding a new example,
+ The following files must be updated when adding a new example,
but it can be automatically done using the raylib provided tool: rexm
So, no worries if just the .c/.png are provided when adding the example.
diff --git a/examples/models/models_decals.c b/examples/models/models_decals.c
new file mode 100644
index 000000000..f556139e1
--- /dev/null
+++ b/examples/models/models_decals.c
@@ -0,0 +1,605 @@
+/*******************************************************************************************
+*
+* raylib [models] example - decals
+*
+* Example complexity rating: [★★★★] 4/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*
+* Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
+* Based on previous work by @mrdoob
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 JP Mortiboys (@themushroompirates) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+
+#include // Required for: memcpy()
+
+#undef FLT_MAX
+#define FLT_MAX 340282346638528859811704183484516925440.0f // Maximum value of a float, from bit pattern 01111111011111111111111111111111
+
+#define MAX_DECALS 256
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct MeshBuilder {
+ int vertexCount;
+ int vertexCapacity;
+ Vector3 *vertices;
+ Vector2 *uvs;
+} MeshBuilder;
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3]);
+static void FreeMeshBuilder(MeshBuilder *mb);
+static Mesh BuildMesh(MeshBuilder *mb);
+static Mesh GenMeshDecal(Model inputModel, Matrix projection, float decalSize, float decalOffset);
+static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s);
+#define FreeDecalMeshData() GenMeshDecal((Model){ .meshCount = -1.0f }, (Matrix){ 0 }, 0.0f, 0.0f)
+static bool GuiButton(Rectangle rec, const char *label);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ SetConfigFlags(FLAG_MSAA_4X_HINT);
+ InitWindow(screenWidth, screenHeight, "raylib [models] example - decals");
+
+ // Define the camera to look into our 3d world
+ Camera camera = { 0 };
+ camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position
+ camera.target = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera looking at point
+ camera.up = (Vector3){ 0.0f, 1.6f, 0.0f }; // Camera up vector (rotation towards target)
+ camera.fovy = 45.0f; // Camera field-of-view Y
+ camera.projection = CAMERA_PERSPECTIVE; // Camera projection type
+
+ // Load character model
+ Model model = LoadModel("resources/models/obj/character.obj");
+
+ // Apply character skin
+ Texture2D modelTexture = LoadTexture("resources/models/obj/character_diffuse.png");
+ SetTextureFilter(modelTexture, TEXTURE_FILTER_BILINEAR);
+ model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = modelTexture;
+
+ BoundingBox modelBBox = GetMeshBoundingBox(model.meshes[0]); // Get mesh bounding box
+
+ camera.target = Vector3Lerp(modelBBox.min, modelBBox.max, 0.5f);
+ camera.position = Vector3Scale(modelBBox.max, 1.0f);
+ camera.position.x *= 0.1f;
+
+ float modelSize = fminf(
+ fminf(fabsf(modelBBox.max.x - modelBBox.min.x), fabsf(modelBBox.max.y - modelBBox.min.y)),
+ fabsf(modelBBox.max.z - modelBBox.min.z));
+
+ camera.position = (Vector3){ 0.0f, modelBBox.max.y*1.2f, modelSize*3.0f };
+
+ float decalSize = modelSize*0.25f;
+ float decalOffset = 0.01f;
+
+ Model placementCube = LoadModelFromMesh(GenMeshCube(decalSize, decalSize, decalSize));
+ placementCube.materials[0].maps[0].color = LIME;
+
+ Material decalMaterial = LoadMaterialDefault();
+ decalMaterial.maps[0].color = YELLOW;
+
+ Image decalImage = LoadImage("resources/raylib_logo.png");
+ ImageResizeNN(&decalImage, decalImage.width/4, decalImage.height/4);
+ Texture decalTexture = LoadTextureFromImage(decalImage);
+ UnloadImage(decalImage);
+
+ SetTextureFilter(decalTexture, TEXTURE_FILTER_BILINEAR);
+ decalMaterial.maps[MATERIAL_MAP_DIFFUSE].texture = decalTexture;
+ decalMaterial.maps[MATERIAL_MAP_DIFFUSE].color = RAYWHITE;
+
+ bool showModel = true;
+ Model decalModels[MAX_DECALS] = { 0 };
+ int decalCount = 0;
+
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) UpdateCamera(&camera, CAMERA_THIRD_PERSON);
+
+ // Display information about closest hit
+ RayCollision collision = { 0 };
+ collision.distance = FLT_MAX;
+ collision.hit = false;
+
+ // Get mouse ray
+ Ray ray = GetScreenToWorldRay(GetMousePosition(), camera);
+
+ // Check ray collision against bounding box first, before trying the full ray-mesh test
+ RayCollision boxHitInfo = GetRayCollisionBox(ray, modelBBox);
+
+ if ((boxHitInfo.hit) && (decalCount < MAX_DECALS))
+ {
+ // Check ray collision against model meshes
+ RayCollision meshHitInfo = { 0 };
+ for (int m = 0; m < model.meshCount; m++)
+ {
+ // NOTE: We consider the model.transform for the collision check but
+ // it can be checked against any transform Matrix, used when checking against same
+ // model drawn multiple times with multiple transforms
+ meshHitInfo = GetRayCollisionMesh(ray, model.meshes[m], model.transform);
+ if (meshHitInfo.hit)
+ {
+ // Save the closest hit mesh
+ if (!collision.hit || (collision.distance > meshHitInfo.distance)) collision = meshHitInfo;
+ }
+ }
+
+ if (meshHitInfo.hit) collision = meshHitInfo;
+ }
+
+ // Add decal to mesh on hit point
+ if (collision.hit && IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (decalCount < MAX_DECALS))
+ {
+ // Create the transformation to project the decal
+ Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f));
+ Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){ 0.0f, 1.0f, 0.0f });
+
+ // Spin the placement around a bit
+ splat = MatrixMultiply(splat, MatrixRotateZ(DEG2RAD*((float)GetRandomValue(-180, 180))));
+
+ Mesh decalMesh = GenMeshDecal(model, splat, decalSize, decalOffset);
+
+ if (decalMesh.vertexCount > 0)
+ {
+ int decalIndex = decalCount++;
+ decalModels[decalIndex] = LoadModelFromMesh(decalMesh);
+ decalModels[decalIndex].materials[0].maps[0] = decalMaterial.maps[0];
+ }
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(RAYWHITE);
+
+ BeginMode3D(camera);
+ // Draw the model at the origin and default scale
+ if (showModel) DrawModel(model, (Vector3){0.0f, 0.0f, 0.0f}, 1.0f, WHITE);
+
+ // Draw the decal models
+ for (int i = 0; i < decalCount; i++) DrawModel(decalModels[i], (Vector3){0}, 1.0f, WHITE);
+
+ // If we hit the mesh, draw the box for the decal
+ if (collision.hit)
+ {
+ Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f));
+ Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){0,1,0});
+ placementCube.transform = MatrixInvert(splat);
+ DrawModel(placementCube, (Vector3){0}, 1.0f, Fade(WHITE, 0.5f));
+ }
+
+ DrawGrid(10, 10.0f);
+ EndMode3D();
+
+ float yPos = 10;
+ float x0 = GetScreenWidth() - 300;
+ float x1 = x0 + 100;
+ float x2 = x1 + 100;
+
+ DrawText("Vertices", x1, yPos, 10, LIME);
+ DrawText("Triangles", x2, yPos, 10, LIME);
+ yPos += 15;
+
+ int vertexCount = 0;
+ int triangleCount = 0;
+
+ for (int i = 0; i < model.meshCount; i++)
+ {
+ vertexCount += model.meshes[i].vertexCount;
+ triangleCount += model.meshes[i].triangleCount;
+ }
+
+ DrawText("Main model", x0, yPos, 10, LIME);
+ DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME);
+ DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME);
+ yPos += 15;
+
+ for (int i = 0; i < decalCount; i++)
+ {
+ if (i == 20)
+ {
+ DrawText("...", x0, yPos, 10, LIME);
+ yPos += 15;
+ }
+
+ if (i < 20)
+ {
+ DrawText(TextFormat("Decal #%d", i+1), x0, yPos, 10, LIME);
+ DrawText(TextFormat("%d", decalModels[i].meshes[0].vertexCount), x1, yPos, 10, LIME);
+ DrawText(TextFormat("%d", decalModels[i].meshes[0].triangleCount), x2, yPos, 10, LIME);
+ yPos += 15;
+ }
+
+ vertexCount += decalModels[i].meshes[0].vertexCount;
+ triangleCount += decalModels[i].meshes[0].triangleCount;
+ }
+
+ DrawText("TOTAL", x0, yPos, 10, LIME);
+ DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME);
+ DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME);
+ yPos += 15;
+
+ DrawText("Hold RMB to move camera", 10, 430, 10, GRAY);
+ DrawText("(c) Character model and texture from kenney.nl", screenWidth - 260, screenHeight - 20, 10, GRAY);
+
+ // UI elements
+ if (GuiButton((Rectangle){ 10, screenHeight - 100, 100, 60 }, showModel ? "Hide Model" : "Show Model")) showModel = !showModel;
+
+ if (GuiButton((Rectangle){ 10 + 110, screenHeight - 100, 100, 60 }, "Clear Decals"))
+ {
+ // Clear decals, unload all decal models
+ for (int i = 0; i < decalCount; i++) UnloadModel(decalModels[i]);
+ decalCount = 0;
+ }
+
+ DrawFPS(10, 10);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadModel(model);
+ UnloadTexture(modelTexture);
+
+ // Unload decal models
+ for (int i = 0; i < decalCount; i++) UnloadModel(decalModels[i]);
+
+ UnloadTexture(decalTexture);
+
+ FreeDecalMeshData(); // Free the data for decal generation
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+// Add triangles to mesh builder (dynamic array manager)
+static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3])
+{
+ // Reallocate and copy if we need to
+ if (mb->vertexCapacity <= (mb->vertexCount + 3))
+ {
+ int newVertexCapacity = (1 + (mb->vertexCapacity/256))*256;
+ Vector3 *newVertices = (Vector3 *)MemAlloc(newVertexCapacity*sizeof(Vector3));
+
+ if (mb->vertexCapacity > 0)
+ {
+ memcpy(newVertices, mb->vertices, mb->vertexCount*sizeof(Vector3));
+ MemFree(mb->vertices);
+ }
+
+ mb->vertices = newVertices;
+ mb->vertexCapacity = newVertexCapacity;
+ }
+
+ // Add 3 vertices
+ int index = mb->vertexCount;
+ mb->vertexCount += 3;
+
+ for (int i = 0; i < 3; i++) mb->vertices[index+i] = vertices[i];
+}
+
+// Free mesh builder
+static void FreeMeshBuilder(MeshBuilder *mb)
+{
+ MemFree(mb->vertices);
+ if (mb->uvs) MemFree(mb->uvs);
+ *mb = (MeshBuilder){ 0 };
+}
+
+// Build a Mesh from MeshBuilder data
+static Mesh BuildMesh(MeshBuilder *mb)
+{
+ Mesh outMesh = { 0 };
+
+ outMesh.vertexCount = mb->vertexCount;
+ outMesh.triangleCount = mb->vertexCount/3;
+ outMesh.vertices = MemAlloc(outMesh.vertexCount*3*sizeof(float));
+ if (mb->uvs) outMesh.texcoords = MemAlloc(outMesh.vertexCount*2*sizeof(float));
+
+ for (int i = 0; i < mb->vertexCount; i++)
+ {
+ outMesh.vertices[3*i+0] = mb->vertices[i].x;
+ outMesh.vertices[3*i+1] = mb->vertices[i].y;
+ outMesh.vertices[3*i+2] = mb->vertices[i].z;
+
+ if (mb->uvs)
+ {
+ outMesh.texcoords[2*i+0] = mb->uvs[i].x;
+ outMesh.texcoords[2*i+1] = mb->uvs[i].y;
+ }
+ }
+
+ UploadMesh(&outMesh, false);
+
+ return outMesh;
+}
+
+// Clip segment
+static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s)
+{
+ float d0 = Vector3DotProduct(v0, p) - s;
+ float d1 = Vector3DotProduct(v1, p) - s;
+ float s0 = d0/(d0 - d1);
+
+ Vector3 position = Vector3Lerp(v0, v1, s0);
+
+ return position;
+}
+
+// Generate mesh decals for provided model
+static Mesh GenMeshDecal(Model target, Matrix projection, float decalSize, float decalOffset)
+{
+ // We're going to use these to build up our decal meshes
+ // They'll resize automatically as we go, we'll free them at the end
+ static MeshBuilder meshBuilders[2] = { 0 };
+
+ // Ugly way of telling us to free the static MeshBuilder data
+ if (target.meshCount == -1)
+ {
+ FreeMeshBuilder(&meshBuilders[0]);
+ FreeMeshBuilder(&meshBuilders[1]);
+ return (Mesh){ 0 };
+ }
+
+ // We're going to need the inverse matrix
+ Matrix invProj = MatrixInvert(projection);
+
+ // Reset the mesh builders
+ meshBuilders[0].vertexCount = 0;
+ meshBuilders[1].vertexCount = 0;
+
+ // We'll be flip-flopping between the two mesh builders
+ // Reading from one and writing to the other, then swapping
+ int mbIndex = 0;
+
+ // First pass, just get any triangle inside the bounding box (for each mesh of the model)
+ for (int meshIndex = 0; meshIndex < target.meshCount; meshIndex++)
+ {
+ Mesh mesh = target.meshes[meshIndex];
+ for (int tri = 0; tri < mesh.triangleCount; tri++)
+ {
+ Vector3 vertices[3] = { 0 };
+
+ // The way we calculate the vertices of the mesh triangle
+ // depend on whether the mesh vertices are indexed or not
+ if (mesh.indices == 0)
+ {
+ for (int v = 0; v < 3; v++)
+ {
+ vertices[v] = (Vector3){
+ mesh.vertices[3*3*tri + 3*v + 0],
+ mesh.vertices[3*3*tri + 3*v + 1],
+ mesh.vertices[3*3*tri + 3*v + 2]
+ };
+ }
+ }
+ else
+ {
+ for (int v = 0; v < 3; v++)
+ {
+ vertices[v] = (Vector3){
+ mesh.vertices[ 3*mesh.indices[3*tri+0] + v],
+ mesh.vertices[ 3*mesh.indices[3*tri+1] + v],
+ mesh.vertices[ 3*mesh.indices[3*tri+2] + v]
+ };
+ }
+ }
+
+ // Transform all 3 vertices of the triangle
+ // and check if they are inside our decal box
+ int insideCount = 0;
+ for (int i = 0; i < 3; i++)
+ {
+ // To projection space
+ Vector3 v = Vector3Transform(vertices[i], projection);
+
+ if ((fabsf(v.x) < decalSize) || (fabsf(v.y) <= decalSize) || (fabsf(v.z) <= decalSize)) insideCount++;
+
+ // We need to keep the transformed vertex
+ vertices[i] = v;
+ }
+
+ // If any of them are inside, we add the triangle - we'll clip it later
+ if (insideCount > 0) AddTriangleToMeshBuilder(&meshBuilders[mbIndex], vertices);
+ }
+ }
+
+ // Clipping time! We need to clip against all 6 directions
+ Vector3 planes[6] = {
+ { 1, 0, 0 },
+ { -1, 0, 0 },
+ { 0, 1, 0 },
+ { 0, -1, 0 },
+ { 0, 0, 1 },
+ { 0, 0, -1 }
+ };
+
+ for (int face = 0; face < 6; face++)
+ {
+ // Swap current model builder (so we read from the one we just wrote to)
+ mbIndex = 1 - mbIndex;
+
+ MeshBuilder *inMesh = &meshBuilders[1 - mbIndex];
+ MeshBuilder *outMesh = &meshBuilders[mbIndex];
+
+ // Reset write builder
+ outMesh->vertexCount = 0;
+
+ float s = 0.5f*decalSize;
+
+ for (int i = 0; i < inMesh->vertexCount; i += 3)
+ {
+ Vector3 nV1, nV2, nV3, nV4;
+
+ float d1 = Vector3DotProduct(inMesh->vertices[ i + 0 ], planes[face] ) - s;
+ float d2 = Vector3DotProduct(inMesh->vertices[ i + 1 ], planes[face] ) - s;
+ float d3 = Vector3DotProduct(inMesh->vertices[ i + 2 ], planes[face] ) - s;
+
+ int v1Out = (d1 > 0);
+ int v2Out = (d2 > 0);
+ int v3Out = (d3 > 0);
+
+ // Calculate, how many vertices of the face lie outside of the clipping plane
+ int total = v1Out + v2Out + v3Out;
+
+ switch (total)
+ {
+ case 0:
+ {
+ // The entire face lies inside of the plane, no clipping needed
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){inMesh->vertices[i], inMesh->vertices[i+1], inMesh->vertices[i+2]});
+ } break;
+ case 1:
+ {
+ // One vertex lies outside of the plane, perform clipping
+ if (v1Out)
+ {
+ nV1 = inMesh->vertices[i + 1];
+ nV2 = inMesh->vertices[i + 2];
+ nV3 = ClipSegment(inMesh->vertices[i], nV1, planes[face], s);
+ nV4 = ClipSegment(inMesh->vertices[i], nV2, planes[face], s);
+ }
+
+ if (v2Out)
+ {
+ nV1 = inMesh->vertices[i];
+ nV2 = inMesh->vertices[i + 2];
+ nV3 = ClipSegment(inMesh->vertices[i + 1], nV1, planes[face], s);
+ nV4 = ClipSegment(inMesh->vertices[i + 1], nV2, planes[face], s);
+
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV3, nV2, nV1});
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV2, nV3, nV4});
+ break;
+ }
+
+ if (v3Out)
+ {
+ nV1 = inMesh->vertices[i];
+ nV2 = inMesh->vertices[i + 1];
+ nV3 = ClipSegment(inMesh->vertices[i + 2], nV1, planes[face], s);
+ nV4 = ClipSegment(inMesh->vertices[i + 2], nV2, planes[face], s);
+ }
+
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV4, nV3, nV2});
+ } break;
+ case 2:
+ {
+ // Two vertices lies outside of the plane, perform clipping
+ if (!v1Out)
+ {
+ nV1 = inMesh->vertices[i];
+ nV2 = ClipSegment(nV1, inMesh->vertices[i + 1], planes[face], s);
+ nV3 = ClipSegment(nV1, inMesh->vertices[i + 2], planes[face], s);
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ }
+
+ if (!v2Out)
+ {
+ nV1 = inMesh->vertices[i + 1];
+ nV2 = ClipSegment(nV1, inMesh->vertices[i + 2], planes[face], s);
+ nV3 = ClipSegment(nV1, inMesh->vertices[i], planes[face], s);
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ }
+
+ if (!v3Out)
+ {
+ nV1 = inMesh->vertices[i + 2];
+ nV2 = ClipSegment(nV1, inMesh->vertices[i], planes[face], s);
+ nV3 = ClipSegment(nV1, inMesh->vertices[i + 1], planes[face], s);
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ }
+ } break;
+ case 3: // The entire face lies outside of the plane, so let's discard the corresponding vertices
+ default: break;
+ }
+ }
+ }
+
+ // Now we just need to re-transform the vertices
+ MeshBuilder *theMesh = &meshBuilders[mbIndex];
+
+ // Allocate room for UVs
+ if (theMesh->vertexCount > 0)
+ {
+ theMesh->uvs = (Vector2 *)MemAlloc(sizeof(Vector2)*theMesh->vertexCount);
+
+ for (int i = 0; i < theMesh->vertexCount; i++)
+ {
+ // Calculate the UVs based on the projected coords
+ // They are clipped to (-decalSize .. decalSize) and we want them (0..1)
+ theMesh->uvs[i].x = (theMesh->vertices[i].x/decalSize + 0.5f);
+ theMesh->uvs[i].y = (theMesh->vertices[i].y/decalSize + 0.5f);
+
+ // Tiny nudge in the normal direction so it renders properly over the mesh
+ theMesh->vertices[i].z -= decalOffset;
+
+ // From projection space to world space
+ theMesh->vertices[i] = Vector3Transform(theMesh->vertices[i], invProj);
+ }
+
+ // Decal model data ready, create the mesh and return it
+ return BuildMesh(theMesh);
+ }
+ else
+ {
+ // Return a blank mesh as there's nothing to add
+ return (Mesh){ 0 };
+ }
+}
+
+// Button UI element
+static bool GuiButton(Rectangle rec, const char *label)
+{
+ Color bgColor = GRAY;
+ bool pressed = false;
+
+ if (CheckCollisionPointRec(GetMousePosition(), rec))
+ {
+ bgColor = LIGHTGRAY;
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) pressed = true;
+ }
+
+ DrawRectangleRec(rec, bgColor);
+ DrawRectangleLinesEx(rec, 2.0f, DARKGRAY);
+
+ float fontSize = 10.0f;
+ float textWidth = MeasureText(label, fontSize);
+
+ DrawText(label, (int)(rec.x + rec.width*0.5f - textWidth*0.5f), (int)(rec.y + rec.height*0.5f - fontSize*0.5f), fontSize, DARKGRAY);
+
+ return pressed;
+}
diff --git a/examples/models/models_decals.png b/examples/models/models_decals.png
new file mode 100644
index 000000000..6bdbaf17c
Binary files /dev/null and b/examples/models/models_decals.png differ
diff --git a/examples/models/resources/models/obj/character.mtl b/examples/models/resources/models/obj/character.mtl
new file mode 100644
index 000000000..96b272b29
--- /dev/null
+++ b/examples/models/resources/models/obj/character.mtl
@@ -0,0 +1,12 @@
+# Blender MTL File: 'None'
+# Material Count: 1
+
+newmtl skin
+Ns 86.470579
+Ka 1.000000 1.000000 1.000000
+Kd 0.800000 0.800000 0.800000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 0.000000
+illum 9
diff --git a/examples/models/resources/models/obj/character.obj b/examples/models/resources/models/obj/character.obj
new file mode 100644
index 000000000..be7e47863
--- /dev/null
+++ b/examples/models/resources/models/obj/character.obj
@@ -0,0 +1,3454 @@
+# Blender v2.83.2 OBJ File: ''
+# www.blender.org
+mtllib character.mtl
+o characterMedium
+v 0.410751 3.453012 0.200817
+v 0.176931 3.516046 -0.492870
+v 0.176931 3.069885 -0.492870
+v 0.193767 2.961166 0.489574
+v 0.193767 3.452389 0.455386
+v 0.400606 2.998632 0.217911
+v 0.400606 3.035397 -0.212411
+v 0.410751 3.483905 -0.212411
+v 0.188780 3.698580 0.247489
+v 0.188780 3.731344 -0.224509
+v 0.188780 2.741884 -0.224509
+v 0.188780 2.664058 0.281677
+v 0.338542 2.788810 0.205190
+v 0.323730 3.496119 -0.410188
+v 0.323730 3.441588 0.352035
+v 0.338542 3.642598 0.223085
+v 0.338542 2.852551 -0.208748
+v 0.176295 2.876968 -0.427238
+v 0.323730 3.072495 -0.410188
+v 0.193131 2.735571 0.459728
+v 0.323730 2.996823 0.381949
+v 0.338542 3.655763 -0.208748
+v 0.176295 3.660861 -0.399904
+v 0.193131 3.617279 0.405342
+v 0.180529 3.275434 -0.517282
+v 0.197366 3.218354 0.478425
+v 0.409350 3.230555 0.194491
+v 0.403118 3.253443 -0.219099
+v 0.429171 3.009897 0.014208
+v 0.439316 3.472003 0.009934
+v 0.198303 3.743473 0.020506
+v 0.198303 2.669343 0.029053
+v 0.286423 2.928726 -0.357824
+v 0.286423 2.767836 0.367046
+v 0.286423 3.636701 -0.357824
+v 0.301893 3.594941 0.358830
+v 0.357587 2.802252 0.025342
+v 0.322536 3.266541 -0.423686
+v 0.327481 3.227505 0.360122
+v 0.357587 3.654801 0.017864
+v 0.434369 3.238045 0.005717
+v 0.111250 2.648599 -0.113100
+v 0.129723 2.623841 0.000772
+v 0.110155 2.617475 0.111510
+v 0.098894 2.551101 -0.119944
+v 0.140309 2.525439 -0.009396
+v 0.098894 2.517193 0.100599
+v 0.208678 2.515187 -0.122760
+v 0.245812 2.502890 -0.002447
+v 0.208678 2.483677 0.109699
+v 0.271570 2.206755 -0.145013
+v 0.319908 2.187368 0.032075
+v 0.271570 2.177688 0.191096
+v 0.303127 1.441376 -0.106186
+v 0.355115 1.410218 0.080975
+v 0.289850 1.402806 0.240428
+v 0.260948 1.763152 0.232137
+v 0.307393 1.770383 0.075582
+v 0.260948 1.788246 -0.089088
+v 0.247213 2.324639 0.153241
+v 0.247213 2.354879 -0.163591
+v 0.115069 1.290704 0.269082
+v 0.017798 1.168477 -0.035384
+v 0.183067 1.284675 -0.183271
+v 0.084912 3.522239 -0.501146
+v 0.084912 3.064342 -0.512888
+v 0.084912 2.943401 0.510254
+v 0.084912 3.458095 0.476066
+v 0.090590 3.723567 0.254122
+v 0.090590 3.746935 -0.231142
+v 0.090590 2.722769 -0.231142
+v 0.090590 2.643034 0.288310
+v 0.084607 2.864935 -0.440534
+v 0.084607 2.702693 0.473189
+v 0.084607 3.673055 -0.413200
+v 0.084607 3.629352 0.421907
+v 0.086637 3.278739 -0.526585
+v 0.086636 3.215177 0.507309
+v 0.095154 3.754534 0.020506
+v 0.060191 2.658972 -0.154656
+v 0.053444 2.613782 0.136010
+v 0.047516 2.554504 -0.139039
+v 0.047516 2.514067 0.124693
+v 0.100126 2.519134 -0.142488
+v 0.100126 2.479805 0.136555
+v 0.130264 2.209162 -0.175208
+v 0.130264 2.175989 0.226360
+v 0.145386 1.454041 -0.168399
+v 0.145386 1.399946 0.290329
+v 0.125174 1.790136 -0.123980
+v 0.125174 1.762047 0.266843
+v 0.118592 2.321896 0.187758
+v 0.118592 2.358026 -0.194066
+v 0.064118 0.867640 -0.065778
+v 0.139275 0.844466 0.140266
+v 0.257486 0.890374 -0.145882
+v 0.359097 0.900878 0.061199
+v 0.074195 0.752219 -0.105874
+v 0.147259 0.698792 0.087905
+v 0.263534 0.755735 -0.191206
+v 0.364126 0.730329 0.010206
+v 0.092608 0.518587 -0.156357
+v 0.161208 0.488124 0.011298
+v 0.257654 0.503497 -0.235568
+v 0.342662 0.497755 -0.059963
+v 0.100936 1.052740 0.183646
+v 0.362186 1.124208 0.082677
+v 0.035605 1.007707 -0.051248
+v 0.244578 1.066754 -0.153714
+v 0.055029 1.214705 -0.163442
+v 0.255589 1.328226 0.210676
+v 0.140172 0.882954 -0.138230
+v 0.262287 0.869133 0.135226
+v 0.152224 0.756748 -0.186384
+v 0.268705 0.704238 0.080827
+v 0.163237 0.508650 -0.221611
+v 0.266438 0.484781 0.003128
+v 0.113057 1.038591 -0.152600
+v 0.246990 1.089520 0.173845
+v 0.054756 1.198160 0.101170
+v 0.310361 1.325851 -0.067512
+v 0.060255 0.853278 0.049460
+v 0.343613 0.899484 -0.056313
+v 0.071380 0.718974 0.002418
+v 0.350589 0.741909 -0.110914
+v 0.091684 0.503566 -0.057160
+v 0.339310 0.499423 -0.163148
+v 0.344611 1.099522 -0.066307
+v 0.028575 1.027615 0.082498
+v 0.455190 2.450647 -0.082374
+v 0.462809 2.465601 0.006612
+v 0.448972 2.441031 0.081440
+v 0.434408 2.252116 -0.088512
+v 0.448014 2.213438 0.029647
+v 0.428671 2.233589 0.135751
+v 0.442147 2.332059 0.110493
+v 1.328482 2.369486 -0.025838
+v 0.448115 2.351334 -0.094647
+v 0.717408 2.422497 -0.064617
+v 0.727228 2.428632 0.006928
+v 0.711866 2.404597 0.073618
+v 0.698886 2.236229 -0.077850
+v 0.706620 2.199933 0.027458
+v 0.693774 2.219717 0.102536
+v 0.705784 2.307478 0.109237
+v 0.945792 2.289033 0.134562
+v 0.711103 2.324656 -0.097021
+v 1.329792 2.357378 0.034079
+v 1.323088 2.354750 0.089928
+v 1.305094 2.214479 -0.036920
+v 1.300746 2.180356 0.051271
+v 1.300117 2.200886 0.110979
+v 1.313884 2.273778 0.121339
+v 1.509906 2.320435 -0.046242
+v 1.319060 2.287920 -0.055202
+v 0.930288 2.200850 0.122871
+v 0.936312 2.211617 -0.068478
+v 0.952059 2.307598 -0.088140
+v 0.936310 2.172915 0.046302
+v 0.968273 2.418404 0.023926
+v 0.961626 2.413997 -0.054054
+v 0.955096 2.394653 0.096614
+v 0.330881 2.488142 0.003375
+v 0.305188 2.468017 0.099597
+v 0.315496 2.226114 -0.122984
+v 0.320825 2.354873 -0.139518
+v 0.303439 2.230228 0.158131
+v 0.309166 2.327404 0.136383
+v 0.348316 2.192029 0.031171
+v 0.315498 2.485255 -0.117814
+v 1.401711 2.330388 -0.053750
+v 1.402313 2.325266 0.037149
+v 1.368471 2.326110 0.116069
+v 1.380995 2.227921 -0.070645
+v 1.378716 2.209659 0.062973
+v 1.340428 2.225900 0.146512
+v 1.351661 2.274332 0.162481
+v 1.795120 2.206148 -0.017422
+v 1.399326 2.275373 -0.096810
+v 1.525167 2.312472 0.043161
+v 1.504512 2.310743 0.126497
+v 1.486518 2.218486 -0.062778
+v 1.505804 2.196043 0.068815
+v 1.481542 2.209545 0.157907
+v 1.495307 2.257487 0.173365
+v 1.626749 2.173789 0.059473
+v 1.500484 2.266789 -0.090058
+v 1.809535 2.198612 0.054630
+v 1.788894 2.200041 0.121791
+v 1.762707 2.137646 -0.030749
+v 1.779807 2.119442 0.075304
+v 1.756964 2.132012 0.147105
+v 1.774950 2.163872 0.159563
+v 1.797727 2.160531 0.057501
+v 1.780926 2.169733 -0.052734
+v 1.607462 2.193023 -0.059653
+v 1.616252 2.226447 0.154119
+v 1.602486 2.185360 0.140125
+v 1.646111 2.273569 0.036250
+v 1.630851 2.280393 -0.044683
+v 1.621429 2.234418 -0.084348
+v 1.625457 2.272087 0.111690
+v 1.379530 2.252804 0.224500
+v 1.371148 2.204101 0.211689
+v 1.461364 2.245535 0.213279
+v 1.452982 2.196833 0.200468
+v 1.424118 2.225873 0.279904
+v 1.419068 2.175998 0.270241
+v 1.481443 2.235304 0.220739
+v 1.476394 2.185430 0.211076
+v 1.509712 2.198027 0.341520
+v 1.506171 2.163050 0.334743
+v 1.549915 2.204642 0.300027
+v 1.546374 2.169665 0.293251
+v 0.262061 0.256721 -0.179629
+v 0.125851 0.263241 -0.073885
+v 0.264548 0.252916 -0.065338
+v 0.141817 0.268149 -0.192735
+v 0.270091 0.253667 -0.122910
+v 0.125675 0.264206 -0.137064
+v 0.206420 0.264077 -0.203655
+v 0.230977 0.000692 0.289805
+v 0.342493 0.000690 0.270761
+v 0.163985 0.000688 -0.230879
+v 0.270393 0.000686 -0.245194
+v 0.144177 0.000691 0.033839
+v 0.288000 0.000691 0.291562
+v 0.372899 0.000687 -0.002369
+v 0.227192 0.000686 -0.254522
+v 0.257567 0.000689 0.016768
+v 0.137243 0.000692 0.170051
+v 0.391563 0.000688 0.127957
+v 0.273728 0.000690 0.160912
+v 0.338169 0.000686 -0.146682
+v 0.108448 0.000690 -0.113832
+v 0.239700 0.000687 -0.142594
+v 0.167568 0.000692 0.233611
+v 0.383765 0.000689 0.197667
+v 0.281809 0.000691 0.232984
+v 0.309290 0.000686 -0.218277
+v 0.229983 0.000687 -0.223266
+v 0.118360 0.000689 -0.190507
+v 0.130135 0.000690 -0.034828
+v 0.349068 0.000687 -0.064281
+v 0.249487 0.000688 -0.055304
+v 0.387775 0.000687 0.061323
+v 0.265648 0.000689 0.088840
+v 0.129773 0.000692 0.103416
+v 0.232718 0.085533 0.288274
+v 0.363576 0.085530 0.268239
+v 0.154897 0.085528 -0.243375
+v 0.260403 0.080414 -0.243911
+v 0.128135 0.085532 0.035193
+v 0.299506 0.085532 0.289325
+v 0.383870 0.085527 -0.003576
+v 0.214830 0.085527 -0.261124
+v 0.132008 0.085533 0.181044
+v 0.405763 0.085528 0.135972
+v 0.339530 0.085526 -0.157915
+v 0.096516 0.085530 -0.123177
+v 0.167580 0.085533 0.249102
+v 0.395495 0.085529 0.210885
+v 0.304116 0.077122 -0.204676
+v 0.110617 0.085530 -0.206279
+v 0.114426 0.085531 -0.038332
+v 0.357741 0.085527 -0.069335
+v 0.401320 0.085528 0.064622
+v 0.123244 0.085533 0.109694
+v 0.235360 0.121957 0.282892
+v 0.342479 0.121955 0.271351
+v 0.155498 0.140203 -0.234632
+v 0.258674 0.141703 -0.233045
+v 0.147943 0.140206 0.045064
+v 0.367478 0.140202 0.015099
+v 0.209678 0.140554 -0.248081
+v 0.151504 0.140207 0.167879
+v 0.387046 0.140203 0.131704
+v 0.326827 0.140201 -0.142554
+v 0.113117 0.142231 -0.125673
+v 0.174977 0.140207 0.230696
+v 0.378520 0.140204 0.201276
+v 0.291506 0.139635 -0.192779
+v 0.127237 0.141691 -0.187001
+v 0.134396 0.140206 -0.008056
+v 0.354118 0.140202 -0.035038
+v 0.382905 0.140203 0.065200
+v 0.143705 0.140207 0.101330
+v 0.244012 0.174412 0.250246
+v 0.312400 0.174411 0.237719
+v 0.154929 0.197920 -0.224667
+v 0.244653 0.200889 -0.226557
+v 0.200247 0.182648 0.039626
+v 0.320975 0.193251 0.026737
+v 0.200815 0.200081 -0.230324
+v 0.176892 0.181218 0.144060
+v 0.349336 0.193278 0.128903
+v 0.299466 0.209667 -0.141685
+v 0.117610 0.203001 -0.122411
+v 0.197637 0.187029 0.207154
+v 0.340156 0.188834 0.188204
+v 0.275703 0.199069 -0.189682
+v 0.130048 0.198871 -0.180965
+v 0.183002 0.199344 -0.013043
+v 0.295575 0.215862 -0.011766
+v 0.341167 0.191744 0.072780
+v 0.191423 0.184576 0.092515
+v 0.338887 0.000686 -0.105818
+v 0.244594 0.000688 -0.098949
+v 0.116803 0.000690 -0.073995
+v 0.348659 0.085527 -0.113812
+v 0.102306 0.085531 -0.080271
+v 0.339594 0.140202 -0.089574
+v 0.118165 0.140205 -0.060612
+v 0.304014 0.215861 -0.085942
+v 0.129758 0.215864 -0.062783
+v 0.261646 0.242079 -0.188306
+v 0.230162 0.234212 -0.224732
+v 0.193922 0.242264 -0.221201
+v 0.165941 0.245963 -0.208302
+v 0.280499 0.229314 -0.077601
+v 0.279868 0.243470 -0.137553
+v 0.127675 0.236447 -0.179834
+v 0.120948 0.240070 -0.122668
+v 0.128658 0.229317 -0.058955
+v 0.189612 0.231437 -0.029962
+v 0.259835 0.229315 -0.044259
+v 0.190037 0.256893 -0.038329
+v -0.410268 3.453012 0.200817
+v -0.176448 3.516046 -0.492870
+v -0.176448 3.069885 -0.492870
+v -0.193285 2.961166 0.489574
+v -0.193285 3.452389 0.455386
+v -0.400123 2.998632 0.217911
+v -0.400123 3.035397 -0.212411
+v -0.410268 3.483905 -0.212411
+v -0.188297 3.698580 0.247489
+v -0.188298 3.731344 -0.224509
+v -0.188298 2.741884 -0.224509
+v -0.188298 2.664058 0.281677
+v -0.338060 2.788810 0.205190
+v -0.323248 3.496119 -0.410188
+v -0.323248 3.441588 0.352035
+v -0.338059 3.642598 0.223085
+v -0.338060 2.852551 -0.208748
+v -0.175812 2.876968 -0.427238
+v -0.323248 3.072495 -0.410188
+v -0.192649 2.735571 0.459728
+v -0.323248 2.996823 0.381949
+v -0.338060 3.655763 -0.208748
+v -0.175812 3.660861 -0.399904
+v -0.192648 3.617279 0.405342
+v -0.180047 3.275434 -0.517282
+v 0.000241 3.527937 -0.505363
+v 0.000241 3.059241 -0.517105
+v -0.196883 3.218354 0.478425
+v 0.000241 2.927055 0.514236
+v 0.000241 3.457695 0.495095
+v -0.408868 3.230555 0.194491
+v -0.402636 3.253443 -0.219099
+v -0.428688 3.009897 0.014208
+v -0.438833 3.472003 0.009934
+v 0.000241 3.735282 0.260225
+v 0.000241 3.756304 -0.237245
+v -0.197821 3.743473 0.020506
+v -0.197821 2.669343 0.029053
+v 0.000241 2.716923 -0.237245
+v 0.000241 2.623689 0.294413
+v -0.285941 2.928726 -0.357824
+v -0.285941 2.767836 0.367046
+v -0.285941 3.636701 -0.357824
+v -0.301410 3.594941 0.358830
+v -0.357105 2.802252 0.025342
+v 0.000241 2.853864 -0.452768
+v -0.322054 3.266541 -0.423686
+v 0.000241 2.695371 0.485576
+v -0.326999 3.227505 0.360122
+v -0.357105 3.654801 0.017864
+v 0.000241 3.684277 -0.419779
+v 0.000241 3.640461 0.434294
+v 0.000241 3.279187 -0.533908
+v 0.000241 3.212254 0.507793
+v -0.433886 3.238045 0.005717
+v 0.000241 3.765371 0.020506
+v 0.000241 2.608866 0.157665
+v 0.000241 2.662452 -0.152277
+v -0.110768 2.648599 -0.113100
+v -0.129241 2.623841 0.000772
+v -0.109673 2.617475 0.111510
+v 0.000241 2.511192 0.146864
+v 0.000241 2.557636 -0.161210
+v -0.098412 2.551101 -0.119944
+v -0.139827 2.525439 -0.009396
+v -0.098412 2.517193 0.100599
+v 0.000241 2.476242 0.161267
+v 0.000241 2.522766 -0.165241
+v -0.208196 2.515187 -0.122760
+v -0.245330 2.502890 -0.002447
+v -0.208196 2.483677 0.109699
+v 0.000241 2.174426 0.258809
+v 0.000241 2.211377 -0.202993
+v -0.271088 2.206755 -0.145013
+v -0.319426 2.187368 0.032075
+v -0.271088 2.177688 0.191096
+v 0.000241 1.398135 0.309651
+v 0.000241 1.463624 -0.206620
+v -0.302644 1.441376 -0.106186
+v -0.354291 1.410232 0.081480
+v -0.288561 1.402802 0.240545
+v 0.000241 1.761031 0.298778
+v -0.260465 1.763152 0.232137
+v -0.306911 1.770383 0.075582
+v -0.260465 1.788246 -0.089088
+v 0.000241 1.791875 -0.156086
+v -0.246731 2.324639 0.153241
+v -0.246731 2.354880 -0.163592
+v 0.000241 2.360921 -0.206229
+v 0.000241 2.319373 0.219519
+v -0.113364 1.290662 0.268232
+v -0.018429 1.168483 -0.035181
+v -0.184480 1.284700 -0.183080
+v -0.000316 1.168480 -0.035282
+v -0.084430 3.522239 -0.501146
+v -0.084430 3.064342 -0.512888
+v -0.084430 2.943401 0.510254
+v -0.084429 3.458095 0.476066
+v -0.090108 3.723567 0.254122
+v -0.090108 3.746935 -0.231142
+v -0.090108 2.722769 -0.231142
+v -0.090108 2.643034 0.288310
+v -0.084125 2.864935 -0.440534
+v -0.084125 2.702693 0.473189
+v -0.084125 3.673055 -0.413200
+v -0.084125 3.629352 0.421907
+v -0.086154 3.278739 -0.526585
+v -0.086154 3.215177 0.507309
+v -0.094671 3.754534 0.020506
+v -0.059709 2.658972 -0.154656
+v -0.052962 2.613782 0.136010
+v -0.047034 2.554504 -0.139039
+v -0.047034 2.514068 0.124693
+v -0.099643 2.519134 -0.142488
+v -0.099643 2.479805 0.136555
+v -0.129782 2.209162 -0.175208
+v -0.129782 2.175989 0.226360
+v -0.144904 1.454041 -0.168399
+v -0.144904 1.399946 0.290329
+v -0.124691 1.790136 -0.123980
+v -0.124691 1.762047 0.266843
+v -0.118110 2.321897 0.187758
+v -0.118110 2.358026 -0.194066
+v 0.000241 1.284807 0.281643
+v 0.000241 1.284807 -0.179892
+v -0.065606 0.867575 -0.068223
+v -0.137184 0.844409 0.139088
+v -0.260316 0.890440 -0.144957
+v -0.358304 0.900967 0.063854
+v -0.076447 0.752149 -0.108154
+v -0.146162 0.698757 0.086858
+v -0.267231 0.755783 -0.190189
+v -0.364320 0.730428 0.012933
+v -0.095873 0.518518 -0.158302
+v -0.161565 0.488099 0.010515
+v -0.262272 0.503526 -0.234639
+v -0.344217 0.497838 -0.057588
+v -0.097973 1.052652 0.181831
+v -0.360885 1.124295 0.085420
+v -0.036763 1.007622 -0.054166
+v -0.247441 1.066813 -0.152981
+v -0.057083 1.214724 -0.162813
+v -0.253453 1.328216 0.210857
+v -0.001001 1.201565 -0.157958
+v -0.142896 0.882948 -0.139342
+v -0.260245 0.869150 0.136185
+v -0.155858 0.756730 -0.187298
+v -0.267706 0.704276 0.081887
+v -0.167628 0.508623 -0.222321
+v -0.266919 0.484820 0.004171
+v -0.115942 1.038571 -0.154153
+v -0.244148 1.089522 0.174570
+v -0.053830 1.198178 0.101779
+v -0.310544 1.325896 -0.066387
+v 0.000415 1.184651 0.093554
+v -0.059751 0.853190 0.046927
+v -0.344866 0.899585 -0.053907
+v -0.071771 0.718897 0.000070
+v -0.352883 0.742005 -0.108402
+v -0.093234 0.503499 -0.059137
+v -0.342657 0.499502 -0.160814
+v -0.345917 1.099626 -0.063848
+v -0.027398 1.027503 0.079441
+v -0.454708 2.450647 -0.082374
+v -0.462326 2.465601 0.006612
+v -0.448490 2.441031 0.081440
+v -0.433925 2.252116 -0.088512
+v -0.447532 2.213438 0.029647
+v -0.428189 2.233589 0.135751
+v -0.441665 2.332059 0.110493
+v -1.328000 2.369487 -0.025839
+v -0.447632 2.351334 -0.094647
+v -0.716926 2.422497 -0.064618
+v -0.726745 2.428632 0.006928
+v -0.711384 2.404597 0.073617
+v -0.698403 2.236229 -0.077851
+v -0.706138 2.199933 0.027457
+v -0.693291 2.219717 0.102535
+v -0.705302 2.307478 0.109236
+v -0.945310 2.289035 0.134561
+v -0.710620 2.324656 -0.097021
+v -1.329309 2.357379 0.034077
+v -1.322606 2.354751 0.089927
+v -1.304611 2.214480 -0.036921
+v -1.300263 2.180357 0.051270
+v -1.299635 2.200886 0.110977
+v -1.313401 2.273779 0.121337
+v -1.509424 2.320436 -0.046244
+v -1.318578 2.287921 -0.055203
+v -0.929806 2.200852 0.122871
+v -0.935830 2.211618 -0.068479
+v -0.951576 2.307599 -0.088141
+v -0.935828 2.172916 0.046301
+v -0.967791 2.418405 0.023925
+v -0.961144 2.413998 -0.054055
+v -0.954614 2.394654 0.096613
+v -0.330399 2.488142 0.003375
+v -0.304706 2.468017 0.099597
+v -0.315013 2.226115 -0.122984
+v -0.320343 2.354873 -0.139518
+v -0.302957 2.230229 0.158131
+v -0.308683 2.327404 0.136383
+v -0.347834 2.192029 0.031171
+v -0.315016 2.485255 -0.117814
+v -1.401229 2.330389 -0.053752
+v -1.401832 2.325267 0.037148
+v -1.367989 2.326111 0.116068
+v -1.380512 2.227921 -0.070646
+v -1.378233 2.209659 0.062972
+v -1.339946 2.225900 0.146510
+v -1.351179 2.274333 0.162479
+v -1.794637 2.206148 -0.017425
+v -1.398844 2.275373 -0.096812
+v -1.524685 2.312473 0.043160
+v -1.504030 2.310744 0.126495
+v -1.486035 2.218486 -0.062780
+v -1.505322 2.196043 0.068813
+v -1.481060 2.209546 0.157905
+v -1.494826 2.257488 0.173364
+v -1.626266 2.173790 0.059471
+v -1.500002 2.266789 -0.090059
+v -1.809052 2.198613 0.054628
+v -1.788411 2.200042 0.121789
+v -1.762224 2.137647 -0.030751
+v -1.779324 2.119443 0.075302
+v -1.756481 2.132013 0.147103
+v -1.774468 2.163872 0.159561
+v -1.797244 2.160531 0.057499
+v -1.780442 2.169733 -0.052736
+v -1.606979 2.193023 -0.059655
+v -1.615770 2.226447 0.154117
+v -1.602004 2.185361 0.140123
+v -1.645628 2.273569 0.036248
+v -1.630368 2.280394 -0.044685
+v -1.620946 2.234419 -0.084350
+v -1.624974 2.272088 0.111689
+v -1.379048 2.252805 0.224499
+v -1.370666 2.204103 0.211687
+v -1.460882 2.245536 0.213278
+v -1.452500 2.196834 0.200466
+v -1.423636 2.225874 0.279902
+v -1.418586 2.176000 0.270239
+v -1.480961 2.235306 0.220738
+v -1.475912 2.185432 0.211075
+v -1.509230 2.198029 0.341518
+v -1.505689 2.163052 0.334741
+v -1.549433 2.204644 0.300026
+v -1.545892 2.169667 0.293249
+v -0.265503 0.256741 -0.179040
+v -0.128605 0.263213 -0.074647
+v -0.266996 0.252931 -0.064922
+v -0.145572 0.268133 -0.193156
+v -0.273029 0.253686 -0.122348
+v -0.128976 0.264181 -0.137721
+v -0.210161 0.264081 -0.203502
+v -0.234285 0.000684 0.289802
+v -0.345794 0.000685 0.270758
+v -0.167301 0.000685 -0.230884
+v -0.273702 0.000685 -0.245200
+v -0.147492 0.000684 0.033835
+v -0.291304 0.000684 0.291559
+v -0.376200 0.000685 -0.002375
+v -0.230503 0.000685 -0.254528
+v -0.260875 0.000685 0.016763
+v -0.140559 0.000683 0.170049
+v -0.394861 0.000685 0.127952
+v -0.277034 0.000684 0.160908
+v -0.341473 0.000685 -0.146689
+v -0.111766 0.000684 -0.113835
+v -0.243010 0.000685 -0.142600
+v -0.170881 0.000684 0.233609
+v -0.387064 0.000685 0.197662
+v -0.285114 0.000684 0.232981
+v -0.312595 0.000685 -0.218283
+v -0.233294 0.000685 -0.223272
+v -0.121678 0.000684 -0.190511
+v -0.133452 0.000684 -0.034831
+v -0.352371 0.000685 -0.064287
+v -0.252796 0.000685 -0.055309
+v -0.391075 0.000685 0.061317
+v -0.268955 0.000685 0.088836
+v -0.133089 0.000684 0.103414
+v -0.236024 0.085525 0.288271
+v -0.366872 0.085526 0.268235
+v -0.158210 0.085526 -0.243380
+v -0.263710 0.080414 -0.243917
+v -0.131449 0.085526 0.035190
+v -0.302807 0.085526 0.289322
+v -0.387167 0.085527 -0.003582
+v -0.218139 0.085526 -0.261130
+v -0.135320 0.085525 0.181042
+v -0.409058 0.085527 0.135967
+v -0.342831 0.085527 -0.157921
+v -0.099833 0.085525 -0.123180
+v -0.170889 0.085525 0.249100
+v -0.398790 0.085527 0.210881
+v -0.307420 0.077122 -0.204682
+v -0.113933 0.085526 -0.206283
+v -0.117741 0.085526 -0.038335
+v -0.361040 0.085527 -0.069341
+v -0.404616 0.085527 0.064617
+v -0.126558 0.085525 0.109692
+v -0.238664 0.121950 0.282890
+v -0.345776 0.121951 0.271347
+v -0.158809 0.140201 -0.234637
+v -0.261978 0.141703 -0.233051
+v -0.151253 0.140201 0.045061
+v -0.370775 0.140202 0.015093
+v -0.212986 0.140554 -0.248087
+v -0.154814 0.140200 0.167876
+v -0.390340 0.140202 0.131699
+v -0.330126 0.140202 -0.142561
+v -0.116431 0.142227 -0.125676
+v -0.178285 0.140200 0.230694
+v -0.381814 0.140202 0.201272
+v -0.294809 0.139635 -0.192786
+v -0.130550 0.141688 -0.187006
+v -0.137707 0.140201 -0.008060
+v -0.357415 0.140202 -0.035044
+v -0.386200 0.140202 0.065195
+v -0.147016 0.140200 0.101327
+v -0.247314 0.174407 0.250243
+v -0.315698 0.174407 0.237716
+v -0.158239 0.197919 -0.224671
+v -0.247956 0.200890 -0.226562
+v -0.203553 0.182644 0.039623
+v -0.324272 0.193250 0.026732
+v -0.204122 0.200081 -0.230329
+v -0.180198 0.181212 0.144057
+v -0.352631 0.193276 0.128898
+v -0.302766 0.209668 -0.141691
+v -0.120922 0.202998 -0.122415
+v -0.200942 0.187023 0.207151
+v -0.343452 0.188832 0.188200
+v -0.279004 0.199070 -0.189688
+v -0.133359 0.198869 -0.180969
+v -0.186309 0.199341 -0.013046
+v -0.298874 0.215861 -0.011771
+v -0.344463 0.191743 0.072775
+v -0.194729 0.184572 0.092512
+v -0.342190 0.000685 -0.105824
+v -0.247903 0.000685 -0.098954
+v -0.120121 0.000684 -0.073998
+v -0.351959 0.085527 -0.113818
+v -0.105622 0.085526 -0.080274
+v -0.342893 0.140202 -0.089580
+v -0.121478 0.140201 -0.060615
+v -0.307313 0.215861 -0.085948
+v -0.133068 0.215860 -0.062786
+v -0.264947 0.242080 -0.188311
+v -0.233465 0.234212 -0.224737
+v -0.197228 0.242264 -0.221206
+v -0.169248 0.245962 -0.208306
+v -0.283799 0.229314 -0.077606
+v -0.283168 0.243471 -0.137559
+v -0.130985 0.236445 -0.179838
+v -0.124258 0.240067 -0.122671
+v -0.131967 0.229313 -0.058958
+v -0.192917 0.231434 -0.029966
+v -0.263136 0.229314 -0.044264
+v -0.192377 0.256884 -0.038600
+v -1.684602 2.165335 -0.045203
+v -1.679243 2.158687 0.143613
+v -1.727340 2.236091 0.045438
+v -1.702795 2.146616 0.067387
+v -1.695118 2.195160 0.156839
+v -1.712502 2.243271 -0.031055
+v -1.700694 2.202076 -0.068543
+v -1.706693 2.236064 0.116739
+v 1.685084 2.165334 -0.045201
+v 1.679725 2.158686 0.143615
+v 1.727823 2.236091 0.045440
+v 1.703278 2.146616 0.067389
+v 1.695601 2.195159 0.156841
+v 1.712985 2.243270 -0.031053
+v 1.701177 2.202075 -0.068541
+v 1.707175 2.236064 0.116741
+v 1.566276 2.184916 0.064144
+v 1.555779 2.241967 0.163742
+v 1.570378 2.300414 -0.045463
+v 1.560956 2.250603 -0.087203
+v 1.564984 2.291415 0.119094
+v 1.546990 2.205754 -0.061216
+v 1.542014 2.197453 0.149016
+v 1.585639 2.293020 0.039706
+v -1.565794 2.184916 0.064142
+v -1.555298 2.241968 0.163740
+v -1.569896 2.300415 -0.045465
+v -1.560474 2.250604 -0.087204
+v -1.564502 2.291416 0.119092
+v -1.546507 2.205755 -0.061217
+v -1.541532 2.197453 0.149014
+v -1.585157 2.293021 0.039704
+v 0.817599 2.223923 -0.073164
+v 0.817657 2.186424 0.036880
+v 0.839517 2.418247 -0.059336
+v 0.833481 2.399625 0.085116
+v 0.812031 2.210284 0.112704
+v 0.831581 2.316127 -0.092581
+v 0.836919 2.423518 0.015427
+v -0.817117 2.223924 -0.073165
+v -0.817175 2.186424 0.036879
+v -0.839035 2.418248 -0.059336
+v -0.832999 2.399626 0.085115
+v -0.811549 2.210284 0.112703
+v -0.831098 2.316128 -0.092581
+v -0.836436 2.423519 0.015427
+v 0.000241 1.579583 0.304214
+v 0.334021 1.590260 0.078120
+v 0.000241 1.627749 -0.181353
+v 0.277708 1.583014 0.235970
+v 0.282037 1.614811 -0.097637
+v 0.135280 1.622088 -0.146189
+v 0.135280 1.580997 0.278586
+v -0.333345 1.590268 0.078406
+v -0.276778 1.583012 0.236050
+v -0.281555 1.614811 -0.097637
+v -0.134797 1.622088 -0.146189
+v -0.134797 1.580997 0.278586
+v 0.266259 1.970420 0.211617
+v 0.266259 1.997501 -0.117050
+v 0.000241 1.967728 0.278793
+v 0.313651 1.978875 0.053829
+v 0.000241 2.001626 -0.179539
+v 0.127719 1.969018 0.246602
+v 0.127719 1.999649 -0.149594
+v -0.265777 1.970420 0.211617
+v -0.265777 1.997501 -0.117050
+v -0.313168 1.978875 0.053829
+v -0.127236 1.969018 0.246602
+v -0.127236 1.999649 -0.149594
+v 1.122344 2.200868 0.116925
+v 1.142700 2.297759 -0.071671
+v 1.154038 2.387891 0.029002
+v 1.136979 2.281405 0.127950
+v 1.127844 2.213048 -0.052699
+v 1.133873 2.176636 0.048787
+v 1.152195 2.391741 -0.039946
+v 1.146233 2.374701 0.093271
+v -1.121862 2.200869 0.116924
+v -1.142218 2.297760 -0.071672
+v -1.153556 2.387892 0.029001
+v -1.136497 2.281407 0.127949
+v -1.127362 2.213049 -0.052700
+v -1.133391 2.176636 0.048786
+v -1.151713 2.391742 -0.039947
+v -1.145751 2.374702 0.093270
+v 0.581107 2.319769 0.109865
+v 0.586750 2.337995 -0.095834
+v 0.593441 2.436572 -0.073496
+v 0.600412 2.447117 0.006770
+v 0.587561 2.422814 0.077529
+v 0.577991 2.206686 0.028552
+v 0.568364 2.226653 0.119143
+v 0.573788 2.244173 -0.083181
+v -0.580625 2.319769 0.109865
+v -0.586267 2.337995 -0.095834
+v -0.592958 2.436572 -0.073496
+v -0.599929 2.447117 0.006770
+v -0.587078 2.422814 0.077529
+v -0.577509 2.206685 0.028552
+v -0.567881 2.226653 0.119143
+v -0.573305 2.244173 -0.083181
+v 0.069151 0.811140 -0.084140
+v 0.143267 0.769931 0.115422
+v 0.361608 0.814996 0.037936
+v 0.265496 0.785043 0.109763
+v 0.146190 0.822050 -0.160339
+v 0.347095 0.821727 -0.081373
+v 0.065815 0.785709 0.027417
+v -0.070991 0.811069 -0.086508
+v -0.141651 0.769890 0.114305
+v -0.361270 0.815091 0.040619
+v -0.263946 0.785076 0.110766
+v -0.149333 0.822031 -0.161359
+v -0.348828 0.821822 -0.078922
+v -0.065734 0.785628 0.024971
+vt 0.424701 0.840048
+vt 0.423209 0.793785
+vt 0.461737 0.792426
+vt 0.464884 0.838834
+vt 0.468357 0.881332
+vt 0.416097 0.891155
+vt 0.382303 0.875623
+vt 0.388845 0.838885
+vt 0.386734 0.795098
+vt 0.579037 0.844668
+vt 0.567369 0.879717
+vt 0.544300 0.865660
+vt 0.547922 0.837220
+vt 0.549707 0.794263
+vt 0.582610 0.796170
+vt 0.598269 0.849956
+vt 0.602276 0.796592
+vt 0.621565 0.796099
+vt 0.617431 0.855287
+vt 0.601115 0.901709
+vt 0.583674 0.890608
+vt 0.580062 0.754791
+vt 0.546804 0.757119
+vt 0.544177 0.724490
+vt 0.573455 0.711359
+vt 0.598626 0.752337
+vt 0.595019 0.704367
+vt 0.617289 0.699781
+vt 0.620532 0.750242
+vt 0.349273 0.747190
+vt 0.347330 0.708825
+vt 0.370455 0.709217
+vt 0.379997 0.749138
+vt 0.352581 0.794437
+vt 0.329588 0.744940
+vt 0.331063 0.794428
+vt 0.315002 0.794084
+vt 0.314985 0.741795
+vt 0.314901 0.703498
+vt 0.329344 0.703695
+vt 0.354491 0.840733
+vt 0.357743 0.880856
+vt 0.332172 0.842510
+vt 0.333959 0.884940
+vt 0.315019 0.885796
+vt 0.315031 0.842108
+vt 0.414559 0.747483
+vt 0.399518 0.701783
+vt 0.448949 0.694770
+vt 0.456853 0.745548
+vt 0.505141 0.748829
+vt 0.508784 0.706093
+vt 0.507142 0.792801
+vt 0.508074 0.837122
+vt 0.514661 0.872259
+vt 0.419137 0.937326
+vt 0.478349 0.922822
+vt 0.424097 0.965195
+vt 0.486594 0.948330
+vt 0.495723 0.973192
+vt 0.428443 0.990876
+vt 0.345577 0.936058
+vt 0.314782 0.941388
+vt 0.375705 0.922558
+vt 0.532102 0.902649
+vt 0.545515 0.922196
+vt 0.559814 0.940878
+vt 0.436532 0.655316
+vt 0.362648 0.645806
+vt 0.382595 0.577465
+vt 0.445393 0.577416
+vt 0.535122 0.656711
+vt 0.561397 0.634699
+vt 0.607811 0.622342
+vt 0.339216 0.643866
+vt 0.314578 0.640560
+vt 0.510735 0.577421
+vt 0.559529 0.577420
+vt 0.444090 0.534948
+vt 0.509270 0.534980
+vt 0.347826 0.577463
+vt 0.314959 0.577465
+vt 0.314357 0.535019
+vt 0.343869 0.535021
+vt 0.327559 0.284656
+vt 0.332242 0.271386
+vt 0.359600 0.274896
+vt 0.357633 0.299914
+vt 0.321315 0.250312
+vt 0.314290 0.247970
+vt 0.314171 0.231740
+vt 0.334433 0.243039
+vt 0.382847 0.535032
+vt 0.558656 0.534925
+vt 0.325529 0.253434
+vt 0.351430 0.248123
+vt 0.319754 0.286217
+vt 0.333829 0.303559
+vt 0.418691 0.370972
+vt 0.389352 0.351632
+vt 0.418603 0.335552
+vt 0.431990 0.354981
+vt 0.338145 0.328760
+vt 0.366602 0.325961
+vt 0.377808 0.356778
+vt 0.343676 0.358303
+vt 0.335864 0.210609
+vt 0.314003 0.207365
+vt 0.314103 0.176477
+vt 0.345144 0.178504
+vt 0.387039 0.219621
+vt 0.390341 0.194177
+vt 0.422363 0.207716
+vt 0.418946 0.229929
+vt 0.345500 0.054288
+vt 0.315138 0.054235
+vt 0.315528 0.018181
+vt 0.347504 0.018238
+vt 0.376599 0.479159
+vt 0.415450 0.479198
+vt 0.416158 0.512649
+vt 0.378862 0.512649
+vt 0.417869 0.054390
+vt 0.379180 0.054356
+vt 0.383732 0.018359
+vt 0.421058 0.018359
+vt 0.344804 0.479148
+vt 0.345824 0.512586
+vt 0.343730 0.404567
+vt 0.376072 0.404566
+vt 0.374336 0.441555
+vt 0.343784 0.441555
+vt 0.416751 0.128948
+vt 0.377222 0.128952
+vt 0.374628 0.091879
+vt 0.414680 0.091883
+vt 0.414734 0.404572
+vt 0.414742 0.441555
+vt 0.344319 0.128948
+vt 0.314426 0.128944
+vt 0.314749 0.091873
+vt 0.343495 0.091877
+vt 0.377580 0.274898
+vt 0.379110 0.250741
+vt 0.414096 0.254865
+vt 0.413016 0.274926
+vt 0.383845 0.322909
+vt 0.415778 0.316747
+vt 0.785443 0.156150
+vt 0.764725 0.156147
+vt 0.765086 0.122612
+vt 0.785862 0.122612
+vt 0.799682 0.217712
+vt 0.787967 0.231864
+vt 0.787944 0.209717
+vt 0.806383 0.217712
+vt 0.817931 0.209717
+vt 0.817908 0.231864
+vt 0.313408 0.304910
+vt 0.313716 0.329378
+vt 0.371733 0.216071
+vt 0.314416 0.404567
+vt 0.314870 0.441555
+vt 0.315301 0.479147
+vt 0.315731 0.512570
+vt 0.379817 0.180762
+vt 0.313963 0.358401
+vt 0.313509 0.286997
+vt 0.603163 0.577407
+vt 0.606192 0.534877
+vt 0.745241 0.200706
+vt 0.748033 0.232049
+vt 0.860635 0.200706
+vt 0.857842 0.232049
+vt 0.709972 0.232115
+vt 0.709972 0.200711
+vt 0.709972 0.171386
+vt 0.709972 0.163211
+vt 0.711885 0.163092
+vt 0.722930 0.172839
+vt 0.895904 0.232115
+vt 0.895904 0.200711
+vt 0.882945 0.172839
+vt 0.893990 0.163092
+vt 0.895904 0.163211
+vt 0.895904 0.171386
+vt 0.746436 0.108499
+vt 0.728058 0.108499
+vt 0.727994 0.095821
+vt 0.746362 0.095822
+vt 0.742320 0.156136
+vt 0.722900 0.156121
+vt 0.728122 0.122612
+vt 0.746509 0.122612
+vt 0.820432 0.156150
+vt 0.806711 0.156148
+vt 0.806948 0.122612
+vt 0.820014 0.122612
+vt 0.863555 0.156136
+vt 0.841092 0.156147
+vt 0.840811 0.122612
+vt 0.859366 0.122612
+vt 0.820810 0.095822
+vt 0.806988 0.095820
+vt 0.807180 0.054984
+vt 0.822926 0.054984
+vt 0.820412 0.108499
+vt 0.806968 0.108499
+vt 0.859513 0.095822
+vt 0.859440 0.108499
+vt 0.840859 0.095821
+vt 0.785464 0.108499
+vt 0.765055 0.108499
+vt 0.765025 0.095821
+vt 0.785065 0.095822
+vt 0.765027 0.054984
+vt 0.748996 0.054984
+vt 0.749674 0.016269
+vt 0.765051 0.016269
+vt 0.840857 0.054984
+vt 0.856880 0.054984
+vt 0.782949 0.054984
+vt 0.729510 0.054983
+vt 0.799277 0.156148
+vt 0.882975 0.156121
+vt 0.798935 0.095820
+vt 0.798699 0.054984
+vt 0.877882 0.095821
+vt 0.876366 0.054983
+vt 0.730059 0.016269
+vt 0.798960 0.108499
+vt 0.877818 0.108499
+vt 0.877753 0.122612
+vt 0.798985 0.122612
+vt 0.840838 0.016269
+vt 0.856202 0.016269
+vt 0.782896 0.016268
+vt 0.798648 0.016268
+vt 0.449700 0.220684
+vt 0.449796 0.204123
+vt 0.480859 0.204123
+vt 0.480685 0.220695
+vt 0.449654 0.257610
+vt 0.449682 0.238404
+vt 0.480652 0.238492
+vt 0.480599 0.257655
+vt 0.449661 0.302478
+vt 0.449646 0.286082
+vt 0.480577 0.286036
+vt 0.480601 0.302370
+vt 0.449670 0.274956
+vt 0.480593 0.274987
+vt 0.377299 0.292342
+vt 0.412883 0.292280
+vt 0.427685 0.190243
+vt 0.435707 0.203873
+vt 0.566812 0.286023
+vt 0.566812 0.275036
+vt 0.595577 0.275057
+vt 0.595566 0.286095
+vt 0.566827 0.354952
+vt 0.566822 0.326817
+vt 0.595512 0.326825
+vt 0.595500 0.354952
+vt 0.566782 0.238670
+vt 0.566782 0.220717
+vt 0.595706 0.220705
+vt 0.595699 0.238600
+vt 0.566815 0.302227
+vt 0.595550 0.302456
+vt 0.449673 0.326828
+vt 0.480612 0.326823
+vt 0.449765 0.354952
+vt 0.480773 0.354952
+vt 0.936048 0.768188
+vt 0.936053 0.746623
+vt 0.924192 0.740812
+vt 0.923121 0.760166
+vt 0.936018 0.819789
+vt 0.936059 0.797784
+vt 0.916592 0.805110
+vt 0.913699 0.821253
+vt 0.935973 0.782601
+vt 0.915423 0.782034
+vt 0.911752 0.319669
+vt 0.933272 0.316595
+vt 0.941824 0.333084
+vt 0.910614 0.334381
+vt 0.566800 0.257742
+vt 0.595621 0.257734
+vt 0.566790 0.204124
+vt 0.595682 0.204124
+vt 0.506526 0.274998
+vt 0.506548 0.257674
+vt 0.532519 0.257694
+vt 0.532485 0.275009
+vt 0.506620 0.220701
+vt 0.506734 0.204123
+vt 0.532625 0.204124
+vt 0.532558 0.220707
+vt 0.532559 0.238577
+vt 0.506530 0.302339
+vt 0.506519 0.286032
+vt 0.532490 0.286028
+vt 0.532482 0.302308
+vt 0.506529 0.326822
+vt 0.532468 0.326821
+vt 0.506639 0.354952
+vt 0.532541 0.354952
+vt 0.420373 0.176908
+vt 0.414725 0.374942
+vt 0.885913 0.762972
+vt 0.885325 0.783977
+vt 0.889616 0.328988
+vt 0.912643 0.364253
+vt 0.892080 0.360976
+vt 0.879460 0.743643
+vt 0.891324 0.803735
+vt 0.891345 0.819504
+vt 0.896713 0.317960
+vt 0.936077 0.838896
+vt 0.917882 0.833832
+vt 0.948365 0.733420
+vt 0.934622 0.732855
+vt 0.849376 0.815349
+vt 0.850748 0.805248
+vt 0.836471 0.804603
+vt 0.835136 0.812201
+vt 0.845468 0.793376
+vt 0.831510 0.796107
+vt 0.917673 0.409579
+vt 0.942118 0.402143
+vt 0.940634 0.420541
+vt 0.917720 0.427678
+vt 0.838529 0.771488
+vt 0.832166 0.765778
+vt 0.818658 0.776896
+vt 0.825597 0.780492
+vt 0.891695 0.833437
+vt 0.868327 0.735148
+vt 0.887944 0.727402
+vt 0.871512 0.724326
+vt 0.941792 0.356512
+vt 0.824181 0.797634
+vt 0.812448 0.795354
+vt 0.828406 0.817321
+vt 0.830746 0.786410
+vt 0.844654 0.780574
+vt 0.900278 0.405603
+vt 0.901378 0.423637
+vt 0.844856 0.823697
+vt 0.876501 0.831755
+vt 0.877480 0.819001
+vt 0.863616 0.818497
+vt 0.861307 0.830073
+vt 0.872376 0.787311
+vt 0.872238 0.768855
+vt 0.858562 0.774738
+vt 0.859427 0.790645
+vt 0.895628 0.374273
+vt 0.915135 0.377867
+vt 0.917627 0.391481
+vt 0.899177 0.387570
+vt 0.865460 0.753064
+vt 0.851461 0.762485
+vt 0.857000 0.744904
+vt 0.845674 0.754660
+vt 0.942698 0.370129
+vt 0.943603 0.383745
+vt 0.878174 0.804814
+vt 0.865024 0.805893
+vt 0.914557 0.725788
+vt 0.924213 0.719241
+vt 0.914994 0.703678
+vt 0.906472 0.711107
+vt 0.881044 0.356556
+vt 0.875706 0.338668
+vt 0.863509 0.352136
+vt 0.879002 0.362548
+vt 0.863138 0.381292
+vt 0.852273 0.373989
+vt 0.885267 0.719886
+vt 0.871271 0.716399
+vt 0.894062 0.694357
+vt 0.896674 0.686606
+vt 0.881207 0.690837
+vt 0.886620 0.697803
+vt 0.822979 0.016268
+vt 0.807221 0.016268
+vt 0.875816 0.016269
+vt 0.767140 0.911152
+vt 0.774189 0.910992
+vt 0.771025 0.901580
+vt 0.764041 0.893569
+vt 0.762619 0.936895
+vt 0.770492 0.925697
+vt 0.696701 0.941705
+vt 0.711877 0.936747
+vt 0.712850 0.911002
+vt 0.696555 0.911002
+vt 0.714237 0.884771
+vt 0.699642 0.883044
+vt 0.663963 0.911002
+vt 0.680259 0.911002
+vt 0.684668 0.883866
+vt 0.669298 0.887352
+vt 0.666683 0.936525
+vt 0.681635 0.941705
+vt 0.736641 0.940160
+vt 0.745745 0.941028
+vt 0.748883 0.911001
+vt 0.739015 0.911001
+vt 0.747331 0.888913
+vt 0.738188 0.889775
+vt 0.652548 0.923774
+vt 0.650728 0.911086
+vt 0.654009 0.898398
+vt 0.729146 0.911001
+vt 0.728658 0.888542
+vt 0.727561 0.938163
+vt 0.685829 0.695635
+vt 0.692503 0.712229
+vt 0.708990 0.708576
+vt 0.708432 0.689949
+vt 0.636358 0.838542
+vt 0.651216 0.838339
+vt 0.651688 0.827846
+vt 0.635893 0.827677
+vt 0.781184 0.780586
+vt 0.761434 0.786870
+vt 0.765163 0.797322
+vt 0.785169 0.791226
+vt 0.644587 0.767637
+vt 0.662889 0.772774
+vt 0.667608 0.758644
+vt 0.648575 0.752749
+vt 0.673889 0.744932
+vt 0.655645 0.733289
+vt 0.636687 0.810221
+vt 0.652656 0.811979
+vt 0.655557 0.797710
+vt 0.638034 0.794237
+vt 0.751425 0.706855
+vt 0.736307 0.719414
+vt 0.743897 0.740484
+vt 0.762033 0.731608
+vt 0.770097 0.809706
+vt 0.787648 0.803114
+vt 0.775207 0.821912
+vt 0.791133 0.816315
+vt 0.756045 0.773861
+vt 0.741140 0.776355
+vt 0.746963 0.789506
+vt 0.749903 0.756858
+vt 0.738081 0.763188
+vt 0.728583 0.733966
+vt 0.733420 0.750248
+vt 0.683428 0.721761
+vt 0.690265 0.735383
+vt 0.699037 0.717821
+vt 0.675902 0.773849
+vt 0.678758 0.763215
+vt 0.663860 0.828975
+vt 0.666038 0.813500
+vt 0.651369 0.848259
+vt 0.662989 0.848260
+vt 0.662721 0.839648
+vt 0.726155 0.711178
+vt 0.718851 0.717725
+vt 0.763232 0.827184
+vt 0.767474 0.837667
+vt 0.779325 0.835265
+vt 0.753212 0.799839
+vt 0.758294 0.814508
+vt 0.683588 0.751217
+vt 0.658905 0.785523
+vt 0.671987 0.788046
+vt 0.669398 0.798853
+vt 0.770171 0.848260
+vt 0.779396 0.848260
+vt 0.737140 0.805935
+vt 0.745139 0.819551
+vt 0.691125 0.756638
+vt 0.696225 0.747399
+vt 0.671483 0.841478
+vt 0.672536 0.832167
+vt 0.695283 0.790443
+vt 0.692294 0.778048
+vt 0.684106 0.807013
+vt 0.755272 0.840706
+vt 0.757876 0.848260
+vt 0.689617 0.767062
+vt 0.751837 0.830942
+vt 0.726011 0.777908
+vt 0.724135 0.790230
+vt 0.727747 0.767067
+vt 0.723221 0.747063
+vt 0.728335 0.757320
+vt 0.702554 0.734897
+vt 0.676496 0.818660
+vt 0.669902 0.848260
+vt 0.715282 0.734795
+vt 0.744649 0.834372
+vt 0.747224 0.843692
+vt 0.678439 0.843499
+vt 0.679462 0.835501
+vt 0.740023 0.822211
+vt 0.676559 0.848260
+vt 0.718747 0.798862
+vt 0.731506 0.809276
+vt 0.681201 0.821956
+vt 0.749698 0.848260
+vt 0.689595 0.809913
+vt 0.701454 0.798968
+vt 0.731965 0.694501
+vt 0.685748 0.848259
+vt 0.686221 0.838135
+vt 0.741199 0.848260
+vt 0.688336 0.824075
+vt 0.697257 0.814380
+vt 0.734432 0.824734
+vt 0.739082 0.837215
+vt 0.710682 0.811176
+vt 0.725362 0.813361
+vt 0.794502 0.834892
+vt 0.769187 0.749663
+vt 0.775611 0.765710
+vt 0.794901 0.848257
+vt 0.640929 0.781632
+vt 0.666521 0.709568
+vt 0.636356 0.848259
+vt 0.205395 0.840356
+vt 0.165057 0.839231
+vt 0.168249 0.792680
+vt 0.206812 0.794023
+vt 0.214392 0.891615
+vt 0.161589 0.882055
+vt 0.241265 0.839077
+vt 0.247916 0.875817
+vt 0.243291 0.795273
+vt 0.050187 0.844482
+vt 0.081566 0.837294
+vt 0.084989 0.865972
+vt 0.061577 0.879960
+vt 0.047164 0.795723
+vt 0.080136 0.794155
+vt 0.030751 0.849572
+vt 0.011363 0.854676
+vt 0.008122 0.795077
+vt 0.027453 0.795879
+vt 0.044980 0.890795
+vt 0.027199 0.901816
+vt 0.050209 0.754404
+vt 0.083344 0.757041
+vt 0.057188 0.711303
+vt 0.086190 0.724548
+vt 0.031763 0.751718
+vt 0.009998 0.749349
+vt 0.013882 0.699460
+vt 0.035870 0.704195
+vt 0.280653 0.747292
+vt 0.249910 0.749310
+vt 0.259406 0.709407
+vt 0.282503 0.708944
+vt 0.277433 0.794536
+vt 0.300327 0.744987
+vt 0.298944 0.794473
+vt 0.300463 0.703752
+vt 0.275598 0.840835
+vt 0.272406 0.880931
+vt 0.297897 0.842557
+vt 0.296112 0.884965
+vt 0.215427 0.747718
+vt 0.173187 0.745804
+vt 0.181086 0.695152
+vt 0.230402 0.702057
+vt 0.124974 0.748995
+vt 0.121499 0.706399
+vt 0.122778 0.792952
+vt 0.121636 0.837433
+vt 0.114850 0.872809
+vt 0.211767 0.938667
+vt 0.151460 0.924131
+vt 0.206881 0.967319
+vt 0.202444 0.993810
+vt 0.133578 0.975415
+vt 0.143009 0.950086
+vt 0.284332 0.935822
+vt 0.254612 0.922405
+vt 0.097049 0.903456
+vt 0.083305 0.923173
+vt 0.068619 0.942013
+vt 0.194143 0.656045
+vt 0.184361 0.577417
+vt 0.247489 0.577466
+vt 0.266383 0.646033
+vt 0.095483 0.657314
+vt 0.069552 0.635446
+vt 0.023577 0.623156
+vt 0.289968 0.643994
+vt 0.071392 0.577421
+vt 0.119669 0.577423
+vt 0.120835 0.534998
+vt 0.185223 0.534962
+vt 0.282127 0.577464
+vt 0.284898 0.535025
+vt 0.299459 0.284656
+vt 0.269410 0.300468
+vt 0.267320 0.274905
+vt 0.294776 0.271386
+vt 0.306484 0.250312
+vt 0.293315 0.242924
+vt 0.245931 0.535039
+vt 0.071962 0.534946
+vt 0.275823 0.248153
+vt 0.301489 0.253434
+vt 0.307265 0.286217
+vt 0.293325 0.304171
+vt 0.208695 0.372787
+vt 0.194848 0.354981
+vt 0.207736 0.335642
+vt 0.238048 0.352770
+vt 0.289297 0.329143
+vt 0.284195 0.358809
+vt 0.249789 0.357798
+vt 0.260662 0.326638
+vt 0.291825 0.210419
+vt 0.282910 0.178142
+vt 0.240092 0.219225
+vt 0.207156 0.229503
+vt 0.203883 0.206876
+vt 0.237038 0.193441
+vt 0.284744 0.054246
+vt 0.283530 0.018181
+vt 0.253997 0.479174
+vt 0.252661 0.512749
+vt 0.215378 0.512749
+vt 0.215164 0.479218
+vt 0.212078 0.054277
+vt 0.209691 0.018239
+vt 0.247220 0.018239
+vt 0.250975 0.054268
+vt 0.285805 0.479156
+vt 0.285667 0.512634
+vt 0.285068 0.404567
+vt 0.285942 0.441555
+vt 0.255333 0.441555
+vt 0.252561 0.404567
+vt 0.211458 0.128944
+vt 0.214464 0.091875
+vt 0.254730 0.091874
+vt 0.251290 0.128949
+vt 0.214951 0.441555
+vt 0.213861 0.404572
+vt 0.284433 0.128947
+vt 0.285957 0.091875
+vt 0.249199 0.274905
+vt 0.212908 0.274933
+vt 0.211924 0.254886
+vt 0.247827 0.250786
+vt 0.210380 0.317703
+vt 0.243254 0.323720
+vt 0.634500 0.156150
+vt 0.634082 0.122612
+vt 0.654909 0.122612
+vt 0.655078 0.156147
+vt 0.620451 0.217712
+vt 0.631999 0.209717
+vt 0.631977 0.231864
+vt 0.985614 0.217712
+vt 0.973899 0.231864
+vt 0.973876 0.209717
+vt 0.255597 0.215743
+vt 0.247850 0.179997
+vt 0.028247 0.577410
+vt 0.025045 0.534903
+vt 0.674703 0.200706
+vt 0.671910 0.232049
+vt 0.931173 0.200706
+vt 0.933965 0.232049
+vt 0.697013 0.172839
+vt 0.708058 0.163092
+vt 0.908862 0.172839
+vt 0.897817 0.163092
+vt 0.673508 0.108499
+vt 0.673582 0.095822
+vt 0.691950 0.095821
+vt 0.691886 0.108499
+vt 0.677624 0.156136
+vt 0.673434 0.122612
+vt 0.691822 0.122612
+vt 0.697044 0.156121
+vt 0.971375 0.156150
+vt 0.971794 0.122612
+vt 0.984917 0.122612
+vt 0.985209 0.156148
+vt 0.928252 0.156136
+vt 0.932441 0.122612
+vt 0.951042 0.122612
+vt 0.950589 0.156147
+vt 0.970997 0.095822
+vt 0.968881 0.054984
+vt 0.984631 0.054984
+vt 0.984867 0.095820
+vt 0.971395 0.108499
+vt 0.984892 0.108499
+vt 0.932368 0.108499
+vt 0.932294 0.095822
+vt 0.950965 0.095821
+vt 0.634480 0.108499
+vt 0.634879 0.095822
+vt 0.654938 0.095821
+vt 0.654923 0.108499
+vt 0.654936 0.054984
+vt 0.654925 0.016269
+vt 0.670270 0.016269
+vt 0.670948 0.054984
+vt 0.934928 0.054984
+vt 0.950969 0.054984
+vt 0.636994 0.054984
+vt 0.690377 0.054983
+vt 0.620779 0.156148
+vt 0.908832 0.156121
+vt 0.621056 0.095820
+vt 0.621248 0.054984
+vt 0.913926 0.095821
+vt 0.915498 0.054983
+vt 0.689838 0.016269
+vt 0.621036 0.108499
+vt 0.913990 0.108499
+vt 0.914054 0.122612
+vt 0.621016 0.122612
+vt 0.935606 0.016269
+vt 0.950999 0.016269
+vt 0.621289 0.016268
+vt 0.637047 0.016268
+vt 0.176090 0.220682
+vt 0.145191 0.220694
+vt 0.145087 0.204123
+vt 0.175901 0.204123
+vt 0.176179 0.257611
+vt 0.145241 0.257656
+vt 0.145210 0.238484
+vt 0.176125 0.238395
+vt 0.176168 0.302520
+vt 0.145242 0.302415
+vt 0.145255 0.286054
+vt 0.176196 0.286099
+vt 0.145244 0.274996
+vt 0.176147 0.274965
+vt 0.213159 0.292296
+vt 0.249624 0.292358
+vt 0.190858 0.203868
+vt 0.204472 0.190753
+vt 0.059422 0.286044
+vt 0.031066 0.286124
+vt 0.031049 0.275075
+vt 0.059417 0.275048
+vt 0.059492 0.354952
+vt 0.031128 0.354952
+vt 0.031124 0.326827
+vt 0.059475 0.326819
+vt 0.059279 0.238666
+vt 0.030929 0.238598
+vt 0.030921 0.220705
+vt 0.059276 0.220716
+vt 0.031084 0.302521
+vt 0.059440 0.302276
+vt 0.176146 0.326829
+vt 0.145236 0.326824
+vt 0.175964 0.354952
+vt 0.145141 0.354952
+vt 0.936052 0.597770
+vt 0.923354 0.589708
+vt 0.924484 0.570357
+vt 0.936057 0.576206
+vt 0.936019 0.649366
+vt 0.913751 0.650767
+vt 0.916692 0.634633
+vt 0.936061 0.627368
+vt 0.915592 0.611553
+vt 0.935975 0.612170
+vt 0.797433 0.319246
+vt 0.796272 0.333957
+vt 0.827484 0.332708
+vt 0.818957 0.316206
+vt 0.059362 0.257746
+vt 0.031009 0.257741
+vt 0.030934 0.204124
+vt 0.059305 0.204124
+vt 0.118260 0.275008
+vt 0.093911 0.275019
+vt 0.093876 0.257696
+vt 0.118252 0.257676
+vt 0.118222 0.220700
+vt 0.093831 0.220705
+vt 0.093754 0.204124
+vt 0.118173 0.204123
+vt 0.093831 0.238570
+vt 0.118261 0.302386
+vt 0.093919 0.302358
+vt 0.093909 0.286048
+vt 0.118265 0.286051
+vt 0.118262 0.326824
+vt 0.093936 0.326823
+vt 0.118215 0.354952
+vt 0.093852 0.354952
+vt 0.208452 0.175985
+vt 0.212772 0.376778
+vt 0.885489 0.613407
+vt 0.886139 0.592404
+vt 0.775283 0.328531
+vt 0.777696 0.360523
+vt 0.798255 0.363832
+vt 0.879743 0.573056
+vt 0.891403 0.648951
+vt 0.891428 0.633182
+vt 0.782396 0.317514
+vt 0.936077 0.668483
+vt 0.917897 0.663357
+vt 0.934937 0.562431
+vt 0.948678 0.563037
+vt 0.849446 0.644672
+vt 0.835215 0.641481
+vt 0.836574 0.633887
+vt 0.850848 0.634574
+vt 0.831637 0.625377
+vt 0.845604 0.622687
+vt 0.803215 0.409166
+vt 0.803234 0.427265
+vt 0.826158 0.420164
+vt 0.827672 0.401768
+vt 0.838730 0.600779
+vt 0.825771 0.609744
+vt 0.818842 0.606128
+vt 0.832383 0.595050
+vt 0.891712 0.662885
+vt 0.868635 0.564528
+vt 0.871852 0.553715
+vt 0.888276 0.556840
+vt 0.827416 0.356136
+vt 0.824304 0.626881
+vt 0.812578 0.624567
+vt 0.828470 0.646582
+vt 0.830902 0.615677
+vt 0.844827 0.609883
+vt 0.785826 0.405163
+vt 0.786898 0.423198
+vt 0.844902 0.653006
+vt 0.876523 0.661158
+vt 0.861333 0.659431
+vt 0.863677 0.647862
+vt 0.877540 0.648407
+vt 0.872530 0.616702
+vt 0.859570 0.619998
+vt 0.858753 0.604088
+vt 0.872446 0.598246
+vt 0.781225 0.373826
+vt 0.784753 0.387128
+vt 0.803196 0.391068
+vt 0.800726 0.377450
+vt 0.851688 0.591814
+vt 0.865716 0.582435
+vt 0.845924 0.583972
+vt 0.857280 0.574250
+vt 0.829185 0.383372
+vt 0.828300 0.369754
+vt 0.878275 0.634222
+vt 0.865123 0.635262
+vt 0.914893 0.555304
+vt 0.906852 0.540600
+vt 0.915395 0.533196
+vt 0.924568 0.548786
+vt 0.761358 0.338190
+vt 0.766667 0.356086
+vt 0.749140 0.351639
+vt 0.737870 0.373475
+vt 0.748724 0.380794
+vt 0.764617 0.362075
+vt 0.885620 0.549316
+vt 0.871635 0.545787
+vt 0.894491 0.523813
+vt 0.887040 0.527237
+vt 0.881647 0.520255
+vt 0.897126 0.516070
+vt 0.968828 0.016268
+vt 0.984580 0.016268
+vt 0.916038 0.016269
+vt 0.934523 0.917621
+vt 0.931424 0.935204
+vt 0.938408 0.927193
+vt 0.941572 0.917780
+vt 0.930002 0.891877
+vt 0.937875 0.903075
+vt 0.864084 0.887068
+vt 0.863938 0.917771
+vt 0.880234 0.917771
+vt 0.879260 0.892026
+vt 0.867026 0.945729
+vt 0.881621 0.944002
+vt 0.831347 0.917772
+vt 0.836681 0.941421
+vt 0.852052 0.944907
+vt 0.847642 0.917771
+vt 0.834066 0.892248
+vt 0.849018 0.887068
+vt 0.904024 0.888613
+vt 0.906398 0.917771
+vt 0.916266 0.917771
+vt 0.913129 0.887745
+vt 0.905572 0.938997
+vt 0.914714 0.939860
+vt 0.819931 0.904999
+vt 0.818111 0.917687
+vt 0.821392 0.930376
+vt 0.896042 0.940231
+vt 0.896530 0.917771
+vt 0.894944 0.890609
+vt 0.686042 0.524352
+vt 0.708647 0.518689
+vt 0.709177 0.537312
+vt 0.692687 0.540948
+vt 0.636372 0.667162
+vt 0.635921 0.656300
+vt 0.651714 0.656493
+vt 0.651227 0.666984
+vt 0.781285 0.609428
+vt 0.785249 0.620097
+vt 0.765233 0.626167
+vt 0.761520 0.615688
+vt 0.644711 0.596297
+vt 0.648718 0.581418
+vt 0.667739 0.587337
+vt 0.663002 0.601458
+vt 0.655822 0.561957
+vt 0.674036 0.573634
+vt 0.636733 0.638857
+vt 0.638119 0.622878
+vt 0.655630 0.626375
+vt 0.652694 0.640638
+vt 0.751631 0.535644
+vt 0.762210 0.560416
+vt 0.744045 0.569271
+vt 0.736483 0.548184
+vt 0.787716 0.631988
+vt 0.770153 0.638555
+vt 0.791176 0.645197
+vt 0.775239 0.650769
+vt 0.756154 0.602668
+vt 0.747050 0.618300
+vt 0.741245 0.605142
+vt 0.750033 0.585655
+vt 0.738203 0.591970
+vt 0.733559 0.579024
+vt 0.728733 0.562733
+vt 0.683603 0.550467
+vt 0.699215 0.546547
+vt 0.690416 0.564106
+vt 0.678881 0.591921
+vt 0.676012 0.602550
+vt 0.666074 0.642176
+vt 0.663882 0.657641
+vt 0.651365 0.677015
+vt 0.662728 0.668313
+vt 0.662980 0.677015
+vt 0.726341 0.539931
+vt 0.719028 0.546474
+vt 0.779342 0.664126
+vt 0.767486 0.666511
+vt 0.763261 0.656022
+vt 0.758344 0.643339
+vt 0.753283 0.628664
+vt 0.683726 0.579931
+vt 0.658998 0.614197
+vt 0.672082 0.616741
+vt 0.669471 0.627536
+vt 0.779389 0.677016
+vt 0.770165 0.677015
+vt 0.745182 0.648362
+vt 0.737201 0.634733
+vt 0.696399 0.576131
+vt 0.691285 0.585364
+vt 0.672552 0.660852
+vt 0.671485 0.670160
+vt 0.692397 0.606771
+vt 0.695369 0.619169
+vt 0.684166 0.635721
+vt 0.757870 0.677015
+vt 0.755280 0.669527
+vt 0.689760 0.595785
+vt 0.751861 0.659762
+vt 0.724212 0.618997
+vt 0.726110 0.606671
+vt 0.727889 0.595831
+vt 0.728493 0.586086
+vt 0.723396 0.575823
+vt 0.702738 0.563637
+vt 0.676524 0.647357
+vt 0.669891 0.677015
+vt 0.715467 0.563548
+vt 0.747228 0.672502
+vt 0.744669 0.663180
+vt 0.679473 0.664199
+vt 0.678437 0.672191
+vt 0.740064 0.651011
+vt 0.676547 0.677015
+vt 0.731566 0.638069
+vt 0.718813 0.627622
+vt 0.681227 0.650664
+vt 0.749692 0.677015
+vt 0.689654 0.638630
+vt 0.701529 0.627703
+vt 0.732176 0.523263
+vt 0.685735 0.677015
+vt 0.686228 0.666838
+vt 0.741198 0.677015
+vt 0.688358 0.652787
+vt 0.697308 0.643104
+vt 0.734468 0.653528
+vt 0.739084 0.666015
+vt 0.710741 0.639927
+vt 0.725417 0.642145
+vt 0.794526 0.663780
+vt 0.769330 0.578484
+vt 0.775733 0.594543
+vt 0.794904 0.677014
+vt 0.641034 0.610282
+vt 0.666728 0.538248
+vt 0.636356 0.677015
+vn 0.9457 0.1443 0.2913
+vn 0.9564 -0.0041 0.2922
+vn 0.9998 -0.0209 -0.0009
+vn 0.9824 0.1864 0.0134
+vn 0.7379 0.6737 0.0405
+vn 0.7078 0.6423 0.2941
+vn 0.6460 0.4611 0.6084
+vn 0.7695 0.1073 0.6296
+vn 0.7886 0.0331 0.6140
+vn 0.3103 0.2935 -0.9042
+vn 0.3025 0.7212 -0.6232
+vn 0.6054 0.6169 -0.5030
+vn 0.7379 0.2250 -0.6362
+vn 0.7562 -0.0103 -0.6543
+vn 0.3308 0.0001 -0.9437
+vn 0.1084 0.3109 -0.9442
+vn 0.0989 0.0136 -0.9950
+vn -0.0000 0.0197 -0.9998
+vn -0.0000 0.3126 -0.9499
+vn -0.0000 0.7558 -0.6548
+vn 0.1472 0.7442 -0.6515
+vn 0.3550 -0.2096 -0.9110
+vn 0.7477 -0.1850 -0.6378
+vn 0.6791 -0.4538 -0.5770
+vn 0.3752 -0.5647 -0.7350
+vn 0.1368 -0.2014 -0.9699
+vn 0.1695 -0.6011 -0.7810
+vn 0.0000 -0.6130 -0.7901
+vn -0.0000 -0.2004 -0.9797
+vn 0.4474 -0.0538 0.8927
+vn 0.4742 -0.5231 0.7082
+vn 0.7731 -0.4655 0.4308
+vn 0.8083 -0.0705 0.5845
+vn 0.4476 0.0625 0.8920
+vn 0.1322 -0.0587 0.9895
+vn 0.1444 0.0607 0.9877
+vn -0.0000 0.0525 0.9986
+vn 0.0000 -0.0698 0.9976
+vn 0.0000 -0.6245 0.7810
+vn 0.2144 -0.6358 0.7415
+vn 0.4047 0.1590 0.9005
+vn 0.3492 0.5807 0.7354
+vn 0.1784 0.2024 0.9629
+vn 0.2000 0.6209 0.7580
+vn 0.0000 0.6376 0.7704
+vn -0.0000 0.1969 0.9804
+vn 0.9553 -0.1362 0.2625
+vn 0.8333 -0.5293 0.1596
+vn 0.8217 -0.5659 -0.0678
+vn 0.9850 -0.1721 -0.0131
+vn 0.9458 -0.1792 -0.2708
+vn 0.7735 -0.5442 -0.3250
+vn 0.9657 -0.0170 -0.2589
+vn 0.9520 0.1879 -0.2416
+vn 0.7174 0.6660 -0.2046
+vn 0.2950 0.9058 0.3042
+vn 0.3086 0.9496 0.0553
+vn 0.1702 0.9347 0.3120
+vn 0.1370 0.9891 0.0545
+vn 0.0000 0.9989 0.0475
+vn 0.0000 0.9489 0.3155
+vn 0.2964 0.9341 -0.1988
+vn 0.1395 0.9681 -0.2083
+vn 0.0000 0.9774 -0.2113
+vn 0.5914 -0.8002 -0.0998
+vn 0.4555 -0.8719 0.1795
+vn 0.6394 -0.6842 0.3507
+vn 0.8795 -0.4694 -0.0788
+vn 0.4438 -0.7827 -0.4363
+vn 0.1549 -0.8154 -0.5578
+vn 0.0000 -0.8224 -0.5689
+vn 0.2065 -0.9492 0.2376
+vn -0.0000 -0.9727 0.2319
+vn 0.6646 -0.5276 -0.5291
+vn 0.2417 -0.5411 -0.8054
+vn 0.7131 0.6934 0.1032
+vn 0.5830 0.4427 -0.6813
+vn 0.3650 -0.6772 0.6388
+vn -0.0000 -0.7727 0.6348
+vn 0.0000 0.2392 0.9710
+vn 0.3422 0.2291 0.9113
+vn 0.2187 0.9685 0.1193
+vn 0.2776 0.7794 -0.5617
+vn 0.0000 0.4232 0.9060
+vn 0.2215 0.4915 0.8423
+vn 0.5299 0.4783 0.7003
+vn 0.3187 0.1528 -0.9355
+vn 0.2344 0.7167 0.6568
+vn 0.2099 0.4105 -0.8874
+vn 0.3673 -0.9301 0.0098
+vn 0.3974 -0.5924 -0.7008
+vn 0.1794 -0.6195 -0.7642
+vn 0.0690 -0.9969 -0.0385
+vn 0.1877 0.1073 -0.9763
+vn 0.2476 0.0854 -0.9651
+vn 0.4933 -0.2459 -0.8344
+vn 0.2022 -0.1020 -0.9740
+vn 0.2329 0.2954 0.9266
+vn 0.0000 0.3022 0.9532
+vn -0.0000 0.1792 0.9838
+vn 0.2403 0.1796 0.9539
+vn 0.2128 0.2478 0.9452
+vn 0.4914 -0.2255 0.8412
+vn 0.1337 -0.5254 0.8403
+vn 0.1148 0.2277 0.9669
+vn 0.2362 0.0566 0.9700
+vn 0.0000 0.0526 0.9986
+vn -0.0009 -0.0926 0.9957
+vn 0.2385 -0.0982 0.9662
+vn 0.7220 0.1360 -0.6784
+vn 0.9918 0.1212 0.0408
+vn 0.9923 0.0130 0.1231
+vn 0.7610 0.0535 -0.6465
+vn 0.6859 0.0936 0.7216
+vn 0.6979 -0.1956 0.6890
+vn 0.2849 0.1291 -0.9498
+vn 0.2636 0.0932 -0.9601
+vn 0.2253 -0.1212 -0.9667
+vn 0.6874 -0.1083 -0.7181
+vn 0.7076 0.0146 -0.7065
+vn 0.2536 0.0037 -0.9673
+vn 0.9995 -0.0294 0.0078
+vn 0.6908 0.0535 0.7211
+vn 0.6725 0.0801 0.7358
+vn 0.9981 0.0555 0.0252
+vn 0.2430 0.0914 0.9657
+vn -0.0000 0.0953 0.9955
+vn 0.0000 0.0740 0.9973
+vn 0.2426 0.0741 0.9673
+vn 0.2022 0.9739 0.1031
+vn 0.2013 0.6974 0.6878
+vn 0.1541 0.6819 0.7150
+vn 0.1655 0.9817 0.0947
+vn 0.3004 0.0419 -0.9529
+vn 0.1688 0.0258 -0.9853
+vn 0.4500 -0.1523 0.8799
+vn -0.4454 -0.1944 0.8740
+vn -0.3460 -0.2779 0.8962
+vn 0.3766 -0.1964 0.9053
+vn 0.5997 -0.3336 0.7274
+vn 0.8694 -0.0087 -0.4940
+vn 0.0000 0.3057 -0.9521
+vn 0.0000 0.1113 -0.9938
+vn 0.2453 0.2787 0.9285
+vn 0.0000 -0.1176 -0.9931
+vn 0.0000 0.0149 -0.9999
+vn -0.0000 0.1493 -0.9888
+vn 0.0000 0.0659 -0.9978
+vn 0.6091 0.0343 0.7924
+vn 0.0000 -0.0920 -0.9958
+vn 0.0000 0.1404 -0.9901
+vn 0.0000 -0.4846 -0.8747
+vn 0.1067 -0.4160 0.9031
+vn 0.3116 -0.0248 -0.9499
+vn -0.0013 -0.6103 0.7922
+vn 0.0003 -0.9575 0.2883
+vn -0.0006 -0.9977 -0.0685
+vn -0.5755 -0.7952 -0.1911
+vn -0.5898 -0.6462 0.4843
+vn -0.0011 -0.1368 -0.9906
+vn -0.1764 -0.3704 -0.9120
+vn -0.0020 -0.7436 -0.6687
+vn -0.9340 -0.1822 0.3072
+vn -0.9184 0.0606 -0.3909
+vn -0.9107 0.0462 -0.4104
+vn -0.9365 -0.1814 0.3002
+vn -0.9426 -0.1215 0.3112
+vn -0.9450 -0.1377 -0.2966
+vn -0.9243 -0.0652 -0.3762
+vn -0.9228 -0.2105 0.3226
+vn 0.8756 0.0396 -0.4815
+vn 0.9476 -0.0151 0.3190
+vn 0.9181 -0.0664 0.3906
+vn 0.9077 0.0723 -0.4133
+vn -0.4433 -0.1404 -0.8853
+vn 0.3698 -0.0259 -0.9287
+vn 0.3708 0.1432 -0.9176
+vn -0.4292 0.0769 -0.8999
+vn 0.8919 0.1157 -0.4372
+vn 0.9256 -0.1284 0.3562
+vn 0.9305 -0.2256 0.2887
+vn 0.8784 -0.1012 -0.4671
+vn 0.8901 0.1775 -0.4199
+vn 0.9257 -0.0826 0.3690
+vn -0.3939 0.2181 -0.8929
+vn -0.4115 0.2799 -0.8674
+vn 0.3324 0.2377 -0.9127
+vn 0.3702 -0.2797 0.8858
+vn -0.3684 -0.3290 0.8695
+vn -0.3734 -0.3396 0.8633
+vn 0.3699 -0.3096 0.8760
+vn -0.3218 -0.2828 0.9036
+vn -0.9240 -0.1780 0.3384
+vn -0.9034 -0.0051 0.4289
+vn -0.1555 0.0783 0.9847
+vn 0.2807 -0.0015 -0.9598
+vn -0.4512 0.0172 -0.8923
+vn 0.4510 -0.2961 0.8420
+vn -0.9203 -0.0430 -0.3889
+vn -0.9785 0.0388 -0.2025
+vn 0.1337 0.2725 -0.9528
+vn -0.6002 0.0760 -0.7962
+vn 0.6684 0.1792 0.7219
+vn 0.9807 0.1591 0.1132
+vn 0.0231 -0.5921 0.8055
+vn -0.0441 -0.9976 -0.0530
+vn -0.0785 -0.9958 -0.0464
+vn -0.0514 -0.6426 0.7645
+vn 0.1031 0.6834 0.7227
+vn 0.0614 0.1922 0.9794
+vn -0.0142 0.1514 0.9884
+vn 0.0418 0.7022 0.7108
+vn 0.0286 0.0423 -0.9987
+vn 0.1078 0.7277 -0.6773
+vn 0.0901 0.7629 -0.6402
+vn 0.0343 0.0455 -0.9984
+vn 0.1349 0.9851 0.1063
+vn 0.0795 0.9895 0.1207
+vn 0.2886 0.7054 -0.6474
+vn 0.2213 0.7031 -0.6758
+vn 0.1543 0.8126 -0.5621
+vn 0.1374 0.9816 0.1329
+vn 0.3013 0.9452 0.1258
+vn 0.1981 0.8835 -0.4245
+vn 0.0229 -0.9997 -0.0021
+vn 0.0623 -0.6655 -0.7438
+vn 0.0341 -0.7440 -0.6674
+vn 0.1430 -0.9897 0.0080
+vn 0.0423 0.1045 0.9936
+vn 0.0253 -0.6320 0.7746
+vn 0.0240 -0.7308 0.6822
+vn -0.3127 0.2099 0.9264
+vn 0.0965 0.0398 -0.9945
+vn -0.1350 0.1050 -0.9853
+vn -0.0256 -0.6368 -0.7706
+vn -0.0322 -0.6542 -0.7556
+vn 0.1349 0.8453 0.5169
+vn -0.4932 0.4930 0.7168
+vn -0.0139 0.8416 0.5400
+vn 0.0750 0.8493 -0.5225
+vn -0.1172 0.0807 -0.9898
+vn 0.2518 0.9644 0.0807
+vn -0.1514 -0.7066 -0.6913
+vn 0.0599 -0.9980 0.0190
+vn 0.1047 0.7466 0.6570
+vn 0.0280 0.9910 0.1306
+vn -0.0336 0.7148 0.6986
+vn 0.0289 0.7181 0.6953
+vn 0.0847 0.9874 0.1334
+vn -0.1332 -0.6247 0.7694
+vn -0.1064 -0.9942 -0.0166
+vn -0.0407 -0.9991 0.0079
+vn -0.0547 -0.6278 0.7764
+vn -0.0227 0.1091 0.9938
+vn 0.0379 0.0500 -0.9980
+vn 0.0584 0.7850 -0.6168
+vn 0.0999 0.7937 -0.6001
+vn 0.0656 0.0439 -0.9969
+vn -0.0380 -0.6635 -0.7472
+vn 0.0085 -0.6713 -0.7411
+vn 0.8732 -0.4872 0.0139
+vn 0.1845 0.8730 0.4514
+vn 0.2209 0.9735 0.0600
+vn -0.5726 -0.6425 0.5092
+vn -0.1516 -0.9884 -0.0104
+vn 0.1681 -0.8946 0.4139
+vn 0.3284 0.3520 0.8765
+vn 0.1938 0.8999 -0.3906
+vn 0.0779 0.1056 -0.9914
+vn 0.2088 0.0236 -0.9777
+vn 0.4326 0.8074 -0.4012
+vn 0.8096 0.4726 -0.3482
+vn 0.6046 -0.1712 -0.7779
+vn 0.4070 0.9114 0.0607
+vn 0.9199 0.3892 0.0477
+vn -0.3275 -0.9444 -0.0292
+vn -0.1998 -0.8212 -0.5345
+vn 0.2486 -0.8576 -0.4502
+vn 0.4146 -0.9085 0.0525
+vn 0.0541 0.2120 0.9758
+vn -0.2886 -0.7432 0.6036
+vn 0.1971 -0.7858 0.5863
+vn 0.5629 -0.0268 0.8261
+vn -0.0910 -0.8166 -0.5699
+vn 0.5147 0.8181 0.2567
+vn 0.2374 -0.8666 -0.4388
+vn 0.9324 -0.3612 0.0109
+vn 0.7483 0.4975 0.4388
+vn 0.3372 0.8276 0.4488
+vn -0.1555 -0.8122 -0.5622
+vn 0.0736 0.0760 -0.9944
+vn 0.1485 0.0722 -0.9863
+vn -0.1638 -0.8029 -0.5731
+vn 0.3115 0.9481 0.0636
+vn 0.3176 0.8353 0.4488
+vn 0.3268 0.8416 0.4299
+vn 0.3667 0.9284 0.0598
+vn -0.0652 -0.7833 0.6183
+vn -0.1876 -0.9821 -0.0192
+vn -0.2699 -0.9624 -0.0318
+vn -0.1672 -0.7777 0.6060
+vn 0.2008 0.1620 0.9661
+vn 0.1350 0.2102 0.9683
+vn 0.2863 0.8648 -0.4125
+vn 0.3527 0.8371 -0.4183
+vn -0.5104 0.6254 0.5902
+vn -0.7359 -0.6521 0.1822
+vn -0.5788 -0.7442 0.3334
+vn -0.4153 0.5623 0.7151
+vn 0.3722 -0.5937 -0.7135
+vn 0.7782 -0.6218 -0.0880
+vn 0.0267 -0.7229 0.6905
+vn 0.5714 0.7000 -0.4283
+vn 0.1233 0.3691 0.9212
+vn 0.8710 0.4712 0.1392
+vn 0.8376 0.2166 -0.5015
+vn -0.0000 -1.0000 0.0000
+vn 0.0084 -0.6750 -0.7378
+vn 0.3680 -0.6369 -0.6774
+vn 0.6015 -0.6121 -0.5133
+vn -0.6355 -0.6986 -0.3287
+vn -0.3370 -0.7295 -0.5952
+vn -0.7034 -0.7107 -0.0097
+vn -0.5972 -0.8019 0.0184
+vn 0.6442 -0.7370 -0.2048
+vn 0.6648 -0.7399 -0.1029
+vn 0.6664 -0.7454 0.0181
+vn 0.6517 -0.7303 0.2050
+vn -0.5592 -0.6963 0.4499
+vn -0.6826 -0.7042 0.1955
+vn -0.6484 -0.7443 0.1597
+vn -0.6932 -0.7206 0.0148
+vn 0.7022 -0.6799 -0.2114
+vn 0.6342 -0.7655 -0.1091
+vn -0.2498 -0.6440 0.7231
+vn 0.1061 -0.6663 0.7381
+vn 0.4440 -0.6813 0.5820
+vn 0.6185 -0.7625 -0.1899
+vn -0.6115 -0.7763 0.1532
+vn 0.6837 0.0752 0.7259
+vn 0.1525 0.1246 0.9804
+vn 0.4903 0.1374 -0.8606
+vn 0.7599 0.1599 -0.6301
+vn -0.9665 0.0230 0.2556
+vn -0.9782 0.0452 0.2028
+vn 0.9493 0.0983 -0.2986
+vn 0.9839 0.0914 -0.1536
+vn 0.9960 0.0812 0.0373
+vn 0.9159 0.1392 -0.3765
+vn 0.9780 0.0775 -0.1938
+vn -0.7453 0.1106 0.6575
+vn -0.9495 0.1270 0.2870
+vn -0.9970 0.0745 -0.0194
+vn -0.8740 0.0598 -0.4823
+vn -0.9951 0.0798 0.0585
+vn -0.8303 0.5511 0.0824
+vn -0.8523 0.3910 0.3476
+vn -0.9916 0.1283 0.0146
+vn -0.8484 0.5290 -0.0195
+vn -0.7014 0.4470 0.5552
+vn -0.8576 0.4754 0.1962
+vn 0.9409 0.0844 0.3281
+vn 0.8080 0.4997 0.3121
+vn 0.4611 0.4221 0.7805
+vn 0.8317 0.4977 -0.2460
+vn 0.8603 0.4813 -0.1678
+vn 0.7603 0.2592 -0.5956
+vn 0.8765 0.3184 -0.3611
+vn 0.0027 0.0640 -0.9979
+vn 0.0179 0.2134 -0.9768
+vn 0.5328 0.2307 -0.8142
+vn -0.3109 0.0989 0.9453
+vn -0.2355 0.3923 0.8892
+vn -0.9029 0.1928 -0.3842
+vn -0.5381 0.2055 -0.8174
+vn -0.5082 0.0300 -0.8607
+vn -0.9301 0.2315 0.2851
+vn -0.9798 0.1938 -0.0499
+vn 0.8834 0.4680 0.0259
+vn 0.9585 0.0708 -0.2762
+vn 0.8740 0.4463 -0.1921
+vn 0.9188 0.3598 -0.1622
+vn -0.8756 0.2043 0.4377
+vn -0.9977 0.0637 -0.0225
+vn 0.4477 0.8941 0.0123
+vn 0.4095 0.8844 0.2238
+vn 0.4740 0.2525 -0.8436
+vn 0.7825 0.3019 -0.5445
+vn 0.3908 0.8872 0.2453
+vn 0.4131 0.9101 -0.0329
+vn 0.7671 0.6409 -0.0280
+vn -0.5579 0.2025 -0.8048
+vn -0.0554 0.2166 -0.9747
+vn 0.4242 0.8999 -0.1010
+vn -0.9151 0.1009 -0.3904
+vn -0.3681 0.9119 0.1818
+vn -0.4525 0.6615 0.5981
+vn -0.3940 0.9187 -0.0283
+vn -0.4085 0.8532 0.3243
+vn -0.5208 0.8521 0.0525
+vn 0.2601 0.7859 0.5609
+vn 0.8501 0.4447 -0.2822
+vn -0.1194 0.7620 0.6365
+vn -0.8841 0.1773 -0.4324
+vn -0.4165 0.3095 -0.8548
+vn 0.3278 0.3994 -0.8562
+vn 0.6951 0.4915 -0.5247
+vn -0.9970 0.0755 -0.0137
+vn -0.1212 0.4521 -0.8837
+vn -0.1949 0.4563 0.8682
+vn -0.7707 0.2211 0.5976
+vn 0.8312 0.5333 -0.1575
+vn 0.6322 0.7536 0.1800
+vn 0.2893 0.7521 0.5922
+vn -0.9457 0.1443 0.2913
+vn -0.9824 0.1864 0.0134
+vn -0.9998 -0.0209 -0.0009
+vn -0.9564 -0.0041 0.2922
+vn -0.7078 0.6423 0.2941
+vn -0.7379 0.6737 0.0405
+vn -0.7695 0.1073 0.6296
+vn -0.6460 0.4611 0.6084
+vn -0.7886 0.0331 0.6140
+vn -0.3103 0.2935 -0.9042
+vn -0.7379 0.2250 -0.6362
+vn -0.6054 0.6169 -0.5030
+vn -0.3025 0.7212 -0.6232
+vn -0.3308 0.0001 -0.9437
+vn -0.7562 -0.0103 -0.6543
+vn -0.1084 0.3109 -0.9442
+vn -0.0989 0.0136 -0.9950
+vn -0.1472 0.7442 -0.6515
+vn -0.3550 -0.2096 -0.9110
+vn -0.7477 -0.1850 -0.6378
+vn -0.3752 -0.5647 -0.7350
+vn -0.6791 -0.4538 -0.5770
+vn -0.1368 -0.2014 -0.9699
+vn -0.1695 -0.6011 -0.7810
+vn -0.4474 -0.0538 0.8927
+vn -0.8083 -0.0705 0.5845
+vn -0.7731 -0.4655 0.4308
+vn -0.4742 -0.5231 0.7082
+vn -0.4476 0.0625 0.8920
+vn -0.1322 -0.0587 0.9895
+vn -0.1444 0.0607 0.9877
+vn -0.2144 -0.6358 0.7415
+vn -0.4047 0.1590 0.9005
+vn -0.3492 0.5807 0.7354
+vn -0.1784 0.2024 0.9629
+vn -0.2000 0.6209 0.7580
+vn -0.9553 -0.1362 0.2625
+vn -0.9850 -0.1721 -0.0131
+vn -0.8217 -0.5659 -0.0678
+vn -0.8333 -0.5293 0.1596
+vn -0.9458 -0.1792 -0.2708
+vn -0.7735 -0.5442 -0.3250
+vn -0.9657 -0.0170 -0.2589
+vn -0.9520 0.1879 -0.2416
+vn -0.7174 0.6660 -0.2046
+vn -0.2950 0.9058 0.3042
+vn -0.3086 0.9496 0.0553
+vn -0.1702 0.9347 0.3120
+vn -0.1370 0.9891 0.0545
+vn -0.2964 0.9341 -0.1988
+vn -0.1395 0.9681 -0.2083
+vn -0.5914 -0.8002 -0.0998
+vn -0.8795 -0.4694 -0.0788
+vn -0.6394 -0.6842 0.3507
+vn -0.4555 -0.8719 0.1795
+vn -0.4438 -0.7827 -0.4363
+vn -0.1549 -0.8154 -0.5578
+vn -0.2065 -0.9492 0.2376
+vn -0.2417 -0.5411 -0.8054
+vn -0.6646 -0.5276 -0.5291
+vn -0.5830 0.4427 -0.6813
+vn -0.7131 0.6934 0.1032
+vn -0.3650 -0.6772 0.6388
+vn -0.3422 0.2291 0.9113
+vn -0.2776 0.7794 -0.5617
+vn -0.2187 0.9685 0.1193
+vn -0.2215 0.4915 0.8423
+vn -0.5299 0.4783 0.7003
+vn -0.3187 0.1528 -0.9355
+vn -0.2344 0.7167 0.6568
+vn -0.2099 0.4105 -0.8874
+vn -0.3673 -0.9301 0.0098
+vn -0.0690 -0.9969 -0.0385
+vn -0.1794 -0.6195 -0.7642
+vn -0.3974 -0.5924 -0.7008
+vn -0.1877 0.1073 -0.9763
+vn -0.2022 -0.1020 -0.9740
+vn -0.4933 -0.2459 -0.8344
+vn -0.2476 0.0854 -0.9651
+vn -0.2329 0.2954 0.9266
+vn -0.2403 0.1796 0.9539
+vn -0.2128 0.2478 0.9452
+vn -0.1148 0.2277 0.9669
+vn -0.1337 -0.5254 0.8403
+vn -0.4914 -0.2255 0.8412
+vn -0.2364 0.0565 0.9700
+vn -0.2399 -0.1022 0.9654
+vn -0.7225 0.1357 -0.6780
+vn -0.7618 0.0546 -0.6455
+vn -0.9917 0.0127 0.1276
+vn -0.9918 0.1202 0.0423
+vn -0.6966 -0.1992 0.6893
+vn -0.6855 0.0928 0.7222
+vn -0.2849 0.1291 -0.9498
+vn -0.2631 0.0936 -0.9602
+vn -0.2253 -0.1212 -0.9667
+vn -0.2536 0.0037 -0.9673
+vn -0.7077 0.0144 -0.7064
+vn -0.6874 -0.1083 -0.7181
+vn -0.9995 -0.0294 0.0078
+vn -0.9982 0.0549 0.0255
+vn -0.6726 0.0797 0.7357
+vn -0.6908 0.0535 0.7211
+vn -0.2430 0.0914 0.9657
+vn -0.2426 0.0740 0.9673
+vn -0.2022 0.9739 0.1031
+vn -0.1655 0.9817 0.0947
+vn -0.1541 0.6819 0.7150
+vn -0.2013 0.6974 0.6878
+vn -0.1688 0.0258 -0.9853
+vn -0.3004 0.0419 -0.9529
+vn -0.4369 -0.1528 0.8864
+vn -0.3610 -0.1963 0.9117
+vn 0.3613 -0.2783 0.8900
+vn 0.4588 -0.1943 0.8670
+vn -0.5930 -0.3361 0.7317
+vn -0.8740 -0.0068 -0.4859
+vn -0.2453 0.2787 0.9285
+vn -0.6091 0.0343 0.7924
+vn -0.1059 -0.4199 0.9014
+vn -0.3165 -0.0232 -0.9483
+vn 0.5913 -0.6474 0.4808
+vn 0.5748 -0.7942 -0.1971
+vn 0.1734 -0.3703 -0.9126
+vn 0.9391 -0.1828 0.2909
+vn 0.9414 -0.1820 0.2838
+vn 0.9035 0.0456 -0.4262
+vn 0.9115 0.0601 -0.4068
+vn 0.9472 -0.1220 0.2966
+vn 0.9282 -0.2111 0.3065
+vn 0.9176 -0.0657 -0.3922
+vn 0.9397 -0.1373 -0.3132
+vn -0.8826 0.0408 -0.4683
+vn -0.9147 0.0729 -0.3974
+vn -0.9113 -0.0659 0.4065
+vn -0.9426 -0.0146 0.3336
+vn 0.4306 -0.1368 -0.8921
+vn 0.4136 0.0768 -0.9072
+vn -0.3866 0.1436 -0.9110
+vn -0.3825 -0.0232 -0.9236
+vn -0.8993 0.1163 -0.4216
+vn -0.8859 -0.1006 -0.4528
+vn -0.9258 -0.2249 0.3039
+vn -0.9193 -0.1278 0.3722
+vn -0.8971 0.1781 -0.4043
+vn -0.9193 -0.0821 0.3850
+vn 0.3966 0.2797 -0.8743
+vn 0.3785 0.2178 -0.8996
+vn -0.3480 0.2379 -0.9068
+vn -0.3550 -0.2796 0.8921
+vn -0.3548 -0.3094 0.8823
+vn 0.3881 -0.3399 0.8567
+vn 0.3832 -0.3294 0.8629
+vn 0.3361 -0.2834 0.8982
+vn 0.1673 0.0823 0.9825
+vn 0.9087 -0.0107 0.4173
+vn 0.9291 -0.1794 0.3233
+vn 0.4369 0.0163 -0.8994
+vn -0.2959 -0.0015 -0.9552
+vn -0.4374 -0.2958 0.8492
+vn 0.9138 -0.0443 -0.4037
+vn 0.9765 0.0369 -0.2121
+vn 0.5910 0.0741 -0.8033
+vn -0.1439 0.2747 -0.9507
+vn -0.9780 0.1679 0.1240
+vn -0.6588 0.1851 0.7292
+vn -0.0231 -0.5921 0.8055
+vn 0.0514 -0.6426 0.7645
+vn 0.0785 -0.9958 -0.0464
+vn 0.0441 -0.9976 -0.0530
+vn -0.1031 0.6834 0.7227
+vn -0.0417 0.7022 0.7107
+vn 0.0142 0.1514 0.9884
+vn -0.0614 0.1922 0.9794
+vn -0.0286 0.0423 -0.9987
+vn -0.0343 0.0455 -0.9984
+vn -0.0901 0.7629 -0.6402
+vn -0.1078 0.7277 -0.6773
+vn -0.0795 0.9895 0.1207
+vn -0.1349 0.9851 0.1063
+vn -0.2213 0.7031 -0.6758
+vn -0.2886 0.7054 -0.6474
+vn -0.1543 0.8126 -0.5621
+vn -0.1981 0.8835 -0.4245
+vn -0.3013 0.9452 0.1258
+vn -0.1374 0.9816 0.1329
+vn -0.0229 -0.9997 -0.0021
+vn -0.1430 -0.9897 0.0080
+vn -0.0341 -0.7440 -0.6674
+vn -0.0623 -0.6655 -0.7438
+vn -0.0423 0.1045 0.9936
+vn 0.3127 0.2099 0.9264
+vn -0.0240 -0.7308 0.6822
+vn -0.0253 -0.6320 0.7746
+vn 0.1350 0.1050 -0.9853
+vn -0.0965 0.0398 -0.9945
+vn 0.0256 -0.6368 -0.7706
+vn 0.0322 -0.6542 -0.7556
+vn -0.1349 0.8453 0.5169
+vn 0.0139 0.8416 0.5400
+vn 0.4932 0.4930 0.7168
+vn 0.1172 0.0807 -0.9898
+vn -0.0750 0.8493 -0.5225
+vn -0.2518 0.9644 0.0807
+vn -0.0599 -0.9980 0.0190
+vn 0.1514 -0.7066 -0.6913
+vn -0.1047 0.7466 0.6570
+vn -0.0280 0.9910 0.1306
+vn -0.0847 0.9874 0.1334
+vn -0.0289 0.7181 0.6953
+vn 0.0336 0.7148 0.6986
+vn 0.1332 -0.6247 0.7694
+vn 0.0547 -0.6278 0.7764
+vn 0.0407 -0.9991 0.0079
+vn 0.1064 -0.9942 -0.0166
+vn 0.0227 0.1091 0.9938
+vn -0.0379 0.0500 -0.9980
+vn -0.0656 0.0439 -0.9969
+vn -0.0999 0.7937 -0.6001
+vn -0.0584 0.7850 -0.6168
+vn 0.0380 -0.6635 -0.7472
+vn -0.0085 -0.6713 -0.7411
+vn -0.8732 -0.4872 0.0139
+vn -0.2209 0.9735 0.0600
+vn -0.1845 0.8730 0.4514
+vn 0.5726 -0.6425 0.5092
+vn -0.1681 -0.8946 0.4139
+vn 0.1516 -0.9884 -0.0104
+vn -0.3284 0.3520 0.8765
+vn -0.0779 0.1056 -0.9914
+vn -0.1938 0.8999 -0.3906
+vn -0.2088 0.0236 -0.9777
+vn -0.6045 -0.1712 -0.7779
+vn -0.8096 0.4726 -0.3482
+vn -0.4326 0.8074 -0.4012
+vn -0.9199 0.3892 0.0477
+vn -0.4070 0.9114 0.0607
+vn 0.3275 -0.9444 -0.0292
+vn -0.4146 -0.9085 0.0526
+vn -0.2486 -0.8576 -0.4502
+vn 0.1998 -0.8212 -0.5345
+vn -0.0541 0.2120 0.9758
+vn -0.5629 -0.0268 0.8261
+vn -0.1971 -0.7858 0.5863
+vn 0.2886 -0.7432 0.6036
+vn 0.0910 -0.8166 -0.5699
+vn -0.2374 -0.8666 -0.4388
+vn -0.5147 0.8181 0.2567
+vn -0.9324 -0.3612 0.0109
+vn -0.7483 0.4975 0.4388
+vn -0.3372 0.8276 0.4487
+vn 0.1555 -0.8122 -0.5622
+vn 0.1638 -0.8029 -0.5731
+vn -0.1485 0.0722 -0.9863
+vn -0.0736 0.0760 -0.9944
+vn -0.3115 0.9481 0.0636
+vn -0.3667 0.9284 0.0598
+vn -0.3268 0.8416 0.4299
+vn -0.3176 0.8353 0.4488
+vn 0.0652 -0.7833 0.6183
+vn 0.1672 -0.7777 0.6060
+vn 0.2699 -0.9624 -0.0318
+vn 0.1876 -0.9821 -0.0192
+vn -0.1350 0.2102 0.9683
+vn -0.2008 0.1620 0.9661
+vn -0.2863 0.8648 -0.4125
+vn -0.3527 0.8371 -0.4183
+vn 0.5104 0.6254 0.5902
+vn 0.4153 0.5623 0.7151
+vn 0.5788 -0.7442 0.3334
+vn 0.7359 -0.6521 0.1822
+vn -0.0267 -0.7229 0.6905
+vn -0.7782 -0.6218 -0.0880
+vn -0.3722 -0.5937 -0.7135
+vn -0.5714 0.7000 -0.4283
+vn -0.1233 0.3691 0.9212
+vn -0.8710 0.4712 0.1392
+vn -0.8425 0.2212 -0.4912
+vn -0.6016 -0.6121 -0.5133
+vn -0.3680 -0.6369 -0.6774
+vn -0.0084 -0.6750 -0.7378
+vn 0.6355 -0.6986 -0.3287
+vn 0.3370 -0.7295 -0.5952
+vn 0.7034 -0.7107 -0.0097
+vn 0.5971 -0.8019 0.0184
+vn -0.6648 -0.7399 -0.1029
+vn -0.6442 -0.7370 -0.2047
+vn -0.6517 -0.7302 0.2050
+vn -0.6664 -0.7454 0.0181
+vn 0.5592 -0.6963 0.4499
+vn 0.6826 -0.7042 0.1954
+vn 0.6484 -0.7443 0.1597
+vn 0.6931 -0.7206 0.0148
+vn -0.6342 -0.7655 -0.1091
+vn -0.7022 -0.6799 -0.2114
+vn 0.2498 -0.6440 0.7231
+vn -0.1061 -0.6663 0.7381
+vn -0.4440 -0.6813 0.5820
+vn -0.6185 -0.7625 -0.1899
+vn 0.6115 -0.7763 0.1532
+vn -0.1525 0.1246 0.9804
+vn -0.6837 0.0753 0.7259
+vn -0.7599 0.1599 -0.6301
+vn -0.4904 0.1374 -0.8606
+vn 0.9782 0.0451 0.2028
+vn 0.9665 0.0229 0.2556
+vn -0.9839 0.0914 -0.1535
+vn -0.9493 0.0983 -0.2986
+vn -0.9960 0.0812 0.0373
+vn -0.9780 0.0775 -0.1937
+vn -0.9159 0.1393 -0.3765
+vn 0.9495 0.1269 0.2870
+vn 0.7453 0.1105 0.6575
+vn 0.9970 0.0744 -0.0194
+vn 0.8740 0.0597 -0.4823
+vn 0.9951 0.0798 0.0585
+vn 0.8523 0.3909 0.3475
+vn 0.8304 0.5511 0.0824
+vn 0.9916 0.1283 0.0146
+vn 0.8484 0.5290 -0.0195
+vn 0.8577 0.4753 0.1961
+vn 0.7014 0.4469 0.5552
+vn -0.9409 0.0844 0.3281
+vn -0.4611 0.4221 0.7805
+vn -0.8080 0.4997 0.3121
+vn -0.8603 0.4813 -0.1678
+vn -0.8317 0.4977 -0.2460
+vn -0.8765 0.3184 -0.3610
+vn -0.7604 0.2592 -0.5955
+vn -0.0027 0.0640 -0.9979
+vn -0.5328 0.2307 -0.8142
+vn -0.0179 0.2134 -0.9768
+vn 0.3109 0.0989 0.9453
+vn 0.2355 0.3923 0.8892
+vn 0.5083 0.0300 -0.8607
+vn 0.5382 0.2055 -0.8174
+vn 0.9029 0.1928 -0.3841
+vn 0.9798 0.1938 -0.0499
+vn 0.9302 0.2314 0.2851
+vn -0.8834 0.4680 0.0259
+vn -0.9585 0.0708 -0.2762
+vn -0.8740 0.4463 -0.1920
+vn -0.9188 0.3598 -0.1622
+vn 0.9977 0.0636 -0.0225
+vn 0.8756 0.2043 0.4376
+vn -0.4095 0.8845 0.2238
+vn -0.4477 0.8941 0.0123
+vn -0.7826 0.3019 -0.5445
+vn -0.4740 0.2525 -0.8436
+vn -0.4131 0.9101 -0.0329
+vn -0.3908 0.8872 0.2454
+vn -0.7671 0.6409 -0.0280
+vn 0.0554 0.2166 -0.9747
+vn 0.5579 0.2025 -0.8048
+vn -0.4242 0.8999 -0.1010
+vn 0.9151 0.1009 -0.3904
+vn 0.4525 0.6614 0.5981
+vn 0.3681 0.9118 0.1818
+vn 0.3940 0.9187 -0.0283
+vn 0.5208 0.8521 0.0525
+vn 0.4086 0.8532 0.3243
+vn -0.2601 0.7859 0.5609
+vn -0.8501 0.4447 -0.2822
+vn 0.1194 0.7620 0.6365
+vn 0.4148 0.3089 -0.8559
+vn 0.8842 0.1771 -0.4323
+vn -0.6931 0.4946 -0.5244
+vn -0.3279 0.4006 -0.8556
+vn 0.9973 0.0714 -0.0155
+vn 0.1210 0.4544 -0.8825
+vn 0.7698 0.2210 0.5987
+vn 0.1922 0.4608 0.8664
+vn -0.8281 0.5387 -0.1555
+vn -0.6279 0.7573 0.1795
+vn -0.2868 0.7541 0.5909
+usemtl skin
+s 1
+f 1/1/1 27/2/2 41/3/3 30/4/4
+f 1/1/1 30/4/4 40/5/5 16/6/6
+f 1/1/1 16/6/6 36/7/7 15/8/8
+f 1/1/1 15/8/8 39/9/9 27/2/2
+f 2/10/10 23/11/11 35/12/12 14/13/13
+f 2/10/10 14/13/13 38/14/14 25/15/15
+f 65/16/16 77/17/17 380/18/18 353/19/19
+f 65/16/16 353/19/19 378/20/20 75/21/21
+f 3/22/22 25/15/15 38/14/14 19/23/23
+f 3/22/22 19/23/23 33/24/24 18/25/25
+f 66/26/26 73/27/27 373/28/28 354/29/29
+f 66/26/26 354/29/29 380/18/18 77/17/17
+f 4/30/30 20/31/31 34/32/32 21/33/33
+f 4/30/30 21/33/33 39/9/9 26/34/34
+f 67/35/35 78/36/36 381/37/37 356/38/38
+f 67/35/35 356/38/38 375/39/39 74/40/40
+f 5/41/41 26/34/34 39/9/9 15/8/8
+f 5/41/41 15/8/8 36/7/7 24/42/42
+f 68/43/43 76/44/44 379/45/45 357/46/46
+f 68/43/43 357/46/46 381/37/37 78/36/36
+f 6/47/47 13/48/48 37/49/49 29/50/50
+f 6/47/47 29/50/50 41/3/3 27/2/2
+f 6/47/47 27/2/2 39/9/9 21/33/33
+f 6/47/47 21/33/33 34/32/32 13/48/48
+f 7/51/51 17/52/52 33/24/24 19/23/23
+f 7/51/51 19/23/23 38/14/14 28/53/53
+f 7/51/51 28/53/53 41/3/3 29/50/50
+f 7/51/51 29/50/50 37/49/49 17/52/52
+f 8/54/54 28/53/53 38/14/14 14/13/13
+f 8/54/54 14/13/13 35/12/12 22/55/55
+f 8/54/54 22/55/55 40/5/5 30/4/4
+f 8/54/54 30/4/4 41/3/3 28/53/53
+f 9/56/56 16/6/6 40/5/5 31/57/57
+f 69/58/58 79/59/59 383/60/60 362/61/61
+f 69/62/58 362/63/61 379/45/45 76/44/44
+f 9/64/56 24/42/42 36/7/7 16/6/6
+f 10/65/62 22/55/55 35/12/12 23/11/11
+f 70/66/63 75/21/21 378/20/20 363/67/64
+f 70/66/63 363/67/64 383/60/60 79/59/59
+f 10/65/62 31/57/57 40/5/5 22/55/55
+f 32/68/65 12/69/66 44/70/67 43/71/68
+f 11/72/69 18/25/25 33/24/24 17/52/52
+f 11/72/69 17/52/52 37/49/49 32/68/65
+f 71/73/70 366/74/71 373/28/28 73/27/27
+f 12/69/66 32/68/65 37/49/49 13/48/48
+f 12/69/66 13/48/48 34/32/32 20/31/31
+f 72/75/72 74/40/40 375/39/39 367/76/73
+f 71/73/70 11/72/69 42/77/74 80/78/75
+f 42/77/74 43/71/68 46/79/76 45/80/77
+f 81/81/78 384/82/79 389/83/80 83/84/81
+f 11/72/69 32/68/65 43/71/68 42/77/74
+f 72/75/72 367/76/73 384/82/79 81/81/78
+f 45/85/77 46/86/76 49/87/82 48/88/83
+f 83/89/81 389/90/80 394/91/84 85/92/85
+f 43/71/68 44/70/67 47/93/86 46/79/76
+f 80/78/75 42/77/74 45/80/77 82/94/87
+f 46/86/76 47/95/86 50/96/88 49/87/82
+f 82/97/87 45/85/77 48/88/83 84/98/89
+f 169/99/90 165/100/91 133/101/92 134/102/93
+f 93/103/94 61/104/95 51/105/96 86/106/97
+f 92/107/98 417/108/99 399/109/100 87/110/101
+f 168/111/102 167/112/103 135/113/104 136/114/105
+f 741/115/106 735/116/107 404/117/108 89/118/109
+f 739/119/110 736/120/111 55/121/112 54/122/113
+f 736/123/111 738/124/114 56/125/115 55/126/112
+f 740/127/116 739/119/110 54/122/113 88/128/117
+f 753/129/118 748/130/119 59/131/120 90/132/121
+f 750/133/122 747/134/123 57/135/124 58/136/125
+f 748/130/119 750/137/122 58/138/125 59/131/120
+f 752/139/126 749/140/127 409/141/128 91/142/129
+f 163/143/130 164/144/131 132/145/132 131/146/133
+f 85/92/85 394/91/84 417/108/99 92/107/98
+f 84/98/89 48/88/83 61/104/95 93/103/94
+f 165/100/91 166/147/134 138/148/135 133/101/92
+f 119/149/136 106/150/137 95/151/138 113/152/139
+f 55/153/112 56/154/115 111/155/140
+f 55/156/112 121/157/141 54/158/113
+f 395/159/142 84/98/89 93/103/94 416/160/143
+f 50/96/88 85/92/85 92/107/98 60/161/144
+f 747/134/123 752/139/126 91/142/129 57/135/124
+f 751/162/145 753/129/118 90/132/121 413/163/146
+f 737/164/147 740/127/116 88/128/117 405/165/148
+f 738/124/114 741/115/106 89/118/109 56/125/115
+f 60/161/144 92/107/98 87/110/101 53/166/149
+f 416/160/143 93/103/94 86/106/97 400/167/150
+f 390/168/151 82/97/87 84/98/89 395/159/142
+f 385/169/152 80/78/75 82/94/87 390/170/151
+f 47/95/86 83/89/81 85/92/85 50/96/88
+f 12/69/66 72/75/72 81/81/78 44/70/67
+f 44/70/67 81/81/78 83/84/81 47/93/86
+f 366/74/71 71/73/70 80/78/75 385/169/152
+f 12/69/66 20/31/31 74/40/40 72/75/72
+f 11/72/69 71/73/70 73/27/27 18/25/25
+f 10/65/62 70/66/63 79/59/59 31/57/57
+f 10/65/62 23/11/11 75/21/21 70/66/63
+f 9/64/56 69/62/58 76/44/44 24/42/42
+f 9/56/56 31/57/57 79/59/59 69/58/58
+f 5/41/41 68/43/43 78/36/36 26/34/34
+f 5/41/41 24/42/42 76/44/44 68/43/43
+f 4/30/30 67/35/35 74/40/40 20/31/31
+f 4/30/30 26/34/34 78/36/36 67/35/35
+f 3/22/22 66/26/26 77/17/17 25/15/15
+f 3/22/22 18/25/25 73/27/27 66/26/26
+f 2/10/10 65/16/16 75/21/21 23/11/11
+f 2/10/10 25/15/15 77/17/17 65/16/16
+f 62/171/153 56/154/115 89/172/109
+f 64/173/154 88/174/117 54/158/113
+f 404/175/108 451/176/155 62/171/153 89/172/109
+f 482/177/156 421/178/157 63/179/158 120/180/159
+f 405/181/148 88/174/117 64/173/154 452/182/160
+f 110/183/161 63/184/158 421/185/157 471/186/162
+f 797/187/163 791/188/164 98/189/165 124/190/166
+f 129/191/167 108/192/168 94/193/169 122/194/170
+f 128/195/171 107/196/172 97/197/173 123/198/174
+f 118/199/175 109/200/176 96/201/177 112/202/178
+f 125/203/179 101/204/180 105/205/181 127/206/182
+f 796/207/183 793/208/184 101/204/180 125/203/179
+f 114/209/185 795/210/186 100/211/187
+f 794/212/188 792/213/189 99/214/190 115/215/191
+f 103/216/192 126/217/193 216/218/194 327/219/195
+f 114/209/185 100/211/187 104/220/196 116/221/197
+f 115/215/191 99/214/190 103/216/192 117/222/198
+f 124/190/166 98/189/165 102/223/199 126/217/193
+f 110/183/161 64/173/154 109/200/176 118/199/175
+f 121/157/141 55/156/112 107/196/172 128/195/171
+f 120/180/159 63/179/158 108/192/168 129/191/167
+f 111/155/140 62/171/153 106/150/137 119/149/136
+f 55/153/112 111/155/140 119/149/136 107/224/172
+f 63/184/158 110/183/161 118/199/175 108/225/168
+f 101/226/180 115/215/191 117/222/198 105/227/181
+f 98/228/165 114/209/185 116/221/197 102/229/199
+f 126/217/193 102/223/199 220/230/200 216/218/194
+f 793/231/184 794/212/188 115/215/191 101/226/180
+f 791/232/164 795/210/186 114/209/185 98/228/165
+f 108/225/168 118/199/175 112/202/178 94/233/169
+f 64/173/154 110/183/161 471/186/162 452/182/160
+f 107/224/172 119/149/136 113/152/139 97/234/173
+f 116/221/197 104/220/196 221/235/201 218/236/202
+f 62/171/153 120/180/159 129/191/167 106/150/137
+f 64/173/154 121/157/141 128/195/171 109/200/176
+f 99/214/190 124/190/166 126/217/193 103/216/192
+f 105/227/181 117/222/198 217/237/203 219/238/204
+f 796/207/183 125/203/179 100/211/187
+f 100/211/187 125/203/179 127/206/182 104/220/196
+f 109/200/176 128/195/171 123/198/174 96/201/177
+f 106/150/137 129/191/167 122/194/170 95/151/138
+f 792/213/189 797/187/163 124/190/166 99/214/190
+f 451/176/155 482/177/156 120/180/159 62/171/153
+f 62/171/153 111/155/140 56/154/115
+f 64/173/154 54/158/113 121/157/141
+f 781/239/205 780/240/206 143/241/207 144/242/208
+f 779/243/209 775/244/210 145/245/211 141/246/212
+f 776/247/213 777/248/214 139/249/215 147/250/216
+f 777/248/214 778/251/217 140/252/218 139/249/215
+f 166/147/134 170/253/219 130/254/220 138/148/135
+f 164/144/131 168/111/102 136/114/105 132/145/132
+f 170/253/219 163/143/130 131/146/133 130/254/220
+f 167/112/103 169/255/90 134/256/93 135/113/104
+f 765/257/221 761/258/222 148/259/223 137/260/224
+f 764/261/225 763/262/226 150/263/227 151/264/228
+f 762/265/229 759/266/230 152/267/231 153/268/232
+f 763/262/226 760/269/233 155/270/234 150/263/227
+f 778/251/217 779/243/209 141/246/212 140/252/218
+f 782/271/235 776/247/213 147/250/216 142/272/236
+f 775/244/210 781/239/205 144/242/208 145/245/211
+f 780/273/206 782/271/235 142/272/236 143/274/207
+f 149/275/237 153/276/232 177/277/238 173/278/239
+f 155/279/234 137/280/224 171/281/240 179/282/241
+f 137/280/224 148/283/223 172/284/242 171/281/240
+f 151/285/228 150/286/227 174/287/243 175/288/244
+f 760/269/233 765/257/221 137/260/224 155/270/234
+f 766/289/245 762/265/229 153/268/232 149/290/237
+f 759/266/230 764/291/225 151/292/228 152/267/231
+f 761/258/222 766/289/245 149/290/237 148/259/223
+f 727/293/246 724/294/247 162/295/248 160/296/249
+f 725/297/250 722/298/251 159/299/252 156/300/253
+f 162/295/248 724/294/247 146/301/254
+f 726/302/255 723/303/256 161/304/257 158/305/258
+f 721/306/259 726/302/255 158/305/258 157/307/260
+f 725/297/250 156/300/253 146/301/254
+f 722/308/251 721/306/259 157/307/260 159/309/252
+f 723/303/256 727/293/246 160/296/249 161/304/257
+f 53/166/149 52/310/261 169/255/90 167/112/103
+f 48/88/83 49/87/82 163/143/130 170/253/219
+f 50/96/88 60/161/144 168/111/102 164/144/131
+f 61/104/95 48/88/83 170/253/219 166/147/134
+f 51/105/96 61/104/95 166/147/134 165/100/91
+f 49/87/82 50/96/88 164/144/131 163/143/130
+f 60/161/144 53/166/149 167/112/103 168/111/102
+f 52/311/261 51/105/96 165/100/91 169/99/90
+f 172/284/242 173/278/239 181/312/262 180/313/263
+f 176/314/264 175/288/244 183/315/265 184/316/266
+f 173/278/239 177/277/238 185/317/267 181/312/262
+f 179/282/241 171/281/240 154/318/268 187/319/269
+f 152/320/231 151/285/228 175/288/244 176/314/264
+f 148/283/223 149/275/237 173/278/239 172/284/242
+f 150/321/227 155/279/234 179/282/241 174/322/243
+f 153/276/232 152/323/231 176/324/264 177/277/238
+f 703/325/270 702/326/271 178/327/272 195/328/273
+f 702/326/271 699/329/274 188/330/275 178/327/272
+f 700/331/276 697/332/277 190/333/278 191/334/279
+f 701/335/280 698/336/281 192/337/282 193/338/283
+f 174/322/243 179/282/241 187/319/269 182/339/284
+f 184/340/266 185/317/267 205/341/285 206/342/286
+f 175/288/244 174/287/243 182/343/284 183/315/265
+f 171/281/240 172/284/242 180/313/263 154/318/268
+f 194/344/287 193/338/283 192/337/282 191/345/279
+f 195/328/273 194/344/287 191/345/279 190/346/278
+f 178/327/272 188/330/275 194/344/287 195/328/273
+f 188/330/275 189/347/288 193/338/283 194/344/287
+f 704/348/289 701/335/280 193/338/283 189/347/288
+f 698/349/281 700/331/276 191/334/279 192/350/282
+f 699/329/274 704/348/289 189/347/288 188/330/275
+f 697/351/277 703/325/270 195/328/273 190/346/278
+f 710/352/290 708/353/291 201/354/292 196/355/293
+f 712/356/294 709/357/295 202/358/296 199/359/297
+f 711/360/298 705/361/299 186/362/300 198/363/301
+f 709/357/295 706/364/302 197/365/303 202/358/296
+f 706/364/302 711/366/298 198/367/301 197/365/303
+f 705/361/299 710/368/290 196/369/293 186/362/300
+f 707/370/304 712/356/294 199/359/297 200/371/305
+f 708/353/291 707/370/304 200/371/305 201/354/292
+f 203/372/306 204/373/307 208/374/308 207/375/309
+f 176/314/264 184/316/266 206/376/286 204/377/307
+f 185/317/267 177/277/238 203/372/306 205/341/285
+f 177/277/238 176/324/264 204/373/307 203/372/306
+f 208/378/308 210/379/310 214/380/311 212/381/312
+f 204/377/307 206/376/286 210/379/310 208/378/308
+f 205/341/285 203/372/306 207/375/309 209/382/313
+f 206/342/286 205/341/285 209/382/313 210/383/310
+f 211/384/314 212/385/312 214/386/311 213/387/315
+f 209/382/313 207/375/309 211/384/314 213/387/315
+f 210/383/310 209/382/313 213/387/315 214/386/311
+f 207/375/309 208/374/308 212/385/312 211/384/314
+f 104/220/196 127/206/182 215/388/316 221/235/201
+f 127/206/182 105/205/181 219/389/204 215/388/316
+f 102/229/199 116/221/197 218/236/202 220/390/200
+f 117/222/198 103/216/192 327/219/195 217/237/203
+f 241/391/317 229/392/318 225/393/319 240/394/320
+f 242/395/321 224/396/322 229/392/318 241/391/317
+f 248/397/323 226/398/324 230/399/317 247/400/317
+f 247/400/317 230/399/317 228/401/325 246/402/326
+f 239/403/317 233/404/317 232/405/327 238/406/328
+f 237/407/329 231/408/330 233/404/317 239/403/317
+f 309/409/331 235/410/332 236/411/317 308/412/317
+f 308/412/317 236/411/317 234/413/333 307/414/334
+f 222/415/335 237/407/329 239/403/317 227/416/336
+f 227/416/336 239/403/317 238/406/328 223/417/337
+f 235/410/332 242/395/321 241/391/317 236/411/317
+f 236/411/317 241/391/317 240/394/320 234/413/333
+f 230/399/317 245/418/317 244/419/338 228/401/325
+f 226/398/324 243/420/339 245/418/317 230/399/317
+f 233/404/317 247/400/317 246/402/326 232/405/327
+f 231/408/330 248/397/323 247/400/317 233/404/317
+f 223/421/337 250/422/340 254/423/341 227/424/336
+f 225/425/319 252/426/342 263/427/343 240/428/320
+f 243/429/339 265/430/344 311/431/345 309/432/331
+f 228/433/325 255/434/346 267/435/347 246/436/326
+f 246/436/326 267/435/347 258/437/348 232/438/327
+f 234/439/333 259/440/349 310/441/350 307/442/334
+f 237/443/329 261/444/351 257/445/352 231/446/330
+f 240/428/320 263/427/343 259/440/349 234/439/333
+f 309/432/331 311/431/345 260/447/353 235/448/332
+f 235/448/332 260/447/353 264/449/354 242/450/321
+f 253/451/355 273/452/356 284/453/357 265/430/344
+f 268/454/358 287/455/359 273/452/356 253/451/355
+f 261/444/351 280/456/360 276/457/361 257/445/352
+f 262/458/362 281/459/363 270/460/364 250/422/340
+f 255/434/346 274/461/365 286/462/366 267/435/347
+f 263/427/343 282/463/367 278/464/368 259/440/349
+f 256/465/369 275/466/370 272/467/371 252/426/342
+f 249/468/372 269/469/373 280/456/360 261/444/351
+f 264/449/354 283/470/374 271/471/375 251/472/376
+f 257/445/352 276/457/361 287/455/359 268/454/358
+f 311/431/345 313/473/377 279/474/378 260/447/353
+f 258/437/348 277/475/379 281/459/363 262/458/362
+f 252/426/342 272/467/371 282/463/367 263/427/343
+f 266/476/380 285/477/381 274/461/365 255/434/346
+f 310/441/350 312/478/382 285/477/381 266/476/380
+f 251/472/376 271/471/375 275/479/370 256/480/369
+f 267/435/347 286/462/366 277/475/379 258/437/348
+f 260/447/353 279/474/378 283/470/374 264/449/354
+f 313/473/377 315/481/383 298/482/384 279/474/378
+f 277/475/379 296/483/385 300/484/386 281/459/363
+f 272/467/371 291/485/387 301/486/388 282/463/367
+f 285/477/381 304/487/389 293/488/390 274/461/365
+f 312/478/382 314/489/391 304/487/389 285/477/381
+f 271/471/375 290/490/392 294/491/393 275/479/370
+f 286/462/366 305/492/394 296/483/385 277/475/379
+f 279/474/378 298/482/384 302/493/395 283/470/374
+f 273/452/356 292/494/396 303/495/397 284/453/357
+f 287/455/359 306/496/398 292/494/396 273/452/356
+f 280/456/360 299/497/399 295/498/400 276/457/361
+f 281/459/363 300/484/386 289/499/401 270/460/364
+f 274/461/365 293/488/390 305/492/394 286/462/366
+f 282/463/367 301/486/388 297/500/402 278/464/368
+f 275/466/370 294/501/393 291/485/387 272/467/371
+f 269/469/373 288/502/403 299/497/399 280/456/360
+f 283/470/374 302/493/395 290/490/392 271/471/375
+f 276/457/361 295/498/400 306/496/398 287/455/359
+f 290/490/392 302/493/395 322/503/404 319/504/405
+f 301/486/388 291/485/387 317/505/406 316/506/407
+f 302/493/395 298/482/384 323/507/408 322/503/404
+f 291/485/387 294/501/393 318/508/409 317/505/406
+f 315/481/383 303/495/397 325/509/410 324/510/411
+f 297/500/402 301/486/388 316/506/407 321/511/412
+f 294/491/393 290/490/392 319/504/405 318/512/409
+f 314/489/391 297/500/402 321/511/412 320/513/413
+f 303/495/397 304/487/389 326/514/414 325/509/410
+f 269/469/373 270/460/364 289/499/401 288/502/403
+f 300/484/386 296/483/385 295/498/400 299/497/399
+f 306/496/398 295/498/400 296/483/385 305/492/394
+f 305/492/394 293/488/390 292/494/396 306/496/398
+f 303/495/397 292/494/396 293/488/390 304/487/389
+f 304/487/389 314/489/391 320/513/413 326/514/414
+f 298/482/384 315/481/383 324/510/411 323/507/408
+f 278/464/368 297/500/402 314/489/391 312/478/382
+f 284/453/357 303/495/397 315/481/383 313/473/377
+f 259/440/349 278/464/368 312/478/382 310/441/350
+f 265/430/344 284/453/357 313/473/377 311/431/345
+f 227/424/336 254/423/341 249/468/372 222/515/335
+f 245/418/317 308/412/317 307/414/334 244/419/338
+f 243/420/339 309/409/331 308/412/317 245/418/317
+f 221/516/201 215/517/316 316/506/407 317/505/406
+f 318/512/409 319/504/405 221/518/201
+f 221/516/201 317/505/406 318/508/409
+f 219/519/204 217/520/203 320/513/413 321/511/412
+f 220/521/200 218/522/202 322/503/404 323/507/408
+f 215/517/316 219/519/204 321/511/412 316/506/407
+f 218/522/202 221/518/201 319/504/405 322/503/404
+f 327/523/195 216/524/194 324/510/411 325/509/410
+f 325/509/410 326/514/414 327/523/195
+f 217/520/203 327/523/195 326/514/414 320/513/413
+f 216/524/194 220/521/200 323/507/408 324/510/411
+f 222/515/335 249/468/372 261/444/351 237/443/329
+f 242/450/321 264/449/354 251/472/376 224/525/322
+f 248/526/323 268/454/358 253/451/355 226/527/324
+f 224/525/322 251/472/376 256/480/369 229/528/318
+f 231/446/330 257/445/352 268/454/358 248/526/323
+f 307/442/334 310/441/350 266/476/380 244/529/338
+f 232/438/327 258/437/348 262/458/362 238/530/328
+f 244/529/338 266/476/380 255/434/346 228/433/325
+f 226/527/324 253/451/355 265/430/344 243/429/339
+f 229/531/318 256/465/369 252/426/342 225/425/319
+f 238/530/328 262/458/362 250/422/340 223/421/337
+f 299/497/399 288/502/403 289/499/401 300/484/386
+f 250/422/340 270/460/364 254/423/341
+f 254/423/341 269/469/373 249/468/372
+f 269/469/373 254/423/341 270/460/364
+f 328/532/415 361/533/416 382/534/417 358/535/418
+f 328/532/415 343/536/419 377/537/420 361/533/416
+f 328/532/415 342/538/421 371/539/422 343/536/419
+f 328/532/415 358/535/418 376/540/423 342/538/421
+f 329/541/424 341/542/425 370/543/426 350/544/427
+f 329/541/424 352/545/428 374/546/429 341/542/425
+f 422/547/430 353/548/19 380/549/18 434/550/431
+f 422/547/430 432/551/432 378/552/20 353/548/19
+f 330/553/433 346/554/434 374/546/429 352/545/428
+f 330/553/433 345/555/435 368/556/436 346/554/434
+f 423/557/437 354/558/29 373/559/28 430/560/438
+f 423/557/437 434/550/431 380/549/18 354/558/29
+f 331/561/439 348/562/440 369/563/441 347/564/442
+f 331/561/439 355/565/443 376/540/423 348/562/440
+f 424/566/444 356/38/38 381/37/37 435/567/445
+f 424/566/444 431/568/446 375/39/39 356/38/38
+f 332/569/447 342/538/421 376/540/423 355/565/443
+f 332/569/447 351/570/448 371/539/422 342/538/421
+f 425/571/449 357/46/46 379/45/45 433/572/450
+f 425/571/449 435/567/445 381/37/37 357/46/46
+f 333/573/451 360/574/452 372/575/453 340/576/454
+f 333/573/451 358/535/418 382/534/417 360/574/452
+f 333/573/451 348/562/440 376/540/423 358/535/418
+f 333/573/451 340/576/454 369/563/441 348/562/440
+f 334/577/455 346/554/434 368/556/436 344/578/456
+f 334/577/455 359/579/457 374/546/429 346/554/434
+f 334/577/455 360/574/452 382/534/417 359/579/457
+f 334/577/455 344/578/456 372/575/453 360/574/452
+f 335/580/458 341/542/425 374/546/429 359/579/457
+f 335/580/458 349/581/459 370/543/426 341/542/425
+f 335/580/458 361/533/416 377/537/420 349/581/459
+f 335/580/458 359/579/457 382/534/417 361/533/416
+f 336/582/460 364/583/461 377/537/420 343/536/419
+f 426/584/462 362/585/61 383/586/60 436/587/463
+f 426/588/462 433/572/450 379/45/45 362/63/61
+f 336/589/460 343/536/419 371/539/422 351/570/448
+f 337/590/464 350/544/427 370/543/426 349/581/459
+f 427/591/465 363/592/64 378/552/20 432/551/432
+f 427/591/465 436/587/463 383/586/60 363/592/64
+f 337/590/464 349/581/459 377/537/420 364/583/461
+f 365/593/466 387/594/467 388/595/468 339/596/469
+f 338/597/470 344/578/456 368/556/436 345/555/435
+f 338/597/470 365/593/466 372/575/453 344/578/456
+f 428/598/471 430/560/438 373/559/28 366/599/71
+f 339/596/469 340/576/454 372/575/453 365/593/466
+f 339/596/469 347/564/442 369/563/441 340/576/454
+f 429/600/472 367/76/73 375/39/39 431/568/446
+f 428/598/471 437/601/473 386/602/474 338/597/470
+f 386/602/474 391/603/475 392/604/476 387/594/467
+f 438/605/477 440/606/478 389/83/80 384/82/79
+f 338/597/470 386/602/474 387/594/467 365/593/466
+f 429/600/472 438/605/477 384/82/79 367/76/73
+f 391/607/475 396/608/479 397/609/480 392/610/476
+f 440/611/478 442/612/481 394/91/84 389/90/80
+f 387/594/467 392/604/476 393/613/482 388/595/468
+f 437/601/473 439/614/483 391/603/475 386/602/474
+f 392/610/476 397/609/480 398/615/484 393/616/482
+f 439/617/483 441/618/485 396/608/479 391/607/475
+f 530/619/486 495/620/487 494/621/488 526/622/489
+f 450/623/490 443/624/491 401/625/492 415/626/493
+f 449/627/494 444/628/495 399/109/100 417/108/99
+f 529/629/496 497/630/497 496/631/498 528/632/499
+f 746/633/500 446/634/501 404/117/108 735/116/107
+f 744/635/502 406/636/503 407/637/504 742/638/505
+f 742/639/505 407/640/504 408/641/506 743/642/507
+f 745/643/508 445/644/509 406/636/503 744/635/502
+f 758/645/510 447/646/511 412/647/512 755/648/513
+f 756/649/514 411/650/515 410/651/516 754/652/517
+f 755/648/513 412/647/512 411/653/515 756/654/514
+f 757/655/518 448/656/519 409/141/128 749/140/127
+f 524/657/520 492/658/521 493/659/522 525/660/523
+f 442/612/481 449/627/494 417/108/99 394/91/84
+f 441/618/485 450/623/490 415/626/493 396/608/479
+f 526/622/489 494/621/488 499/661/524 527/662/525
+f 479/663/526 473/664/527 454/665/528 465/666/529
+f 407/667/504 470/668/530 408/669/506
+f 407/670/504 406/671/503 481/672/531
+f 395/159/142 416/160/143 450/623/490 441/618/485
+f 398/615/484 414/673/532 449/627/494 442/612/481
+f 754/652/517 410/651/516 448/656/519 757/655/518
+f 751/162/145 413/163/146 447/646/511 758/645/510
+f 737/164/147 405/165/148 445/644/509 745/643/508
+f 743/642/507 408/641/506 446/634/501 746/633/500
+f 414/673/532 403/674/533 444/628/495 449/627/494
+f 416/160/143 400/167/150 443/624/491 450/623/490
+f 390/168/151 395/159/142 441/618/485 439/617/483
+f 385/675/152 390/676/151 439/614/483 437/601/473
+f 393/616/482 398/615/484 442/612/481 440/611/478
+f 339/596/469 388/595/468 438/605/477 429/600/472
+f 388/595/468 393/613/482 440/606/478 438/605/477
+f 366/599/71 385/675/152 437/601/473 428/598/471
+f 339/596/469 429/600/472 431/568/446 347/564/442
+f 338/597/470 345/555/435 430/560/438 428/598/471
+f 337/590/464 364/583/461 436/587/463 427/591/465
+f 337/590/464 427/591/465 432/551/432 350/544/427
+f 336/589/460 351/570/448 433/572/450 426/588/462
+f 336/582/460 426/584/462 436/587/463 364/583/461
+f 332/569/447 355/565/443 435/567/445 425/571/449
+f 332/569/447 425/571/449 433/572/450 351/570/448
+f 331/561/439 347/564/442 431/568/446 424/566/444
+f 331/561/439 424/566/444 435/567/445 355/565/443
+f 330/553/433 352/545/428 434/550/431 423/557/437
+f 330/553/433 423/557/437 430/560/438 345/555/435
+f 329/541/424 350/544/427 432/551/432 422/547/430
+f 329/541/424 422/547/430 434/550/431 352/545/428
+f 418/677/534 446/678/501 408/669/506
+f 420/679/535 406/671/503 445/680/509
+f 404/175/108 446/678/501 418/677/534 451/176/155
+f 482/177/156 480/681/536 419/682/537 421/178/157
+f 405/181/148 452/182/160 420/679/535 445/680/509
+f 469/683/538 471/186/162 421/185/157 419/684/537
+f 804/685/539 485/686/540 457/687/541 798/688/542
+f 490/689/543 483/690/544 453/691/545 467/692/546
+f 489/693/547 484/694/548 456/695/549 466/696/550
+f 478/697/551 472/698/552 455/699/553 468/700/554
+f 486/701/555 488/702/556 464/703/557 460/704/558
+f 803/705/559 486/701/555 460/704/558 800/706/560
+f 802/707/561 474/708/562 459/709/563
+f 801/710/564 475/711/565 458/712/566 799/713/567
+f 462/714/568 688/715/569 577/716/570 487/717/571
+f 474/708/562 476/718/572 463/719/573 459/709/563
+f 475/711/565 477/720/574 462/714/568 458/712/566
+f 485/686/540 487/717/571 461/721/575 457/687/541
+f 469/683/538 478/697/551 468/700/554 420/679/535
+f 481/672/531 489/693/547 466/696/550 407/670/504
+f 480/681/536 490/689/543 467/692/546 419/682/537
+f 470/668/530 479/663/526 465/666/529 418/677/534
+f 407/667/504 466/722/550 479/663/526 470/668/530
+f 419/684/537 467/723/546 478/697/551 469/683/538
+f 460/724/558 464/725/557 477/720/574 475/711/565
+f 457/726/541 461/727/575 476/718/572 474/708/562
+f 487/717/571 577/716/570 581/728/576 461/721/575
+f 800/729/560 460/724/558 475/711/565 801/710/564
+f 798/730/542 457/726/541 474/708/562 802/707/561
+f 467/723/546 453/731/545 472/698/552 478/697/551
+f 420/679/535 452/182/160 471/186/162 469/683/538
+f 466/722/550 456/732/549 473/664/527 479/663/526
+f 476/718/572 579/733/577 582/734/578 463/719/573
+f 418/677/534 465/666/529 490/689/543 480/681/536
+f 420/679/535 468/700/554 489/693/547 481/672/531
+f 458/712/566 462/714/568 487/717/571 485/686/540
+f 464/725/557 580/735/579 578/736/580 477/720/574
+f 459/709/563 486/701/555 803/705/559
+f 459/709/563 463/719/573 488/702/556 486/701/555
+f 468/700/554 455/699/553 484/694/548 489/693/547
+f 465/666/529 454/665/528 483/690/544 490/689/543
+f 799/713/567 458/712/566 485/686/540 804/685/539
+f 451/176/155 418/677/534 480/681/536 482/177/156
+f 418/677/534 408/669/506 470/668/530
+f 420/679/535 481/672/531 406/671/503
+f 789/737/581 505/738/582 504/739/583 788/740/584
+f 787/741/585 502/742/586 506/743/587 783/744/588
+f 784/745/589 508/746/590 500/747/591 785/748/592
+f 785/748/592 500/747/591 501/749/593 786/750/594
+f 527/662/525 499/661/524 491/751/595 531/752/596
+f 525/660/523 493/659/522 497/630/497 529/629/496
+f 531/752/596 491/751/595 492/658/521 524/657/520
+f 528/632/499 496/631/498 495/753/487 530/754/486
+f 773/755/597 498/756/598 509/757/599 769/758/600
+f 772/759/601 512/760/602 511/761/603 771/762/604
+f 770/763/605 514/764/606 513/765/607 767/766/608
+f 771/762/604 511/761/603 516/767/609 768/768/610
+f 786/750/594 501/749/593 502/742/586 787/741/585
+f 790/769/611 503/770/612 508/746/590 784/745/589
+f 783/744/588 506/743/587 505/738/582 789/737/581
+f 788/771/584 504/772/583 503/770/612 790/769/611
+f 510/773/613 534/774/614 538/775/615 514/776/606
+f 516/777/609 540/778/616 532/779/617 498/780/598
+f 498/780/598 532/779/617 533/781/618 509/782/599
+f 512/783/602 536/784/619 535/785/620 511/786/603
+f 768/768/610 516/767/609 498/756/598 773/755/597
+f 774/787/621 510/788/613 514/764/606 770/763/605
+f 767/766/608 513/765/607 512/789/602 772/790/601
+f 769/758/600 509/757/599 510/788/613 774/787/621
+f 734/791/622 521/792/623 523/793/624 731/794/625
+f 732/795/626 517/796/627 520/797/628 729/798/629
+f 731/794/625 523/793/624 507/799/630
+f 733/800/631 519/801/632 522/802/633 730/803/634
+f 728/804/635 518/805/636 519/801/632 733/800/631
+f 507/799/630 517/796/627 732/795/626
+f 729/806/629 520/807/628 518/805/636 728/804/635
+f 730/803/634 522/802/633 521/792/623 734/791/622
+f 403/674/533 528/632/499 530/754/486 402/808/637
+f 396/608/479 531/752/596 524/657/520 397/609/480
+f 398/615/484 525/660/523 529/629/496 414/673/532
+f 415/626/493 527/662/525 531/752/596 396/608/479
+f 401/625/492 526/622/489 527/662/525 415/626/493
+f 397/609/480 524/657/520 525/660/523 398/615/484
+f 414/673/532 529/629/496 528/632/499 403/674/533
+f 402/809/637 530/619/486 526/622/489 401/625/492
+f 533/781/618 541/810/638 542/811/639 534/774/614
+f 537/812/640 545/813/641 544/814/642 536/784/619
+f 534/774/614 542/811/639 546/815/643 538/775/615
+f 540/778/616 548/816/644 515/817/645 532/779/617
+f 513/818/607 537/812/640 536/784/619 512/783/602
+f 509/782/599 533/781/618 534/774/614 510/773/613
+f 511/819/603 535/820/620 540/778/616 516/777/609
+f 514/776/606 538/775/615 537/821/640 513/822/607
+f 695/823/646 556/824/647 539/825/648 694/826/649
+f 694/826/649 539/825/648 549/827/650 691/828/651
+f 692/829/652 552/830/653 551/831/654 689/832/655
+f 693/833/656 554/834/657 553/835/658 690/836/659
+f 535/820/620 543/837/660 548/816/644 540/778/616
+f 545/838/641 567/839/661 566/840/662 546/815/643
+f 536/784/619 544/814/642 543/841/660 535/785/620
+f 532/779/617 515/817/645 541/810/638 533/781/618
+f 555/842/663 552/843/653 553/835/658 554/834/657
+f 556/824/647 551/844/654 552/843/653 555/842/663
+f 539/825/648 556/824/647 555/842/663 549/827/650
+f 549/827/650 555/842/663 554/834/657 550/845/664
+f 696/846/665 550/845/664 554/834/657 693/833/656
+f 690/847/659 553/848/658 552/830/653 692/829/652
+f 691/828/651 549/827/650 550/845/664 696/846/665
+f 689/849/655 551/844/654 556/824/647 695/823/646
+f 718/850/666 557/851/667 562/852/668 716/853/669
+f 720/854/670 560/855/671 563/856/672 717/857/673
+f 719/858/674 559/859/675 547/860/676 713/861/677
+f 717/857/673 563/856/672 558/862/678 714/863/679
+f 714/863/679 558/862/678 559/864/675 719/865/674
+f 713/861/677 547/860/676 557/866/667 718/867/666
+f 715/868/680 561/869/681 560/855/671 720/854/670
+f 716/853/669 562/852/668 561/869/681 715/868/680
+f 564/870/682 568/871/683 569/872/684 565/873/685
+f 537/812/640 565/874/685 567/875/661 545/813/641
+f 546/815/643 566/840/662 564/870/682 538/775/615
+f 538/775/615 564/870/682 565/873/685 537/821/640
+f 569/876/684 573/877/686 575/878/687 571/879/688
+f 565/874/685 569/876/684 571/879/688 567/875/661
+f 566/840/662 570/880/689 568/871/683 564/870/682
+f 567/839/661 571/881/688 570/880/689 566/840/662
+f 572/882/690 574/883/691 575/884/687 573/885/686
+f 570/880/689 574/883/691 572/882/690 568/871/683
+f 571/881/688 575/884/687 574/883/691 570/880/689
+f 568/871/683 572/882/690 573/885/686 569/872/684
+f 463/719/573 582/734/578 576/886/692 488/702/556
+f 488/702/556 576/886/692 580/887/579 464/703/557
+f 461/727/575 581/888/576 579/733/577 476/718/572
+f 477/720/574 578/736/580 688/715/569 462/714/568
+f 602/889/317 601/890/693 586/891/694 590/892/695
+f 603/893/696 602/889/317 590/892/695 585/894/697
+f 609/895/698 608/896/317 591/897/317 587/898/699
+f 608/896/317 607/899/700 589/900/701 591/897/317
+f 600/901/317 599/902/702 593/903/703 594/904/317
+f 598/905/704 600/901/317 594/904/317 592/906/705
+f 670/907/706 669/908/317 597/909/317 596/910/707
+f 669/908/317 668/911/708 595/912/709 597/909/317
+f 583/913/710 588/914/711 600/901/317 598/905/704
+f 588/914/711 584/915/712 599/902/702 600/901/317
+f 596/910/707 597/909/317 602/889/317 603/893/696
+f 597/909/317 595/912/709 601/890/693 602/889/317
+f 591/897/317 589/900/701 605/916/713 606/917/317
+f 587/898/699 591/897/317 606/917/317 604/918/714
+f 594/904/317 593/903/703 607/899/700 608/896/317
+f 592/906/705 594/904/317 608/896/317 609/895/698
+f 584/919/712 588/920/711 615/921/715 611/922/716
+f 586/923/694 601/924/693 624/925/717 613/926/718
+f 604/927/714 670/928/706 672/929/719 626/930/720
+f 589/931/701 607/932/700 628/933/721 616/934/722
+f 607/932/700 593/935/703 619/936/723 628/933/721
+f 595/937/709 668/938/708 671/939/724 620/940/725
+f 598/941/704 592/942/705 618/943/726 622/944/727
+f 601/924/693 595/937/709 620/940/725 624/925/717
+f 670/928/706 596/945/707 621/946/728 672/929/719
+f 596/945/707 603/947/696 625/948/729 621/946/728
+f 614/949/730 626/930/720 645/950/731 634/951/732
+f 629/952/733 614/949/730 634/951/732 648/953/734
+f 622/944/727 618/943/726 637/954/735 641/955/736
+f 623/956/737 611/922/716 631/957/738 642/958/739
+f 616/934/722 628/933/721 647/959/740 635/960/741
+f 624/925/717 620/940/725 639/961/742 643/962/743
+f 617/963/744 613/926/718 633/964/745 636/965/746
+f 610/966/747 622/944/727 641/955/736 630/967/748
+f 625/948/729 612/968/749 632/969/750 644/970/751
+f 618/943/726 629/952/733 648/953/734 637/954/735
+f 672/929/719 621/946/728 640/971/752 674/972/753
+f 619/936/723 623/956/737 642/958/739 638/973/754
+f 613/926/718 624/925/717 643/962/743 633/964/745
+f 627/974/755 616/934/722 635/960/741 646/975/756
+f 671/939/724 627/974/755 646/975/756 673/976/757
+f 612/968/749 617/977/744 636/978/746 632/969/750
+f 628/933/721 619/936/723 638/973/754 647/959/740
+f 621/946/728 625/948/729 644/970/751 640/971/752
+f 674/972/753 640/971/752 659/979/758 676/980/759
+f 638/973/754 642/958/739 661/981/760 657/982/761
+f 633/964/745 643/962/743 662/983/762 652/984/763
+f 646/975/756 635/960/741 654/985/764 665/986/765
+f 673/976/757 646/975/756 665/986/765 675/987/766
+f 632/969/750 636/978/746 655/988/767 651/989/768
+f 647/959/740 638/973/754 657/982/761 666/990/769
+f 640/971/752 644/970/751 663/991/770 659/979/758
+f 634/951/732 645/950/731 664/992/771 653/993/772
+f 648/953/734 634/951/732 653/993/772 667/994/773
+f 641/955/736 637/954/735 656/995/774 660/996/775
+f 642/958/739 631/957/738 650/997/776 661/981/760
+f 635/960/741 647/959/740 666/990/769 654/985/764
+f 643/962/743 639/961/742 658/998/777 662/983/762
+f 636/965/746 633/964/745 652/984/763 655/999/767
+f 630/967/748 641/955/736 660/996/775 649/1000/778
+f 644/970/751 632/969/750 651/989/768 663/991/770
+f 637/954/735 648/953/734 667/994/773 656/995/774
+f 651/989/768 680/1001/779 683/1002/780 663/991/770
+f 662/983/762 677/1003/781 678/1004/782 652/984/763
+f 663/991/770 683/1002/780 684/1005/783 659/979/758
+f 652/984/763 678/1004/782 679/1006/784 655/999/767
+f 676/980/759 685/1007/785 686/1008/786 664/992/771
+f 658/998/777 682/1009/787 677/1003/781 662/983/762
+f 655/988/767 679/1010/784 680/1001/779 651/989/768
+f 675/987/766 681/1011/788 682/1009/787 658/998/777
+f 664/992/771 686/1008/786 687/1012/789 665/986/765
+f 630/967/748 649/1000/778 650/997/776 631/957/738
+f 661/981/760 660/996/775 656/995/774 657/982/761
+f 667/994/773 666/990/769 657/982/761 656/995/774
+f 666/990/769 667/994/773 653/993/772 654/985/764
+f 664/992/771 665/986/765 654/985/764 653/993/772
+f 665/986/765 687/1012/789 681/1011/788 675/987/766
+f 659/979/758 684/1005/783 685/1007/785 676/980/759
+f 639/961/742 673/976/757 675/987/766 658/998/777
+f 645/950/731 674/972/753 676/980/759 664/992/771
+f 620/940/725 671/939/724 673/976/757 639/961/742
+f 626/930/720 672/929/719 674/972/753 645/950/731
+f 588/920/711 583/1013/710 610/966/747 615/921/715
+f 606/917/317 605/916/713 668/911/708 669/908/317
+f 604/918/714 606/917/317 669/908/317 670/907/706
+f 582/1014/578 678/1004/782 677/1003/781 576/1015/692
+f 679/1010/784 582/1016/578 680/1001/779
+f 582/1014/578 679/1006/784 678/1004/782
+f 580/1017/579 682/1009/787 681/1011/788 578/1018/580
+f 581/1019/576 684/1005/783 683/1002/780 579/1020/577
+f 576/1015/692 677/1003/781 682/1009/787 580/1017/579
+f 579/1020/577 683/1002/780 680/1001/779 582/1016/578
+f 688/1021/569 686/1008/786 685/1007/785 577/1022/570
+f 686/1008/786 688/1021/569 687/1012/789
+f 578/1018/580 681/1011/788 687/1012/789 688/1021/569
+f 577/1022/570 685/1007/785 684/1005/783 581/1019/576
+f 583/1013/710 598/941/704 622/944/727 610/966/747
+f 603/947/696 585/1023/697 612/968/749 625/948/729
+f 609/1024/698 587/1025/699 614/949/730 629/952/733
+f 585/1023/697 590/1026/695 617/977/744 612/968/749
+f 592/942/705 609/1024/698 629/952/733 618/943/726
+f 668/938/708 605/1027/713 627/974/755 671/939/724
+f 593/935/703 599/1028/702 623/956/737 619/936/723
+f 605/1027/713 589/931/701 616/934/722 627/974/755
+f 587/1025/699 604/927/714 626/930/720 614/949/730
+f 590/1029/695 586/923/694 613/926/718 617/963/744
+f 599/1028/702 584/919/712 611/922/716 623/956/737
+f 660/996/775 661/981/760 650/997/776 649/1000/778
+f 611/922/716 615/921/715 631/957/738
+f 615/921/715 610/966/747 630/967/748
+f 630/967/748 631/957/738 615/921/715
+f 557/851/667 689/849/655 695/823/646 562/852/668
+f 560/855/671 691/828/651 696/846/665 563/856/672
+f 559/859/675 690/847/659 692/829/652 547/860/676
+f 563/856/672 696/846/665 693/833/656 558/862/678
+f 558/862/678 693/833/656 690/836/659 559/864/675
+f 547/860/676 692/829/652 689/832/655 557/866/667
+f 561/869/681 694/826/649 691/828/651 560/855/671
+f 562/852/668 695/823/646 694/826/649 561/869/681
+f 196/355/293 201/354/292 703/325/270 697/351/277
+f 199/359/297 202/358/296 704/348/289 699/329/274
+f 198/363/301 186/362/300 700/331/276 698/349/281
+f 202/358/296 197/365/303 701/335/280 704/348/289
+f 197/365/303 198/367/301 698/336/281 701/335/280
+f 186/362/300 196/369/293 697/332/277 700/331/276
+f 200/371/305 199/359/297 699/329/274 702/326/271
+f 201/354/292 200/371/305 702/326/271 703/325/270
+f 187/319/269 154/318/268 707/370/304 708/353/291
+f 154/318/268 180/313/263 712/356/294 707/370/304
+f 183/315/265 182/343/284 710/368/290 705/361/299
+f 185/317/267 184/340/266 711/366/298 706/364/302
+f 181/312/262 185/317/267 706/364/302 709/357/295
+f 184/316/266 183/315/265 705/361/299 711/360/298
+f 180/313/263 181/312/262 709/357/295 712/356/294
+f 182/339/284 187/319/269 708/353/291 710/352/290
+f 548/816/644 716/853/669 715/868/680 515/817/645
+f 515/817/645 715/868/680 720/854/670 541/810/638
+f 544/814/642 713/861/677 718/867/666 543/841/660
+f 546/815/643 714/863/679 719/865/674 545/838/641
+f 542/811/639 717/857/673 714/863/679 546/815/643
+f 545/813/641 719/858/674 713/861/677 544/814/642
+f 541/810/638 720/854/670 717/857/673 542/811/639
+f 543/837/660 718/850/666 716/853/669 548/816/644
+f 139/249/215 140/252/218 727/293/246 723/303/256
+f 143/274/207 142/272/236 721/306/259 722/308/251
+f 145/245/211 144/242/208 725/297/250
+f 142/272/236 147/250/216 726/302/255 721/306/259
+f 147/250/216 139/249/215 723/303/256 726/302/255
+f 141/246/212 145/245/211 724/294/247
+f 144/242/208 143/241/207 722/298/251 725/297/250
+f 140/252/218 141/246/212 724/294/247 727/293/246
+f 500/747/591 730/803/634 734/791/622 501/749/593
+f 504/772/583 729/806/629 728/804/635 503/770/612
+f 505/738/582 506/743/587 732/795/626
+f 503/770/612 728/804/635 733/800/631 508/746/590
+f 508/746/590 733/800/631 730/803/634 500/747/591
+f 502/742/586 731/794/625 506/743/587
+f 505/738/582 732/795/626 729/798/629 504/739/583
+f 501/749/593 734/791/622 731/794/625 502/742/586
+f 410/651/516 743/642/507 746/633/500 448/656/519
+f 413/163/146 737/164/147 745/643/508 447/646/511
+f 447/646/511 745/643/508 744/635/502 412/647/512
+f 411/650/515 742/639/505 743/642/507 410/651/516
+f 412/647/512 744/635/502 742/638/505 411/653/515
+f 448/656/519 746/633/500 735/116/107 409/141/128
+f 57/135/124 91/142/129 741/115/106 738/124/114
+f 413/163/146 90/132/121 740/127/116 737/164/147
+f 90/132/121 59/131/120 739/119/110 740/127/116
+f 58/136/125 57/135/124 738/124/114 736/123/111
+f 59/131/120 58/138/125 736/120/111 739/119/110
+f 91/142/129 409/141/128 735/116/107 741/115/106
+f 400/167/150 751/162/145 758/645/510 443/624/491
+f 403/674/533 754/652/517 757/655/518 444/628/495
+f 444/628/495 757/655/518 749/140/127 399/109/100
+f 401/625/492 755/648/513 756/654/514 402/809/637
+f 402/808/637 756/649/514 754/652/517 403/674/533
+f 443/624/491 758/645/510 755/648/513 401/625/492
+f 400/167/150 86/106/97 753/129/118 751/162/145
+f 53/166/149 87/110/101 752/139/126 747/134/123
+f 87/110/101 399/109/100 749/140/127 752/139/126
+f 51/105/96 52/311/261 750/137/122 748/130/119
+f 52/310/261 53/166/149 747/134/123 750/133/122
+f 86/106/97 51/105/96 748/130/119 753/129/118
+f 160/296/249 162/295/248 766/289/245 761/258/222
+f 156/300/253 159/299/252 764/291/225 759/266/230
+f 162/295/248 146/301/254 762/265/229 766/289/245
+f 158/305/258 161/304/257 765/257/221 760/269/233
+f 157/307/260 158/305/258 760/269/233 763/262/226
+f 146/301/254 156/300/253 759/266/230 762/265/229
+f 159/309/252 157/307/260 763/262/226 764/261/225
+f 161/304/257 160/296/249 761/258/222 765/257/221
+f 521/792/623 769/758/600 774/787/621 523/793/624
+f 517/796/627 767/766/608 772/790/601 520/797/628
+f 523/793/624 774/787/621 770/763/605 507/799/630
+f 519/801/632 768/768/610 773/755/597 522/802/633
+f 518/805/636 771/762/604 768/768/610 519/801/632
+f 507/799/630 770/763/605 767/766/608 517/796/627
+f 520/807/628 772/759/601 771/762/604 518/805/636
+f 522/802/633 773/755/597 769/758/600 521/792/623
+f 134/102/93 133/101/92 782/271/235 780/273/206
+f 136/114/105 135/113/104 781/239/205 775/244/210
+f 133/101/92 138/148/135 776/247/213 782/271/235
+f 131/146/133 132/145/132 779/243/209 778/251/217
+f 130/254/220 131/146/133 778/251/217 777/248/214
+f 138/148/135 130/254/220 777/248/214 776/247/213
+f 132/145/132 136/114/105 775/244/210 779/243/209
+f 135/113/104 134/256/93 780/240/206 781/239/205
+f 495/620/487 788/771/584 790/769/611 494/621/488
+f 497/630/497 783/744/588 789/737/581 496/631/498
+f 494/621/488 790/769/611 784/745/589 499/661/524
+f 492/658/521 786/750/594 787/741/585 493/659/522
+f 491/751/595 785/748/592 786/750/594 492/658/521
+f 499/661/524 784/745/589 785/748/592 491/751/595
+f 493/659/522 787/741/585 783/744/588 497/630/497
+f 496/631/498 789/737/581 788/740/584 495/753/487
+f 506/743/587 507/799/630 732/795/626
+f 145/245/211 146/301/254 724/294/247
+f 506/743/587 731/794/625 507/799/630
+f 145/245/211 725/297/250 146/301/254
+f 95/151/138 122/194/170 797/187/163 792/213/189
+f 96/201/177 123/198/174 796/207/183
+f 94/233/169 112/202/178 795/210/186 791/232/164
+f 97/234/173 113/152/139 794/212/188 793/231/184
+f 113/152/139 95/151/138 792/213/189 794/212/188
+f 112/202/178 96/201/177 795/210/186
+f 123/198/174 97/197/173 793/208/184 796/207/183
+f 122/194/170 94/193/169 791/188/164 797/187/163
+f 454/665/528 799/713/567 804/685/539 483/690/544
+f 484/694/548 455/699/553 803/705/559
+f 453/731/545 798/730/542 802/707/561 472/698/552
+f 456/732/549 800/729/560 801/710/564 473/664/527
+f 473/664/527 801/710/564 799/713/567 454/665/528
+f 472/698/552 802/707/561 455/699/553
+f 484/694/548 803/705/559 800/706/560 456/695/549
+f 483/690/544 804/685/539 798/688/542 453/691/545
+f 455/699/553 459/709/563 803/705/559
+f 96/201/177 100/211/187 795/210/186
+f 455/699/553 802/707/561 459/709/563
+f 96/201/177 796/207/183 100/211/187
diff --git a/examples/models/resources/models/obj/character_diffuse.png b/examples/models/resources/models/obj/character_diffuse.png
new file mode 100644
index 000000000..0fae9d894
Binary files /dev/null and b/examples/models/resources/models/obj/character_diffuse.png differ
diff --git a/examples/models/resources/raylib_logo.png b/examples/models/resources/raylib_logo.png
new file mode 100644
index 000000000..15bbaa2f4
Binary files /dev/null and b/examples/models/resources/raylib_logo.png differ
diff --git a/examples/others/web_basic_window.png b/examples/others/web_basic_window.png
new file mode 100644
index 000000000..346184417
Binary files /dev/null and b/examples/others/web_basic_window.png differ
diff --git a/examples/shaders/raygui.h b/examples/shaders/raygui.h
new file mode 100644
index 000000000..a3fc51f0f
--- /dev/null
+++ b/examples/shaders/raygui.h
@@ -0,0 +1,5757 @@
+/*******************************************************************************************
+*
+* raygui v4.5-dev - A simple and easy-to-use immediate-mode gui library
+*
+* DESCRIPTION:
+* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also
+* available as a standalone library, as long as input and drawing functions are provided.
+*
+* FEATURES:
+* - Immediate-mode gui, minimal retained data
+* - +25 controls provided (basic and advanced)
+* - Styling system for colors, font and metrics
+* - Icons supported, embedded as a 1-bit icons pack
+* - Standalone mode option (custom input/graphics backend)
+* - Multiple support tools provided for raygui development
+*
+* POSSIBLE IMPROVEMENTS:
+* - Better standalone mode API for easy plug of custom backends
+* - Externalize required inputs, allow user easier customization
+*
+* LIMITATIONS:
+* - No editable multi-line word-wraped text box supported
+* - No auto-layout mechanism, up to the user to define controls position and size
+* - Standalone mode requires library modification and some user work to plug another backend
+*
+* NOTES:
+* - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for
+* font atlas recs and glyphs, freeing that memory is (usually) up to the user,
+* no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads
+* by default any previously loaded font (texture, recs, glyphs).
+* - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions
+*
+* CONTROLS PROVIDED:
+* # Container/separators Controls
+* - WindowBox --> StatusBar, Panel
+* - GroupBox --> Line
+* - Line
+* - Panel --> StatusBar
+* - ScrollPanel --> StatusBar
+* - TabBar --> Button
+*
+* # Basic Controls
+* - Label
+* - LabelButton --> Label
+* - Button
+* - Toggle
+* - ToggleGroup --> Toggle
+* - ToggleSlider
+* - CheckBox
+* - ComboBox
+* - DropdownBox
+* - TextBox
+* - ValueBox --> TextBox
+* - Spinner --> Button, ValueBox
+* - Slider
+* - SliderBar --> Slider
+* - ProgressBar
+* - StatusBar
+* - DummyRec
+* - Grid
+*
+* # Advance Controls
+* - ListView
+* - ColorPicker --> ColorPanel, ColorBarHue
+* - MessageBox --> Window, Label, Button
+* - TextInputBox --> Window, Label, TextBox, Button
+*
+* It also provides a set of functions for styling the controls based on its properties (size, color).
+*
+*
+* RAYGUI STYLE (guiStyle):
+* raygui uses a global data array for all gui style properties (allocated on data segment by default),
+* when a new style is loaded, it is loaded over the global style... but a default gui style could always be
+* recovered with GuiLoadStyleDefault() function, that overwrites the current style to the default one
+*
+* The global style array size is fixed and depends on the number of controls and properties:
+*
+* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)];
+*
+* guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB
+*
+* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style
+* used for all controls, when any of those base values is set, it is automatically populated to all
+* controls, so, specific control values overwriting generic style should be set after base values.
+*
+* After the first BASE set we have the EXTENDED properties (by default guiStyle[16..23]), those
+* properties are actually common to all controls and can not be overwritten individually (like BASE ones)
+* Some of those properties are: TEXT_SIZE, TEXT_SPACING, LINE_COLOR, BACKGROUND_COLOR
+*
+* Custom control properties can be defined using the EXTENDED properties for each independent control.
+*
+* TOOL: rGuiStyler is a visual tool to customize raygui style: github.com/raysan5/rguistyler
+*
+*
+* RAYGUI ICONS (guiIcons):
+* raygui could use a global array containing icons data (allocated on data segment by default),
+* a custom icons set could be loaded over this array using GuiLoadIcons(), but loaded icons set
+* must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS will be loaded
+*
+* Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon
+* requires 8 integers (16*16/32) to be stored in memory.
+*
+* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set.
+*
+* The global icons array size is fixed and depends on the number of icons and size:
+*
+* static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS];
+*
+* guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB
+*
+* TOOL: rGuiIcons is a visual tool to customize/create raygui icons: github.com/raysan5/rguiicons
+*
+* RAYGUI LAYOUT:
+* raygui currently does not provide an auto-layout mechanism like other libraries,
+* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it.
+*
+* TOOL: rGuiLayout is a visual tool to create raygui layouts: github.com/raysan5/rguilayout
+*
+* CONFIGURATION:
+* #define RAYGUI_IMPLEMENTATION
+* Generates the implementation of the library into the included file.
+* If not defined, the library is in header only mode and can be included in other headers
+* or source files without problems. But only ONE file should hold the implementation.
+*
+* #define RAYGUI_STANDALONE
+* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined
+* internally in the library and input management and drawing functions must be provided by
+* the user (check library implementation for further details).
+*
+* #define RAYGUI_NO_ICONS
+* Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB)
+*
+* #define RAYGUI_CUSTOM_ICONS
+* Includes custom ricons.h header defining a set of custom icons,
+* this file can be generated using rGuiIcons tool
+*
+* #define RAYGUI_DEBUG_RECS_BOUNDS
+* Draw control bounds rectangles for debug
+*
+* #define RAYGUI_DEBUG_TEXT_BOUNDS
+* Draw text bounds rectangles for debug
+*
+* VERSIONS HISTORY:
+* 4.5-dev (Sep-2024) Current dev version...
+* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes
+* ADDED: GuiValueBoxFloat()
+* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP
+* ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH
+* ADDED: Multiple new icons
+* REVIEWED: GuiTabBar(), close tab with mouse middle button
+* REVIEWED: GuiScrollPanel(), scroll speed proportional to content
+* REVIEWED: GuiDropdownBox(), support roll up and hidden arrow
+* REVIEWED: GuiTextBox(), cursor position initialization
+* REVIEWED: GuiSliderPro(), control value change check
+* REVIEWED: GuiGrid(), simplified implementation
+* REVIEWED: GuiIconText(), increase buffer size and reviewed padding
+* REVIEWED: GuiDrawText(), improved wrap mode drawing
+* REVIEWED: GuiScrollBar(), minor tweaks
+* REVIEWED: Functions descriptions, removed wrong return value reference
+* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion
+*
+* 4.0 (12-Sep-2023) ADDED: GuiToggleSlider()
+* ADDED: GuiColorPickerHSV() and GuiColorPanelHSV()
+* ADDED: Multiple new icons, mostly compiler related
+* ADDED: New DEFAULT properties: TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE
+* ADDED: New enum values: GuiTextAlignment, GuiTextAlignmentVertical, GuiTextWrapMode
+* ADDED: Support loading styles with custom font charset from external file
+* REDESIGNED: GuiTextBox(), support mouse cursor positioning
+* REDESIGNED: GuiDrawText(), support multiline and word-wrap modes (read only)
+* REDESIGNED: GuiProgressBar() to be more visual, progress affects border color
+* REDESIGNED: Global alpha consideration moved to GuiDrawRectangle() and GuiDrawText()
+* REDESIGNED: GuiScrollPanel(), get parameters by reference and return result value
+* REDESIGNED: GuiToggleGroup(), get parameters by reference and return result value
+* REDESIGNED: GuiComboBox(), get parameters by reference and return result value
+* REDESIGNED: GuiCheckBox(), get parameters by reference and return result value
+* REDESIGNED: GuiSlider(), get parameters by reference and return result value
+* REDESIGNED: GuiSliderBar(), get parameters by reference and return result value
+* REDESIGNED: GuiProgressBar(), get parameters by reference and return result value
+* REDESIGNED: GuiListView(), get parameters by reference and return result value
+* REDESIGNED: GuiColorPicker(), get parameters by reference and return result value
+* REDESIGNED: GuiColorPanel(), get parameters by reference and return result value
+* REDESIGNED: GuiColorBarAlpha(), get parameters by reference and return result value
+* REDESIGNED: GuiColorBarHue(), get parameters by reference and return result value
+* REDESIGNED: GuiGrid(), get parameters by reference and return result value
+* REDESIGNED: GuiGrid(), added extra parameter
+* REDESIGNED: GuiListViewEx(), change parameters order
+* REDESIGNED: All controls return result as int value
+* REVIEWED: GuiScrollPanel() to avoid smallish scroll-bars
+* REVIEWED: All examples and specially controls_test_suite
+* RENAMED: gui_file_dialog module to gui_window_file_dialog
+* UPDATED: All styles to include ISO-8859-15 charset (as much as possible)
+*
+* 3.6 (10-May-2023) ADDED: New icon: SAND_TIMER
+* ADDED: GuiLoadStyleFromMemory() (binary only)
+* REVIEWED: GuiScrollBar() horizontal movement key
+* REVIEWED: GuiTextBox() crash on cursor movement
+* REVIEWED: GuiTextBox(), additional inputs support
+* REVIEWED: GuiLabelButton(), avoid text cut
+* REVIEWED: GuiTextInputBox(), password input
+* REVIEWED: Local GetCodepointNext(), aligned with raylib
+* REDESIGNED: GuiSlider*()/GuiScrollBar() to support out-of-bounds
+*
+* 3.5 (20-Apr-2023) ADDED: GuiTabBar(), based on GuiToggle()
+* ADDED: Helper functions to split text in separate lines
+* ADDED: Multiple new icons, useful for code editing tools
+* REMOVED: Unneeded icon editing functions
+* REMOVED: GuiTextBoxMulti(), very limited and broken
+* REMOVED: MeasureTextEx() dependency, logic directly implemented
+* REMOVED: DrawTextEx() dependency, logic directly implemented
+* REVIEWED: GuiScrollBar(), improve mouse-click behaviour
+* REVIEWED: Library header info, more info, better organized
+* REDESIGNED: GuiTextBox() to support cursor movement
+* REDESIGNED: GuiDrawText() to divide drawing by lines
+*
+* 3.2 (22-May-2022) RENAMED: Some enum values, for unification, avoiding prefixes
+* REMOVED: GuiScrollBar(), only internal
+* REDESIGNED: GuiPanel() to support text parameter
+* REDESIGNED: GuiScrollPanel() to support text parameter
+* REDESIGNED: GuiColorPicker() to support text parameter
+* REDESIGNED: GuiColorPanel() to support text parameter
+* REDESIGNED: GuiColorBarAlpha() to support text parameter
+* REDESIGNED: GuiColorBarHue() to support text parameter
+* REDESIGNED: GuiTextInputBox() to support password
+*
+* 3.1 (12-Jan-2022) REVIEWED: Default style for consistency (aligned with rGuiLayout v2.5 tool)
+* REVIEWED: GuiLoadStyle() to support compressed font atlas image data and unload previous textures
+* REVIEWED: External icons usage logic
+* REVIEWED: GuiLine() for centered alignment when including text
+* RENAMED: Multiple controls properties definitions to prepend RAYGUI_
+* RENAMED: RICON_ references to RAYGUI_ICON_ for library consistency
+* Projects updated and multiple tweaks
+*
+* 3.0 (04-Nov-2021) Integrated ricons data to avoid external file
+* REDESIGNED: GuiTextBoxMulti()
+* REMOVED: GuiImageButton*()
+* Multiple minor tweaks and bugs corrected
+*
+* 2.9 (17-Mar-2021) REMOVED: Tooltip API
+* 2.8 (03-May-2020) Centralized rectangles drawing to GuiDrawRectangle()
+* 2.7 (20-Feb-2020) ADDED: Possible tooltips API
+* 2.6 (09-Sep-2019) ADDED: GuiTextInputBox()
+* REDESIGNED: GuiListView*(), GuiDropdownBox(), GuiSlider*(), GuiProgressBar(), GuiMessageBox()
+* REVIEWED: GuiTextBox(), GuiSpinner(), GuiValueBox(), GuiLoadStyle()
+* Replaced property INNER_PADDING by TEXT_PADDING, renamed some properties
+* ADDED: 8 new custom styles ready to use
+* Multiple minor tweaks and bugs corrected
+*
+* 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner()
+* 2.3 (29-Apr-2019) ADDED: rIcons auxiliar library and support for it, multiple controls reviewed
+* Refactor all controls drawing mechanism to use control state
+* 2.2 (05-Feb-2019) ADDED: GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed Gui*Ex() controls
+* 2.1 (26-Dec-2018) REDESIGNED: GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string
+* REDESIGNED: Style system (breaking change)
+* 2.0 (08-Nov-2018) ADDED: Support controls guiLock and custom fonts
+* REVIEWED: GuiComboBox(), GuiListView()...
+* 1.9 (09-Oct-2018) REVIEWED: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()...
+* 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout
+* 1.5 (21-Jun-2017) Working in an improved styles system
+* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones)
+* 1.3 (12-Jun-2017) Complete redesign of style system
+* 1.1 (01-Jun-2017) Complete review of the library
+* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria.
+* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria.
+* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria.
+*
+* DEPENDENCIES:
+* raylib 5.0 - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing
+*
+* STANDALONE MODE:
+* By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled
+* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs.
+*
+* The following functions should be redefined for a custom backend:
+*
+* - Vector2 GetMousePosition(void);
+* - float GetMouseWheelMove(void);
+* - bool IsMouseButtonDown(int button);
+* - bool IsMouseButtonPressed(int button);
+* - bool IsMouseButtonReleased(int button);
+* - bool IsKeyDown(int key);
+* - bool IsKeyPressed(int key);
+* - int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox()
+*
+* - void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle()
+* - void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker()
+*
+* - Font GetFontDefault(void); // -- GuiLoadStyleDefault()
+* - Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle()
+* - Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image
+* - void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization)
+* - char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data
+* - void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data
+* - const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs
+* - int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list
+* - void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list
+* - unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle()
+*
+* CONTRIBUTORS:
+* Ramon Santamaria: Supervision, review, redesign, update and maintenance
+* Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019)
+* Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018)
+* Adria Arranz: Testing and implementation of additional controls (2018)
+* Jordi Jorba: Testing and implementation of additional controls (2018)
+* Albert Martos: Review and testing of the library (2015)
+* Ian Eito: Review and testing of the library (2015)
+* Kevin Gato: Initial implementation of basic components (2014)
+* Daniel Nicolas: Initial implementation of basic components (2014)
+*
+*
+* LICENSE: zlib/libpng
+*
+* Copyright (c) 2014-2024 Ramon Santamaria (@raysan5)
+*
+* This software is provided "as-is", without any express or implied warranty. In no event
+* will the authors be held liable for any damages arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose, including commercial
+* applications, and to alter it and redistribute it freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not claim that you
+* wrote the original software. If you use this software in a product, an acknowledgment
+* in the product documentation would be appreciated but is not required.
+*
+* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
+* as being the original software.
+*
+* 3. This notice may not be removed or altered from any source distribution.
+*
+**********************************************************************************************/
+
+#ifndef RAYGUI_H
+#define RAYGUI_H
+
+#define RAYGUI_VERSION_MAJOR 4
+#define RAYGUI_VERSION_MINOR 5
+#define RAYGUI_VERSION_PATCH 0
+#define RAYGUI_VERSION "4.5-dev"
+
+#if !defined(RAYGUI_STANDALONE)
+ #include "raylib.h"
+#endif
+
+// Function specifiers in case library is build/used as a shared library (Windows)
+// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
+#if defined(_WIN32)
+ #if defined(BUILD_LIBTYPE_SHARED)
+ #define RAYGUIAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
+ #elif defined(USE_LIBTYPE_SHARED)
+ #define RAYGUIAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
+ #endif
+#endif
+
+// Function specifiers definition
+#ifndef RAYGUIAPI
+ #define RAYGUIAPI // Functions defined as 'extern' by default (implicit specifiers)
+#endif
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+// Allow custom memory allocators
+#ifndef RAYGUI_MALLOC
+ #define RAYGUI_MALLOC(sz) malloc(sz)
+#endif
+#ifndef RAYGUI_CALLOC
+ #define RAYGUI_CALLOC(n,sz) calloc(n,sz)
+#endif
+#ifndef RAYGUI_FREE
+ #define RAYGUI_FREE(p) free(p)
+#endif
+
+// Simple log system to avoid printf() calls if required
+// NOTE: Avoiding those calls, also avoids const strings memory usage
+#define RAYGUI_SUPPORT_LOG_INFO
+#if defined(RAYGUI_SUPPORT_LOG_INFO)
+ #define RAYGUI_LOG(...) printf(__VA_ARGS__)
+#else
+ #define RAYGUI_LOG(...)
+#endif
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+// NOTE: Some types are required for RAYGUI_STANDALONE usage
+//----------------------------------------------------------------------------------
+#if defined(RAYGUI_STANDALONE)
+ #ifndef __cplusplus
+ // Boolean type
+ #ifndef true
+ typedef enum { false, true } bool;
+ #endif
+ #endif
+
+ // Vector2 type
+ typedef struct Vector2 {
+ float x;
+ float y;
+ } Vector2;
+
+ // Vector3 type // -- ConvertHSVtoRGB(), ConvertRGBtoHSV()
+ typedef struct Vector3 {
+ float x;
+ float y;
+ float z;
+ } Vector3;
+
+ // Color type, RGBA (32bit)
+ typedef struct Color {
+ unsigned char r;
+ unsigned char g;
+ unsigned char b;
+ unsigned char a;
+ } Color;
+
+ // Rectangle type
+ typedef struct Rectangle {
+ float x;
+ float y;
+ float width;
+ float height;
+ } Rectangle;
+
+ // TODO: Texture2D type is very coupled to raylib, required by Font type
+ // It should be redesigned to be provided by user
+ typedef struct Texture2D {
+ unsigned int id; // OpenGL texture id
+ int width; // Texture base width
+ int height; // Texture base height
+ int mipmaps; // Mipmap levels, 1 by default
+ int format; // Data format (PixelFormat type)
+ } Texture2D;
+
+ // Image, pixel data stored in CPU memory (RAM)
+ typedef struct Image {
+ void *data; // Image raw data
+ int width; // Image base width
+ int height; // Image base height
+ int mipmaps; // Mipmap levels, 1 by default
+ int format; // Data format (PixelFormat type)
+ } Image;
+
+ // GlyphInfo, font characters glyphs info
+ typedef struct GlyphInfo {
+ int value; // Character value (Unicode)
+ int offsetX; // Character offset X when drawing
+ int offsetY; // Character offset Y when drawing
+ int advanceX; // Character advance position X
+ Image image; // Character image data
+ } GlyphInfo;
+
+ // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle()
+ // It should be redesigned to be provided by user
+ typedef struct Font {
+ int baseSize; // Base size (default chars height)
+ int glyphCount; // Number of glyph characters
+ int glyphPadding; // Padding around the glyph characters
+ Texture2D texture; // Texture atlas containing the glyphs
+ Rectangle *recs; // Rectangles in texture for the glyphs
+ GlyphInfo *glyphs; // Glyphs info data
+ } Font;
+#endif
+
+// Style property
+// NOTE: Used when exporting style as code for convenience
+typedef struct GuiStyleProp {
+ unsigned short controlId; // Control identifier
+ unsigned short propertyId; // Property identifier
+ int propertyValue; // Property value
+} GuiStyleProp;
+
+/*
+// Controls text style -NOT USED-
+// NOTE: Text style is defined by control
+typedef struct GuiTextStyle {
+ unsigned int size;
+ int charSpacing;
+ int lineSpacing;
+ int alignmentH;
+ int alignmentV;
+ int padding;
+} GuiTextStyle;
+*/
+
+// Gui control state
+typedef enum {
+ STATE_NORMAL = 0,
+ STATE_FOCUSED,
+ STATE_PRESSED,
+ STATE_DISABLED
+} GuiState;
+
+// Gui control text alignment
+typedef enum {
+ TEXT_ALIGN_LEFT = 0,
+ TEXT_ALIGN_CENTER,
+ TEXT_ALIGN_RIGHT
+} GuiTextAlignment;
+
+// Gui control text alignment vertical
+// NOTE: Text vertical position inside the text bounds
+typedef enum {
+ TEXT_ALIGN_TOP = 0,
+ TEXT_ALIGN_MIDDLE,
+ TEXT_ALIGN_BOTTOM
+} GuiTextAlignmentVertical;
+
+// Gui control text wrap mode
+// NOTE: Useful for multiline text
+typedef enum {
+ TEXT_WRAP_NONE = 0,
+ TEXT_WRAP_CHAR,
+ TEXT_WRAP_WORD
+} GuiTextWrapMode;
+
+// Gui controls
+typedef enum {
+ // Default -> populates to all controls when set
+ DEFAULT = 0,
+
+ // Basic controls
+ LABEL, // Used also for: LABELBUTTON
+ BUTTON,
+ TOGGLE, // Used also for: TOGGLEGROUP
+ SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER
+ PROGRESSBAR,
+ CHECKBOX,
+ COMBOBOX,
+ DROPDOWNBOX,
+ TEXTBOX, // Used also for: TEXTBOXMULTI
+ VALUEBOX,
+ SPINNER, // Uses: BUTTON, VALUEBOX
+ LISTVIEW,
+ COLORPICKER,
+ SCROLLBAR,
+ STATUSBAR
+} GuiControl;
+
+// Gui base properties for every control
+// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties)
+typedef enum {
+ BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL
+ BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL
+ TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL
+ BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED
+ BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED
+ TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED
+ BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED
+ BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED
+ TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED
+ BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED
+ BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED
+ TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED
+ BORDER_WIDTH, // Control border size, 0 for no border
+ //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls
+ //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls
+ //TEXT_LINE_SPACING // Control text spacing between lines -> GLOBAL for all controls
+ TEXT_PADDING, // Control text padding, not considering border
+ TEXT_ALIGNMENT, // Control text horizontal alignment inside control text bound (after border and padding)
+ //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls
+} GuiControlProperty;
+
+// TODO: Which text styling properties should be global or per-control?
+// At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while
+// TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and
+// should be configured by user as needed while defining the UI layout
+
+// Gui extended properties depend on control
+// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties)
+//----------------------------------------------------------------------------------
+// DEFAULT extended properties
+// NOTE: Those properties are common to all controls or global
+// WARNING: We only have 8 slots for those properties by default!!! -> New global control: TEXT?
+typedef enum {
+ TEXT_SIZE = 16, // Text size (glyphs max height)
+ TEXT_SPACING, // Text spacing between glyphs
+ LINE_COLOR, // Line control color
+ BACKGROUND_COLOR, // Background color
+ TEXT_LINE_SPACING, // Text spacing between lines
+ TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding)
+ TEXT_WRAP_MODE // Text wrap-mode inside text bounds
+ //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline
+ //TEXT_DECORATION_THICK // Text decoration line thickness
+} GuiDefaultProperty;
+
+// Other possible text properties:
+// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change
+// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING...
+
+// Label
+//typedef enum { } GuiLabelProperty;
+
+// Button/Spinner
+//typedef enum { } GuiButtonProperty;
+
+// Toggle/ToggleGroup
+typedef enum {
+ GROUP_PADDING = 16, // ToggleGroup separation between toggles
+} GuiToggleProperty;
+
+// Slider/SliderBar
+typedef enum {
+ SLIDER_WIDTH = 16, // Slider size of internal bar
+ SLIDER_PADDING // Slider/SliderBar internal bar padding
+} GuiSliderProperty;
+
+// ProgressBar
+typedef enum {
+ PROGRESS_PADDING = 16, // ProgressBar internal padding
+} GuiProgressBarProperty;
+
+// ScrollBar
+typedef enum {
+ ARROWS_SIZE = 16, // ScrollBar arrows size
+ ARROWS_VISIBLE, // ScrollBar arrows visible
+ SCROLL_SLIDER_PADDING, // ScrollBar slider internal padding
+ SCROLL_SLIDER_SIZE, // ScrollBar slider size
+ SCROLL_PADDING, // ScrollBar scroll padding from arrows
+ SCROLL_SPEED, // ScrollBar scrolling speed
+} GuiScrollBarProperty;
+
+// CheckBox
+typedef enum {
+ CHECK_PADDING = 16 // CheckBox internal check padding
+} GuiCheckBoxProperty;
+
+// ComboBox
+typedef enum {
+ COMBO_BUTTON_WIDTH = 16, // ComboBox right button width
+ COMBO_BUTTON_SPACING // ComboBox button separation
+} GuiComboBoxProperty;
+
+// DropdownBox
+typedef enum {
+ ARROW_PADDING = 16, // DropdownBox arrow separation from border and items
+ DROPDOWN_ITEMS_SPACING, // DropdownBox items separation
+ DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden
+ DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down)
+} GuiDropdownBoxProperty;
+
+// TextBox/TextBoxMulti/ValueBox/Spinner
+typedef enum {
+ TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable
+} GuiTextBoxProperty;
+
+// Spinner
+typedef enum {
+ SPIN_BUTTON_WIDTH = 16, // Spinner left/right buttons width
+ SPIN_BUTTON_SPACING, // Spinner buttons separation
+} GuiSpinnerProperty;
+
+// ListView
+typedef enum {
+ LIST_ITEMS_HEIGHT = 16, // ListView items height
+ LIST_ITEMS_SPACING, // ListView items separation
+ SCROLLBAR_WIDTH, // ListView scrollbar size (usually width)
+ SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE)
+ LIST_ITEMS_BORDER_WIDTH // ListView items border width
+} GuiListViewProperty;
+
+// ColorPicker
+typedef enum {
+ COLOR_SELECTOR_SIZE = 16,
+ HUEBAR_WIDTH, // ColorPicker right hue bar width
+ HUEBAR_PADDING, // ColorPicker right hue bar separation from panel
+ HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height
+ HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow
+} GuiColorPickerProperty;
+
+#define SCROLLBAR_LEFT_SIDE 0
+#define SCROLLBAR_RIGHT_SIDE 1
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+// ...
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+
+#if defined(__cplusplus)
+extern "C" { // Prevents name mangling of functions
+#endif
+
+// Global gui state control functions
+RAYGUIAPI void GuiEnable(void); // Enable gui controls (global state)
+RAYGUIAPI void GuiDisable(void); // Disable gui controls (global state)
+RAYGUIAPI void GuiLock(void); // Lock gui controls (global state)
+RAYGUIAPI void GuiUnlock(void); // Unlock gui controls (global state)
+RAYGUIAPI bool GuiIsLocked(void); // Check if gui is locked (global state)
+RAYGUIAPI void GuiSetAlpha(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f
+RAYGUIAPI void GuiSetState(int state); // Set gui state (global state)
+RAYGUIAPI int GuiGetState(void); // Get gui state (global state)
+
+// Font set/get functions
+RAYGUIAPI void GuiSetFont(Font font); // Set gui custom font (global state)
+RAYGUIAPI Font GuiGetFont(void); // Get gui custom font (global state)
+
+// Style set/get functions
+RAYGUIAPI void GuiSetStyle(int control, int property, int value); // Set one style property
+RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style property
+
+// Styles loading functions
+RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs)
+RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style
+
+// Tooltips management functions
+RAYGUIAPI void GuiEnableTooltip(void); // Enable gui tooltips (global state)
+RAYGUIAPI void GuiDisableTooltip(void); // Disable gui tooltips (global state)
+RAYGUIAPI void GuiSetTooltip(const char *tooltip); // Set tooltip string
+
+// Icons functionality
+RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended (if supported)
+#if !defined(RAYGUI_NO_ICONS)
+RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size
+RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer
+RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data
+RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position
+#endif
+
+// Controls
+//----------------------------------------------------------------------------------------------------------
+// Container/separator controls, useful for controls organization
+RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); // Window Box control, shows a window that can be closed
+RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name
+RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text
+RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls
+RAYGUIAPI int GuiTabBar(Rectangle bounds, const char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1
+RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control
+
+// Basic controls set
+RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control
+RAYGUIAPI int GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked
+RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, returns true when clicked
+RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control
+RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control
+RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control
+RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked); // Check Box control, returns true when active
+RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control
+
+RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control
+RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control
+RAYGUIAPI int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers
+RAYGUIAPI int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode); // Value box control for float values
+RAYGUIAPI int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text
+
+RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control
+RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control
+RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control
+RAYGUIAPI int GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text
+RAYGUIAPI int GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders
+RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control
+
+// Advance controls set
+RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control
+RAYGUIAPI int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters
+RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message
+RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret
+RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls)
+RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control
+RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control
+RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control
+RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls)
+RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV()
+//----------------------------------------------------------------------------------------------------------
+
+#if !defined(RAYGUI_NO_ICONS)
+
+#if !defined(RAYGUI_CUSTOM_ICONS)
+//----------------------------------------------------------------------------------
+// Icons enumeration
+//----------------------------------------------------------------------------------
+typedef enum {
+ ICON_NONE = 0,
+ ICON_FOLDER_FILE_OPEN = 1,
+ ICON_FILE_SAVE_CLASSIC = 2,
+ ICON_FOLDER_OPEN = 3,
+ ICON_FOLDER_SAVE = 4,
+ ICON_FILE_OPEN = 5,
+ ICON_FILE_SAVE = 6,
+ ICON_FILE_EXPORT = 7,
+ ICON_FILE_ADD = 8,
+ ICON_FILE_DELETE = 9,
+ ICON_FILETYPE_TEXT = 10,
+ ICON_FILETYPE_AUDIO = 11,
+ ICON_FILETYPE_IMAGE = 12,
+ ICON_FILETYPE_PLAY = 13,
+ ICON_FILETYPE_VIDEO = 14,
+ ICON_FILETYPE_INFO = 15,
+ ICON_FILE_COPY = 16,
+ ICON_FILE_CUT = 17,
+ ICON_FILE_PASTE = 18,
+ ICON_CURSOR_HAND = 19,
+ ICON_CURSOR_POINTER = 20,
+ ICON_CURSOR_CLASSIC = 21,
+ ICON_PENCIL = 22,
+ ICON_PENCIL_BIG = 23,
+ ICON_BRUSH_CLASSIC = 24,
+ ICON_BRUSH_PAINTER = 25,
+ ICON_WATER_DROP = 26,
+ ICON_COLOR_PICKER = 27,
+ ICON_RUBBER = 28,
+ ICON_COLOR_BUCKET = 29,
+ ICON_TEXT_T = 30,
+ ICON_TEXT_A = 31,
+ ICON_SCALE = 32,
+ ICON_RESIZE = 33,
+ ICON_FILTER_POINT = 34,
+ ICON_FILTER_BILINEAR = 35,
+ ICON_CROP = 36,
+ ICON_CROP_ALPHA = 37,
+ ICON_SQUARE_TOGGLE = 38,
+ ICON_SYMMETRY = 39,
+ ICON_SYMMETRY_HORIZONTAL = 40,
+ ICON_SYMMETRY_VERTICAL = 41,
+ ICON_LENS = 42,
+ ICON_LENS_BIG = 43,
+ ICON_EYE_ON = 44,
+ ICON_EYE_OFF = 45,
+ ICON_FILTER_TOP = 46,
+ ICON_FILTER = 47,
+ ICON_TARGET_POINT = 48,
+ ICON_TARGET_SMALL = 49,
+ ICON_TARGET_BIG = 50,
+ ICON_TARGET_MOVE = 51,
+ ICON_CURSOR_MOVE = 52,
+ ICON_CURSOR_SCALE = 53,
+ ICON_CURSOR_SCALE_RIGHT = 54,
+ ICON_CURSOR_SCALE_LEFT = 55,
+ ICON_UNDO = 56,
+ ICON_REDO = 57,
+ ICON_REREDO = 58,
+ ICON_MUTATE = 59,
+ ICON_ROTATE = 60,
+ ICON_REPEAT = 61,
+ ICON_SHUFFLE = 62,
+ ICON_EMPTYBOX = 63,
+ ICON_TARGET = 64,
+ ICON_TARGET_SMALL_FILL = 65,
+ ICON_TARGET_BIG_FILL = 66,
+ ICON_TARGET_MOVE_FILL = 67,
+ ICON_CURSOR_MOVE_FILL = 68,
+ ICON_CURSOR_SCALE_FILL = 69,
+ ICON_CURSOR_SCALE_RIGHT_FILL = 70,
+ ICON_CURSOR_SCALE_LEFT_FILL = 71,
+ ICON_UNDO_FILL = 72,
+ ICON_REDO_FILL = 73,
+ ICON_REREDO_FILL = 74,
+ ICON_MUTATE_FILL = 75,
+ ICON_ROTATE_FILL = 76,
+ ICON_REPEAT_FILL = 77,
+ ICON_SHUFFLE_FILL = 78,
+ ICON_EMPTYBOX_SMALL = 79,
+ ICON_BOX = 80,
+ ICON_BOX_TOP = 81,
+ ICON_BOX_TOP_RIGHT = 82,
+ ICON_BOX_RIGHT = 83,
+ ICON_BOX_BOTTOM_RIGHT = 84,
+ ICON_BOX_BOTTOM = 85,
+ ICON_BOX_BOTTOM_LEFT = 86,
+ ICON_BOX_LEFT = 87,
+ ICON_BOX_TOP_LEFT = 88,
+ ICON_BOX_CENTER = 89,
+ ICON_BOX_CIRCLE_MASK = 90,
+ ICON_POT = 91,
+ ICON_ALPHA_MULTIPLY = 92,
+ ICON_ALPHA_CLEAR = 93,
+ ICON_DITHERING = 94,
+ ICON_MIPMAPS = 95,
+ ICON_BOX_GRID = 96,
+ ICON_GRID = 97,
+ ICON_BOX_CORNERS_SMALL = 98,
+ ICON_BOX_CORNERS_BIG = 99,
+ ICON_FOUR_BOXES = 100,
+ ICON_GRID_FILL = 101,
+ ICON_BOX_MULTISIZE = 102,
+ ICON_ZOOM_SMALL = 103,
+ ICON_ZOOM_MEDIUM = 104,
+ ICON_ZOOM_BIG = 105,
+ ICON_ZOOM_ALL = 106,
+ ICON_ZOOM_CENTER = 107,
+ ICON_BOX_DOTS_SMALL = 108,
+ ICON_BOX_DOTS_BIG = 109,
+ ICON_BOX_CONCENTRIC = 110,
+ ICON_BOX_GRID_BIG = 111,
+ ICON_OK_TICK = 112,
+ ICON_CROSS = 113,
+ ICON_ARROW_LEFT = 114,
+ ICON_ARROW_RIGHT = 115,
+ ICON_ARROW_DOWN = 116,
+ ICON_ARROW_UP = 117,
+ ICON_ARROW_LEFT_FILL = 118,
+ ICON_ARROW_RIGHT_FILL = 119,
+ ICON_ARROW_DOWN_FILL = 120,
+ ICON_ARROW_UP_FILL = 121,
+ ICON_AUDIO = 122,
+ ICON_FX = 123,
+ ICON_WAVE = 124,
+ ICON_WAVE_SINUS = 125,
+ ICON_WAVE_SQUARE = 126,
+ ICON_WAVE_TRIANGULAR = 127,
+ ICON_CROSS_SMALL = 128,
+ ICON_PLAYER_PREVIOUS = 129,
+ ICON_PLAYER_PLAY_BACK = 130,
+ ICON_PLAYER_PLAY = 131,
+ ICON_PLAYER_PAUSE = 132,
+ ICON_PLAYER_STOP = 133,
+ ICON_PLAYER_NEXT = 134,
+ ICON_PLAYER_RECORD = 135,
+ ICON_MAGNET = 136,
+ ICON_LOCK_CLOSE = 137,
+ ICON_LOCK_OPEN = 138,
+ ICON_CLOCK = 139,
+ ICON_TOOLS = 140,
+ ICON_GEAR = 141,
+ ICON_GEAR_BIG = 142,
+ ICON_BIN = 143,
+ ICON_HAND_POINTER = 144,
+ ICON_LASER = 145,
+ ICON_COIN = 146,
+ ICON_EXPLOSION = 147,
+ ICON_1UP = 148,
+ ICON_PLAYER = 149,
+ ICON_PLAYER_JUMP = 150,
+ ICON_KEY = 151,
+ ICON_DEMON = 152,
+ ICON_TEXT_POPUP = 153,
+ ICON_GEAR_EX = 154,
+ ICON_CRACK = 155,
+ ICON_CRACK_POINTS = 156,
+ ICON_STAR = 157,
+ ICON_DOOR = 158,
+ ICON_EXIT = 159,
+ ICON_MODE_2D = 160,
+ ICON_MODE_3D = 161,
+ ICON_CUBE = 162,
+ ICON_CUBE_FACE_TOP = 163,
+ ICON_CUBE_FACE_LEFT = 164,
+ ICON_CUBE_FACE_FRONT = 165,
+ ICON_CUBE_FACE_BOTTOM = 166,
+ ICON_CUBE_FACE_RIGHT = 167,
+ ICON_CUBE_FACE_BACK = 168,
+ ICON_CAMERA = 169,
+ ICON_SPECIAL = 170,
+ ICON_LINK_NET = 171,
+ ICON_LINK_BOXES = 172,
+ ICON_LINK_MULTI = 173,
+ ICON_LINK = 174,
+ ICON_LINK_BROKE = 175,
+ ICON_TEXT_NOTES = 176,
+ ICON_NOTEBOOK = 177,
+ ICON_SUITCASE = 178,
+ ICON_SUITCASE_ZIP = 179,
+ ICON_MAILBOX = 180,
+ ICON_MONITOR = 181,
+ ICON_PRINTER = 182,
+ ICON_PHOTO_CAMERA = 183,
+ ICON_PHOTO_CAMERA_FLASH = 184,
+ ICON_HOUSE = 185,
+ ICON_HEART = 186,
+ ICON_CORNER = 187,
+ ICON_VERTICAL_BARS = 188,
+ ICON_VERTICAL_BARS_FILL = 189,
+ ICON_LIFE_BARS = 190,
+ ICON_INFO = 191,
+ ICON_CROSSLINE = 192,
+ ICON_HELP = 193,
+ ICON_FILETYPE_ALPHA = 194,
+ ICON_FILETYPE_HOME = 195,
+ ICON_LAYERS_VISIBLE = 196,
+ ICON_LAYERS = 197,
+ ICON_WINDOW = 198,
+ ICON_HIDPI = 199,
+ ICON_FILETYPE_BINARY = 200,
+ ICON_HEX = 201,
+ ICON_SHIELD = 202,
+ ICON_FILE_NEW = 203,
+ ICON_FOLDER_ADD = 204,
+ ICON_ALARM = 205,
+ ICON_CPU = 206,
+ ICON_ROM = 207,
+ ICON_STEP_OVER = 208,
+ ICON_STEP_INTO = 209,
+ ICON_STEP_OUT = 210,
+ ICON_RESTART = 211,
+ ICON_BREAKPOINT_ON = 212,
+ ICON_BREAKPOINT_OFF = 213,
+ ICON_BURGER_MENU = 214,
+ ICON_CASE_SENSITIVE = 215,
+ ICON_REG_EXP = 216,
+ ICON_FOLDER = 217,
+ ICON_FILE = 218,
+ ICON_SAND_TIMER = 219,
+ ICON_WARNING = 220,
+ ICON_HELP_BOX = 221,
+ ICON_INFO_BOX = 222,
+ ICON_PRIORITY = 223,
+ ICON_LAYERS_ISO = 224,
+ ICON_LAYERS2 = 225,
+ ICON_MLAYERS = 226,
+ ICON_MAPS = 227,
+ ICON_HOT = 228,
+ ICON_229 = 229,
+ ICON_230 = 230,
+ ICON_231 = 231,
+ ICON_232 = 232,
+ ICON_233 = 233,
+ ICON_234 = 234,
+ ICON_235 = 235,
+ ICON_236 = 236,
+ ICON_237 = 237,
+ ICON_238 = 238,
+ ICON_239 = 239,
+ ICON_240 = 240,
+ ICON_241 = 241,
+ ICON_242 = 242,
+ ICON_243 = 243,
+ ICON_244 = 244,
+ ICON_245 = 245,
+ ICON_246 = 246,
+ ICON_247 = 247,
+ ICON_248 = 248,
+ ICON_249 = 249,
+ ICON_250 = 250,
+ ICON_251 = 251,
+ ICON_252 = 252,
+ ICON_253 = 253,
+ ICON_254 = 254,
+ ICON_255 = 255,
+} GuiIconName;
+#endif
+
+#endif
+
+#if defined(__cplusplus)
+} // Prevents name mangling of functions
+#endif
+
+#endif // RAYGUI_H
+
+/***********************************************************************************
+*
+* RAYGUI IMPLEMENTATION
+*
+************************************************************************************/
+
+#if defined(RAYGUI_IMPLEMENTATION)
+
+#include // required for: isspace() [GuiTextBox()]
+#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()]
+#include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()]
+#include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy()
+#include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()]
+#include // Required for: roundf() [GuiColorPicker()]
+
+#ifdef __cplusplus
+ #define RAYGUI_CLITERAL(name) name
+#else
+ #define RAYGUI_CLITERAL(name) (name)
+#endif
+
+// Check if two rectangles are equal, used to validate a slider bounds as an id
+#ifndef CHECK_BOUNDS_ID
+ #define CHECK_BOUNDS_ID(src, dst) ((src.x == dst.x) && (src.y == dst.y) && (src.width == dst.width) && (src.height == dst.height))
+#endif
+
+#if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS)
+
+// Embedded icons, no external file provided
+#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared)
+#define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons
+#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id
+
+// Icons data is defined by bit array (every bit represents one pixel)
+// Those arrays are stored as unsigned int data arrays, so,
+// every array element defines 32 pixels (bits) of information
+// One icon is defined by 8 int, (8 int * 32 bit = 256 bit = 16*16 pixels)
+// NOTE: Number of elemens depend on RAYGUI_ICON_SIZE (by default 16x16 pixels)
+#define RAYGUI_ICON_DATA_ELEMENTS (RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32)
+
+//----------------------------------------------------------------------------------
+// Icons data for all gui possible icons (allocated on data segment by default)
+//
+// NOTE 1: Every icon is codified in binary form, using 1 bit per pixel, so,
+// every 16x16 icon requires 8 integers (16*16/32) to be stored
+//
+// NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(),
+// but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS
+//
+// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB
+//----------------------------------------------------------------------------------
+static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE
+ 0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // ICON_FOLDER_FILE_OPEN
+ 0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // ICON_FILE_SAVE_CLASSIC
+ 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // ICON_FOLDER_OPEN
+ 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // ICON_FOLDER_SAVE
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // ICON_FILE_OPEN
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // ICON_FILE_SAVE
+ 0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // ICON_FILE_EXPORT
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // ICON_FILE_ADD
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // ICON_FILE_DELETE
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_FILETYPE_TEXT
+ 0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // ICON_FILETYPE_AUDIO
+ 0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // ICON_FILETYPE_IMAGE
+ 0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PLAY
+ 0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // ICON_FILETYPE_VIDEO
+ 0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // ICON_FILETYPE_INFO
+ 0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // ICON_FILE_COPY
+ 0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // ICON_FILE_CUT
+ 0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // ICON_FILE_PASTE
+ 0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_CURSOR_HAND
+ 0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // ICON_CURSOR_POINTER
+ 0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // ICON_CURSOR_CLASSIC
+ 0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // ICON_PENCIL
+ 0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // ICON_PENCIL_BIG
+ 0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // ICON_BRUSH_CLASSIC
+ 0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // ICON_BRUSH_PAINTER
+ 0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // ICON_WATER_DROP
+ 0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // ICON_COLOR_PICKER
+ 0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // ICON_RUBBER
+ 0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // ICON_COLOR_BUCKET
+ 0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // ICON_TEXT_T
+ 0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // ICON_TEXT_A
+ 0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // ICON_SCALE
+ 0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // ICON_RESIZE
+ 0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_POINT
+ 0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_BILINEAR
+ 0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // ICON_CROP
+ 0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // ICON_CROP_ALPHA
+ 0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // ICON_SQUARE_TOGGLE
+ 0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // ICON_SYMMETRY
+ 0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // ICON_SYMMETRY_HORIZONTAL
+ 0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // ICON_SYMMETRY_VERTICAL
+ 0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // ICON_LENS
+ 0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // ICON_LENS_BIG
+ 0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // ICON_EYE_ON
+ 0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // ICON_EYE_OFF
+ 0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // ICON_FILTER_TOP
+ 0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // ICON_FILTER
+ 0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_POINT
+ 0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL
+ 0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG
+ 0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // ICON_TARGET_MOVE
+ 0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // ICON_CURSOR_MOVE
+ 0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // ICON_CURSOR_SCALE
+ 0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // ICON_CURSOR_SCALE_RIGHT
+ 0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // ICON_CURSOR_SCALE_LEFT
+ 0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO
+ 0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO
+ 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // ICON_REREDO
+ 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // ICON_MUTATE
+ 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // ICON_ROTATE
+ 0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // ICON_REPEAT
+ 0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // ICON_SHUFFLE
+ 0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // ICON_EMPTYBOX
+ 0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // ICON_TARGET
+ 0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL_FILL
+ 0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG_FILL
+ 0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // ICON_TARGET_MOVE_FILL
+ 0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // ICON_CURSOR_MOVE_FILL
+ 0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // ICON_CURSOR_SCALE_FILL
+ 0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // ICON_CURSOR_SCALE_RIGHT_FILL
+ 0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // ICON_CURSOR_SCALE_LEFT_FILL
+ 0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO_FILL
+ 0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO_FILL
+ 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // ICON_REREDO_FILL
+ 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // ICON_MUTATE_FILL
+ 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // ICON_ROTATE_FILL
+ 0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // ICON_REPEAT_FILL
+ 0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // ICON_SHUFFLE_FILL
+ 0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // ICON_EMPTYBOX_SMALL
+ 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX
+ 0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP
+ 0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_RIGHT
+ 0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_RIGHT
+ 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // ICON_BOX_BOTTOM_RIGHT
+ 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // ICON_BOX_BOTTOM
+ 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // ICON_BOX_BOTTOM_LEFT
+ 0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_LEFT
+ 0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_LEFT
+ 0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_CENTER
+ 0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // ICON_BOX_CIRCLE_MASK
+ 0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // ICON_POT
+ 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // ICON_ALPHA_MULTIPLY
+ 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // ICON_ALPHA_CLEAR
+ 0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // ICON_DITHERING
+ 0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // ICON_MIPMAPS
+ 0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // ICON_BOX_GRID
+ 0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // ICON_GRID
+ 0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // ICON_BOX_CORNERS_SMALL
+ 0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // ICON_BOX_CORNERS_BIG
+ 0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // ICON_FOUR_BOXES
+ 0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // ICON_GRID_FILL
+ 0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // ICON_BOX_MULTISIZE
+ 0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_SMALL
+ 0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_MEDIUM
+ 0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // ICON_ZOOM_BIG
+ 0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // ICON_ZOOM_ALL
+ 0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // ICON_ZOOM_CENTER
+ 0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // ICON_BOX_DOTS_SMALL
+ 0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // ICON_BOX_DOTS_BIG
+ 0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // ICON_BOX_CONCENTRIC
+ 0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // ICON_BOX_GRID_BIG
+ 0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // ICON_OK_TICK
+ 0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // ICON_CROSS
+ 0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // ICON_ARROW_LEFT
+ 0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // ICON_ARROW_RIGHT
+ 0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // ICON_ARROW_DOWN
+ 0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP
+ 0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // ICON_ARROW_LEFT_FILL
+ 0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // ICON_ARROW_RIGHT_FILL
+ 0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // ICON_ARROW_DOWN_FILL
+ 0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP_FILL
+ 0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // ICON_AUDIO
+ 0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // ICON_FX
+ 0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // ICON_WAVE
+ 0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // ICON_WAVE_SINUS
+ 0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // ICON_WAVE_SQUARE
+ 0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // ICON_WAVE_TRIANGULAR
+ 0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // ICON_CROSS_SMALL
+ 0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // ICON_PLAYER_PREVIOUS
+ 0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // ICON_PLAYER_PLAY_BACK
+ 0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // ICON_PLAYER_PLAY
+ 0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // ICON_PLAYER_PAUSE
+ 0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // ICON_PLAYER_STOP
+ 0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // ICON_PLAYER_NEXT
+ 0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // ICON_PLAYER_RECORD
+ 0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // ICON_MAGNET
+ 0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_CLOSE
+ 0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_OPEN
+ 0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // ICON_CLOCK
+ 0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // ICON_TOOLS
+ 0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // ICON_GEAR
+ 0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // ICON_GEAR_BIG
+ 0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // ICON_BIN
+ 0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // ICON_HAND_POINTER
+ 0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // ICON_LASER
+ 0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // ICON_COIN
+ 0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // ICON_EXPLOSION
+ 0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // ICON_1UP
+ 0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // ICON_PLAYER
+ 0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // ICON_PLAYER_JUMP
+ 0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // ICON_KEY
+ 0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // ICON_DEMON
+ 0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // ICON_TEXT_POPUP
+ 0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // ICON_GEAR_EX
+ 0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK
+ 0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK_POINTS
+ 0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // ICON_STAR
+ 0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // ICON_DOOR
+ 0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // ICON_EXIT
+ 0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // ICON_MODE_2D
+ 0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // ICON_MODE_3D
+ 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE
+ 0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_TOP
+ 0x7fe00000, 0x50386030, 0x47c2483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // ICON_CUBE_FACE_LEFT
+ 0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // ICON_CUBE_FACE_FRONT
+ 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3bf27be2, 0x0bfe1bfa, 0x000007fe, // ICON_CUBE_FACE_BOTTOM
+ 0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // ICON_CUBE_FACE_RIGHT
+ 0x7fe00000, 0x6fe85ff0, 0x781e77e4, 0x7be27be2, 0x7be27be2, 0x24127be2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_BACK
+ 0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // ICON_CAMERA
+ 0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // ICON_SPECIAL
+ 0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // ICON_LINK_NET
+ 0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // ICON_LINK_BOXES
+ 0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // ICON_LINK_MULTI
+ 0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // ICON_LINK
+ 0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // ICON_LINK_BROKE
+ 0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_TEXT_NOTES
+ 0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // ICON_NOTEBOOK
+ 0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // ICON_SUITCASE
+ 0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // ICON_SUITCASE_ZIP
+ 0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // ICON_MAILBOX
+ 0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // ICON_MONITOR
+ 0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // ICON_PRINTER
+ 0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA
+ 0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA_FLASH
+ 0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // ICON_HOUSE
+ 0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // ICON_HEART
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // ICON_CORNER
+ 0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // ICON_VERTICAL_BARS
+ 0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // ICON_VERTICAL_BARS_FILL
+ 0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // ICON_LIFE_BARS
+ 0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // ICON_INFO
+ 0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // ICON_CROSSLINE
+ 0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // ICON_HELP
+ 0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // ICON_FILETYPE_ALPHA
+ 0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // ICON_FILETYPE_HOME
+ 0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS_VISIBLE
+ 0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS
+ 0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_WINDOW
+ 0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // ICON_HIDPI
+ 0x3ff00000, 0x201c2010, 0x2a842e84, 0x2e842a84, 0x2ba42004, 0x2aa42aa4, 0x20042ba4, 0x00003ffc, // ICON_FILETYPE_BINARY
+ 0x00000000, 0x00000000, 0x00120012, 0x4a5e4bd2, 0x485233d2, 0x00004bd2, 0x00000000, 0x00000000, // ICON_HEX
+ 0x01800000, 0x381c0660, 0x23c42004, 0x23c42044, 0x13c82204, 0x08101008, 0x02400420, 0x00000180, // ICON_SHIELD
+ 0x007e0000, 0x20023fc2, 0x40227fe2, 0x400a403a, 0x400a400a, 0x400a400a, 0x4008400e, 0x00007ff8, // ICON_FILE_NEW
+ 0x00000000, 0x0042007e, 0x40027fc2, 0x44024002, 0x5f024402, 0x44024402, 0x7ffe4002, 0x00000000, // ICON_FOLDER_ADD
+ 0x44220000, 0x12482244, 0xf3cf0000, 0x14280420, 0x48122424, 0x08100810, 0x1ff81008, 0x03c00420, // ICON_ALARM
+ 0x0aa00000, 0x1ff80aa0, 0x1068700e, 0x1008706e, 0x1008700e, 0x1008700e, 0x0aa01ff8, 0x00000aa0, // ICON_CPU
+ 0x07e00000, 0x04201db8, 0x04a01c38, 0x04a01d38, 0x04a01d38, 0x04a01d38, 0x04201d38, 0x000007e0, // ICON_ROM
+ 0x00000000, 0x03c00000, 0x3c382ff0, 0x3c04380c, 0x01800000, 0x03c003c0, 0x00000180, 0x00000000, // ICON_STEP_OVER
+ 0x01800000, 0x01800180, 0x01800180, 0x03c007e0, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_INTO
+ 0x01800000, 0x07e003c0, 0x01800180, 0x01800180, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_OUT
+ 0x00000000, 0x0ff003c0, 0x181c1c34, 0x303c301c, 0x30003000, 0x1c301800, 0x03c00ff0, 0x00000000, // ICON_RESTART
+ 0x00000000, 0x00000000, 0x07e003c0, 0x0ff00ff0, 0x0ff00ff0, 0x03c007e0, 0x00000000, 0x00000000, // ICON_BREAKPOINT_ON
+ 0x00000000, 0x00000000, 0x042003c0, 0x08100810, 0x08100810, 0x03c00420, 0x00000000, 0x00000000, // ICON_BREAKPOINT_OFF
+ 0x00000000, 0x00000000, 0x1ff81ff8, 0x1ff80000, 0x00001ff8, 0x1ff81ff8, 0x00000000, 0x00000000, // ICON_BURGER_MENU
+ 0x00000000, 0x00000000, 0x00880070, 0x0c880088, 0x1e8810f8, 0x3e881288, 0x00000000, 0x00000000, // ICON_CASE_SENSITIVE
+ 0x00000000, 0x02000000, 0x07000a80, 0x07001fc0, 0x02000a80, 0x00300030, 0x00000000, 0x00000000, // ICON_REG_EXP
+ 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_FOLDER
+ 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x00003ffc, // ICON_FILE
+ 0x1ff00000, 0x20082008, 0x17d02fe8, 0x05400ba0, 0x09200540, 0x23881010, 0x2fe827c8, 0x00001ff0, // ICON_SAND_TIMER
+ 0x01800000, 0x02400240, 0x05a00420, 0x09900990, 0x11881188, 0x21842004, 0x40024182, 0x00003ffc, // ICON_WARNING
+ 0x7ffe0000, 0x4ff24002, 0x4c324ff2, 0x4f824c02, 0x41824f82, 0x41824002, 0x40024182, 0x00007ffe, // ICON_HELP_BOX
+ 0x7ffe0000, 0x41824002, 0x40024182, 0x41824182, 0x41824182, 0x41824182, 0x40024182, 0x00007ffe, // ICON_INFO_BOX
+ 0x01800000, 0x04200240, 0x10080810, 0x7bde2004, 0x0a500a50, 0x08500bd0, 0x08100850, 0x00000ff0, // ICON_PRIORITY
+ 0x01800000, 0x18180660, 0x80016006, 0x98196006, 0x99996666, 0x19986666, 0x01800660, 0x00000000, // ICON_LAYERS_ISO
+ 0x07fe0000, 0x1c020402, 0x74021402, 0x54025402, 0x54025402, 0x500857fe, 0x40205ff8, 0x00007fe0, // ICON_LAYERS2
+ 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS
+ 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS
+ 0x04200000, 0x1cf00c60, 0x11f019f0, 0x0f3807b8, 0x1e3c0f3c, 0x1c1c1e1c, 0x1e3c1c1c, 0x00000f70, // ICON_HOT
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_229
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_230
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_231
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_232
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_233
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_234
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_235
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_236
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_237
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_238
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_239
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_240
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_241
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_242
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_243
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_244
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_245
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_246
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_247
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_248
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_249
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255
+};
+
+// NOTE: A pointer to current icons array should be defined
+static unsigned int *guiIconsPtr = guiIcons;
+
+#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS
+
+#ifndef RAYGUI_ICON_SIZE
+ #define RAYGUI_ICON_SIZE 0
+#endif
+
+// WARNING: Those values define the total size of the style data array,
+// if changed, previous saved styles could become incompatible
+#define RAYGUI_MAX_CONTROLS 16 // Maximum number of controls
+#define RAYGUI_MAX_PROPS_BASE 16 // Maximum number of base properties
+#define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// Gui control property style color element
+typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state
+
+static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib)
+static bool guiLocked = false; // Gui lock state (no inputs processed)
+static float guiAlpha = 1.0f; // Gui controls transparency
+
+static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled)
+
+static bool guiTooltip = false; // Tooltip enabled/disabled
+static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user)
+
+static bool guiControlExclusiveMode = false; // Gui control exclusive mode (no inputs processed except current control)
+static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds rectangle, used as an unique identifier
+
+static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*()
+//static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking
+static int autoCursorCooldownCounter = 0; // Cooldown frame counter for automatic cursor movement on key-down
+static int autoCursorDelayCounter = 0; // Delay frame counter for automatic cursor movement
+
+//----------------------------------------------------------------------------------
+// Style data array for all gui style properties (allocated on data segment by default)
+//
+// NOTE 1: First set of BASE properties are generic to all controls but could be individually
+// overwritten per control, first set of EXTENDED properties are generic to all controls and
+// can not be overwritten individually but custom EXTENDED properties can be used by control
+//
+// NOTE 2: A new style set could be loaded over this array using GuiLoadStyle(),
+// but default gui style could always be recovered with GuiLoadStyleDefault()
+//
+// guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB
+//----------------------------------------------------------------------------------
+static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)] = { 0 };
+
+static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization
+
+//----------------------------------------------------------------------------------
+// Standalone Mode Functions Declaration
+//
+// NOTE: raygui depend on some raylib input and drawing functions
+// To use raygui as standalone library, below functions must be defined by the user
+//----------------------------------------------------------------------------------
+#if defined(RAYGUI_STANDALONE)
+
+#define KEY_RIGHT 262
+#define KEY_LEFT 263
+#define KEY_DOWN 264
+#define KEY_UP 265
+#define KEY_BACKSPACE 259
+#define KEY_ENTER 257
+
+#define MOUSE_LEFT_BUTTON 0
+
+// Input required functions
+//-------------------------------------------------------------------------------
+static Vector2 GetMousePosition(void);
+static float GetMouseWheelMove(void);
+static bool IsMouseButtonDown(int button);
+static bool IsMouseButtonPressed(int button);
+static bool IsMouseButtonReleased(int button);
+
+static bool IsKeyDown(int key);
+static bool IsKeyPressed(int key);
+static int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox()
+//-------------------------------------------------------------------------------
+
+// Drawing required functions
+//-------------------------------------------------------------------------------
+static void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle()
+static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker()
+//-------------------------------------------------------------------------------
+
+// Text required functions
+//-------------------------------------------------------------------------------
+static Font GetFontDefault(void); // -- GuiLoadStyleDefault()
+static Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle(), load font
+
+static Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image
+static void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization)
+
+static char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data
+static void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data
+
+static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs
+
+static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list
+static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list
+
+static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle()
+//-------------------------------------------------------------------------------
+
+// raylib functions already implemented in raygui
+//-------------------------------------------------------------------------------
+static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
+static int ColorToInt(Color color); // Returns hexadecimal value for a Color
+static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle
+static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed'
+static const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings
+static int TextToInteger(const char *text); // Get integer value from text
+static float TextToFloat(const char *text); // Get float value from text
+
+static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text
+static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter)
+
+static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient
+//-------------------------------------------------------------------------------
+
+#endif // RAYGUI_STANDALONE
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Declaration
+//----------------------------------------------------------------------------------
+static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only)
+
+static int GetTextWidth(const char *text); // Gui get text width using gui font and style
+static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds
+static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor
+
+static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font
+static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style
+
+static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings
+static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB
+static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV
+
+static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel()
+static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position
+
+static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor
+
+//----------------------------------------------------------------------------------
+// Gui Setup Functions Definition
+//----------------------------------------------------------------------------------
+// Enable gui global state
+// NOTE: We check for STATE_DISABLED to avoid messing custom global state setups
+void GuiEnable(void) { if (guiState == STATE_DISABLED) guiState = STATE_NORMAL; }
+
+// Disable gui global state
+// NOTE: We check for STATE_NORMAL to avoid messing custom global state setups
+void GuiDisable(void) { if (guiState == STATE_NORMAL) guiState = STATE_DISABLED; }
+
+// Lock gui global state
+void GuiLock(void) { guiLocked = true; }
+
+// Unlock gui global state
+void GuiUnlock(void) { guiLocked = false; }
+
+// Check if gui is locked (global state)
+bool GuiIsLocked(void) { return guiLocked; }
+
+// Set gui controls alpha global state
+void GuiSetAlpha(float alpha)
+{
+ if (alpha < 0.0f) alpha = 0.0f;
+ else if (alpha > 1.0f) alpha = 1.0f;
+
+ guiAlpha = alpha;
+}
+
+// Set gui state (global state)
+void GuiSetState(int state) { guiState = (GuiState)state; }
+
+// Get gui state (global state)
+int GuiGetState(void) { return guiState; }
+
+// Set custom gui font
+// NOTE: Font loading/unloading is external to raygui
+void GuiSetFont(Font font)
+{
+ if (font.texture.id > 0)
+ {
+ // NOTE: If we try to setup a font but default style has not been
+ // lazily loaded before, it will be overwritten, so we need to force
+ // default style loading first
+ if (!guiStyleLoaded) GuiLoadStyleDefault();
+
+ guiFont = font;
+ }
+}
+
+// Get custom gui font
+Font GuiGetFont(void)
+{
+ return guiFont;
+}
+
+// Set control style property value
+void GuiSetStyle(int control, int property, int value)
+{
+ if (!guiStyleLoaded) GuiLoadStyleDefault();
+ guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value;
+
+ // Default properties are propagated to all controls
+ if ((control == 0) && (property < RAYGUI_MAX_PROPS_BASE))
+ {
+ for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) guiStyle[i*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value;
+ }
+}
+
+// Get control style property value
+int GuiGetStyle(int control, int property)
+{
+ if (!guiStyleLoaded) GuiLoadStyleDefault();
+ return guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property];
+}
+
+//----------------------------------------------------------------------------------
+// Gui Controls Functions Definition
+//----------------------------------------------------------------------------------
+
+// Window Box control
+int GuiWindowBox(Rectangle bounds, const char *title)
+{
+ // Window title bar height (including borders)
+ // NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox()
+ #if !defined(RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT)
+ #define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24
+ #endif
+
+ int result = 0;
+ //GuiState state = guiState;
+
+ int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT;
+
+ Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight };
+ if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f;
+
+ Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 };
+ Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 20,
+ statusBar.y + statusBarHeight/2.0f - 18.0f/2.0f, 18, 18 };
+
+ // Update control
+ //--------------------------------------------------------------------
+ // NOTE: Logic is directly managed by button
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiStatusBar(statusBar, title); // Draw window header as status bar
+ GuiPanel(windowPanel, NULL); // Draw window base
+
+ // Draw window close button
+ int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
+ int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+#if defined(RAYGUI_NO_ICONS)
+ result = GuiButton(closeButtonRec, "x");
+#else
+ result = GuiButton(closeButtonRec, GuiIconText(ICON_CROSS_SMALL, NULL));
+#endif
+ GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment);
+ //--------------------------------------------------------------------
+
+ return result; // Window close button clicked: result = 1
+}
+
+// Group Box control with text name
+int GuiGroupBox(Rectangle bounds, const char *text)
+{
+ #if !defined(RAYGUI_GROUPBOX_LINE_THICK)
+ #define RAYGUI_GROUPBOX_LINE_THICK 1
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)));
+
+ GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text);
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Line control
+int GuiLine(Rectangle bounds, const char *text)
+{
+ #if !defined(RAYGUI_LINE_ORIGIN_SIZE)
+ #define RAYGUI_LINE_MARGIN_TEXT 12
+ #endif
+ #if !defined(RAYGUI_LINE_TEXT_PADDING)
+ #define RAYGUI_LINE_TEXT_PADDING 4
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR));
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (text == NULL) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, bounds.width, 1 }, 0, BLANK, color);
+ else
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.height = bounds.height;
+ textBounds.x = bounds.x + RAYGUI_LINE_MARGIN_TEXT;
+ textBounds.y = bounds.y;
+
+ // Draw line with embedded text label: "--- text --------------"
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color);
+ GuiDrawText(text, textBounds, TEXT_ALIGN_LEFT, color);
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + 12 + textBounds.width + 4, bounds.y + bounds.height/2, bounds.width - textBounds.width - RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color);
+ }
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Panel control
+int GuiPanel(Rectangle bounds, const char *text)
+{
+ #if !defined(RAYGUI_PANEL_BORDER_WIDTH)
+ #define RAYGUI_PANEL_BORDER_WIDTH 1
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ // Text will be drawn as a header bar (if provided)
+ Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT };
+ if ((text != NULL) && (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f)) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f;
+
+ if (text != NULL)
+ {
+ // Move panel bounds after the header bar
+ bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1;
+ bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1;
+ }
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar
+
+ GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED: (int)LINE_COLOR)),
+ GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR)));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Tab Bar control
+// NOTE: Using GuiToggle() for the TABS
+int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
+{
+ #define RAYGUI_TABBAR_ITEM_WIDTH 160
+
+ int result = -1;
+ //GuiState state = guiState;
+
+ Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height };
+
+ if (*active < 0) *active = 0;
+ else if (*active > count - 1) *active = count - 1;
+
+ int offsetX = 0; // Required in case tabs go out of screen
+ offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth();
+ if (offsetX < 0) offsetX = 0;
+
+ bool toggle = false; // Required for individual toggles
+
+ // Draw control
+ //--------------------------------------------------------------------
+ for (int i = 0; i < count; i++)
+ {
+ tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX;
+
+ if (tabBounds.x < GetScreenWidth())
+ {
+ // Draw tabs as toggle controls
+ int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT);
+ int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING);
+ GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+ GuiSetStyle(TOGGLE, TEXT_PADDING, 8);
+
+ if (i == (*active))
+ {
+ toggle = true;
+ GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle);
+ }
+ else
+ {
+ toggle = false;
+ GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle);
+ if (toggle) *active = i;
+ }
+
+ // Close tab with middle mouse button pressed
+ if (CheckCollisionPointRec(GetMousePosition(), tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i;
+
+ GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding);
+ GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment);
+
+ // Draw tab close button
+ // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds))
+ int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
+ int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+#if defined(RAYGUI_NO_ICONS)
+ if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i;
+#else
+ if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i;
+#endif
+ GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment);
+ }
+ }
+
+ // Draw tab-bar bottom line
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL)));
+ //--------------------------------------------------------------------
+
+ return result; // Return as result the current TAB closing requested
+}
+
+// Scroll Panel control
+int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view)
+{
+ #define RAYGUI_MIN_SCROLLBAR_WIDTH 40
+ #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40
+ #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20
+
+ int result = 0;
+ GuiState state = guiState;
+
+ Rectangle temp = { 0 };
+ if (view == NULL) view = &temp;
+
+ Vector2 scrollPos = { 0.0f, 0.0f };
+ if (scroll != NULL) scrollPos = *scroll;
+
+ // Text will be drawn as a header bar (if provided)
+ Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT };
+ if (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f;
+
+ if (text != NULL)
+ {
+ // Move panel bounds after the header bar
+ bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1;
+ bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + 1;
+ }
+
+ bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false;
+ bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false;
+
+ // Recheck to account for the other scrollbar being visible
+ if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false;
+ if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false;
+
+ int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0;
+ int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0;
+ Rectangle horizontalScrollBar = {
+ (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH),
+ (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH),
+ (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH),
+ (float)horizontalScrollBarWidth
+ };
+ Rectangle verticalScrollBar = {
+ (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)),
+ (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH),
+ (float)verticalScrollBarWidth,
+ (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH)
+ };
+
+ // Make sure scroll bars have a minimum width/height
+ if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH;
+ if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT;
+
+ // Calculate view area (area without the scrollbars)
+ *view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)?
+ RAYGUI_CLITERAL(Rectangle){ bounds.x + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth } :
+ RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth };
+
+ // Clip view area to the actual content size
+ if (view->width > content.width) view->width = content.width;
+ if (view->height > content.height) view->height = content.height;
+
+ float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH);
+ float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH);
+ float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f;
+ float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH);
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check button state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+
+#if defined(SUPPORT_SCROLLBAR_KEY_INPUT)
+ if (hasHorizontalScrollBar)
+ {
+ if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ }
+
+ if (hasVerticalScrollBar)
+ {
+ if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ }
+#endif
+ float wheelMove = GetMouseWheelMove();
+
+ // Set scrolling speed with mouse wheel based on ratio between bounds and content
+ Vector2 mouseWheelSpeed = { content.width/bounds.width, content.height/bounds.height };
+ if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
+ if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED;
+
+ // Horizontal and vertical scrolling with mouse wheel
+ if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x;
+ else scrollPos.y += wheelMove*mouseWheelSpeed.y; // Vertical scroll
+ }
+ }
+
+ // Normalize scroll values
+ if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin;
+ if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax;
+ if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin;
+ if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax;
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar
+
+ GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
+
+ // Save size of the scrollbar slider
+ const int slider = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE);
+
+ // Draw horizontal scrollbar if visible
+ if (hasHorizontalScrollBar)
+ {
+ // Change scrollbar slider size to show the diff in size between the content width and the widget width
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/(int)content.width)*((int)bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)));
+ scrollPos.x = (float)-GuiScrollBar(horizontalScrollBar, (int)-scrollPos.x, (int)horizontalMin, (int)horizontalMax);
+ }
+ else scrollPos.x = 0.0f;
+
+ // Draw vertical scrollbar if visible
+ if (hasVerticalScrollBar)
+ {
+ // Change scrollbar slider size to show the diff in size between the content height and the widget height
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/(int)content.height)*((int)bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)));
+ scrollPos.y = (float)-GuiScrollBar(verticalScrollBar, (int)-scrollPos.y, (int)verticalMin, (int)verticalMax);
+ }
+ else scrollPos.y = 0.0f;
+
+ // Draw detail corner rectangle if both scroll bars are visible
+ if (hasHorizontalScrollBar && hasVerticalScrollBar)
+ {
+ Rectangle corner = { (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) + 2) : (horizontalScrollBar.x + horizontalScrollBar.width + 2), verticalScrollBar.y + verticalScrollBar.height + 2, (float)horizontalScrollBarWidth - 4, (float)verticalScrollBarWidth - 4 };
+ GuiDrawRectangle(corner, 0, BLANK, GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3))));
+ }
+
+ // Draw scrollbar lines depending on current state
+ GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK);
+
+ // Set scrollbar slider size back to the way it was before
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider);
+ //--------------------------------------------------------------------
+
+ if (scroll != NULL) *scroll = scrollPos;
+
+ return result;
+}
+
+// Label control
+int GuiLabel(Rectangle bounds, const char *text)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ // Update control
+ //--------------------------------------------------------------------
+ //...
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Button control, returns true when clicked
+int GuiButton(Rectangle bounds, const char *text)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check button state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+
+ if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), GetColor(GuiGetStyle(BUTTON, BASE + (state*3))));
+ GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))));
+
+ if (state == STATE_FOCUSED) GuiTooltip(bounds);
+ //------------------------------------------------------------------
+
+ return result; // Button pressed: result = 1
+}
+
+// Label button control
+int GuiLabelButton(Rectangle bounds, const char *text)
+{
+ GuiState state = guiState;
+ bool pressed = false;
+
+ // NOTE: We force bounds.width to be all text
+ float textWidth = (float)GetTextWidth(text);
+ if ((bounds.width - 2*GuiGetStyle(LABEL, BORDER_WIDTH) - 2*GuiGetStyle(LABEL, TEXT_PADDING)) < textWidth) bounds.width = textWidth + 2*GuiGetStyle(LABEL, BORDER_WIDTH) + 2*GuiGetStyle(LABEL, TEXT_PADDING) + 2;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check checkbox state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+
+ if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return pressed;
+}
+
+// Toggle Button control
+int GuiToggle(Rectangle bounds, const char *text, bool *active)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ bool temp = false;
+ if (active == NULL) active = &temp;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check toggle button state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_NORMAL;
+ *active = !(*active);
+ }
+ else state = STATE_FOCUSED;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state == STATE_NORMAL)
+ {
+ GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3)))), GetColor(GuiGetStyle(TOGGLE, ((*active)? BASE_COLOR_PRESSED : (BASE + state*3)))));
+ GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, ((*active)? TEXT_COLOR_PRESSED : (TEXT + state*3)))));
+ }
+ else
+ {
+ GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), GetColor(GuiGetStyle(TOGGLE, BASE + state*3)));
+ GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, TEXT + state*3)));
+ }
+
+ if (state == STATE_FOCUSED) GuiTooltip(bounds);
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Toggle Group control
+int GuiToggleGroup(Rectangle bounds, const char *text, int *active)
+{
+ #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS)
+ #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32
+ #endif
+
+ int result = 0;
+ float initBoundsX = bounds.x;
+
+ int temp = 0;
+ if (active == NULL) active = &temp;
+
+ bool toggle = false; // Required for individual toggles
+
+ // Get substrings items from text (items pointers)
+ int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 };
+ int itemCount = 0;
+ const char **items = GuiTextSplit(text, ';', &itemCount, rows);
+
+ int prevRow = rows[0];
+
+ for (int i = 0; i < itemCount; i++)
+ {
+ if (prevRow != rows[i])
+ {
+ bounds.x = initBoundsX;
+ bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING));
+ prevRow = rows[i];
+ }
+
+ if (i == (*active))
+ {
+ toggle = true;
+ GuiToggle(bounds, items[i], &toggle);
+ }
+ else
+ {
+ toggle = false;
+ GuiToggle(bounds, items[i], &toggle);
+ if (toggle) *active = i;
+ }
+
+ bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING));
+ }
+
+ return result;
+}
+
+// Toggle Slider control extended
+int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ int temp = 0;
+ if (active == NULL) active = &temp;
+
+ //bool toggle = false; // Required for individual toggles
+
+ // Get substrings items from text (items pointers)
+ int itemCount = 0;
+ const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
+
+ Rectangle slider = {
+ 0, // Calculated later depending on the active toggle
+ bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
+ (bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - (itemCount + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING))/itemCount,
+ bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ (*active)++;
+ result = 1;
+ }
+ else state = STATE_FOCUSED;
+ }
+
+ if ((*active) && (state != STATE_FOCUSED)) state = STATE_PRESSED;
+ }
+
+ if (*active >= itemCount) *active = 0;
+ slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width;
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + (state*3))),
+ GetColor(GuiGetStyle(TOGGLE, BASE_COLOR_NORMAL)));
+
+ // Draw internal slider
+ if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
+ else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_FOCUSED)));
+ else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
+
+ // Draw text in slider
+ if (text != NULL)
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GetTextWidth(text);
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = slider.x + slider.width/2 - textBounds.width/2;
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+ GuiDrawText(items[*active], textBounds, GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + (state*3))), guiAlpha));
+ }
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Check Box control, returns 1 when state changed
+int GuiCheckBox(Rectangle bounds, const char *text, bool *checked)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ bool temp = false;
+ if (checked == NULL) checked = &temp;
+
+ Rectangle textBounds = { 0 };
+
+ if (text != NULL)
+ {
+ textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+ if (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(CHECKBOX, TEXT_PADDING);
+ }
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ Rectangle totalBounds = {
+ (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT)? textBounds.x : bounds.x,
+ bounds.y,
+ bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING),
+ bounds.height,
+ };
+
+ // Check checkbox state
+ if (CheckCollisionPointRec(mousePoint, totalBounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+
+ if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
+ {
+ *checked = !(*checked);
+ result = 1;
+ }
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), BLANK);
+
+ if (*checked)
+ {
+ Rectangle check = { bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING),
+ bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING),
+ bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)),
+ bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)) };
+ GuiDrawRectangle(check, 0, BLANK, GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)));
+ }
+
+ GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Combo Box control
+int GuiComboBox(Rectangle bounds, const char *text, int *active)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ int temp = 0;
+ if (active == NULL) active = &temp;
+
+ bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING));
+
+ Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING),
+ (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height };
+
+ // Get substrings items from text (items pointers, lengths and count)
+ int itemCount = 0;
+ const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
+
+ if (*active < 0) *active = 0;
+ else if (*active > (itemCount - 1)) *active = itemCount - 1;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (CheckCollisionPointRec(mousePoint, bounds) ||
+ CheckCollisionPointRec(mousePoint, selector))
+ {
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ *active += 1;
+ if (*active >= itemCount) *active = 0; // Cyclic combobox
+ }
+
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ // Draw combo box main
+ GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3))));
+ GuiDrawText(items[*active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3))));
+
+ // Draw selector using a custom button
+ // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
+ int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
+ int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, 1);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+ GuiButton(selector, TextFormat("%i/%i", *active + 1, itemCount));
+
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Dropdown Box control
+// NOTE: Returns mouse click
+int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ int temp = 0;
+ if (active == NULL) active = &temp;
+
+ int itemSelected = *active;
+ int itemFocused = -1;
+
+ int direction = 0; // Dropdown box open direction: down (default)
+ if (GuiGetStyle(DROPDOWNBOX, DROPDOWN_ROLL_UP) == 1) direction = 1; // Up
+
+ // Get substrings items from text (items pointers, lengths and count)
+ int itemCount = 0;
+ const char **items = GuiTextSplit(text, ';', &itemCount, NULL);
+
+ Rectangle boundsOpen = bounds;
+ boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+ if (direction == 1) boundsOpen.y -= itemCount*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)) + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING);
+
+ Rectangle itemBounds = bounds;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (editMode)
+ {
+ state = STATE_PRESSED;
+
+ // Check if mouse has been pressed or released outside limits
+ if (!CheckCollisionPointRec(mousePoint, boundsOpen))
+ {
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1;
+ }
+
+ // Check if already selected item has been pressed again
+ if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
+
+ // Check focused and selected item
+ for (int i = 0; i < itemCount; i++)
+ {
+ // Update item rectangle y position for next item
+ if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+ else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+
+ if (CheckCollisionPointRec(mousePoint, itemBounds))
+ {
+ itemFocused = i;
+ if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON))
+ {
+ itemSelected = i;
+ result = 1; // Item selected
+ }
+ break;
+ }
+ }
+
+ itemBounds = bounds;
+ }
+ else
+ {
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ result = 1;
+ state = STATE_PRESSED;
+ }
+ else state = STATE_FOCUSED;
+ }
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (editMode) GuiPanel(boundsOpen, NULL);
+
+ GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3)));
+ GuiDrawText(items[itemSelected], GetTextBounds(DROPDOWNBOX, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3)));
+
+ if (editMode)
+ {
+ // Draw visible items
+ for (int i = 0; i < itemCount; i++)
+ {
+ // Update item rectangle y position for next item
+ if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+ else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
+
+ if (i == itemSelected)
+ {
+ GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED)));
+ GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED)));
+ }
+ else if (i == itemFocused)
+ {
+ GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED)));
+ GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED)));
+ }
+ else GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL)));
+ }
+ }
+
+ if (!GuiGetStyle(DROPDOWNBOX, DROPDOWN_ARROW_HIDDEN))
+ {
+ // Draw arrows (using icon if available)
+#if defined(RAYGUI_NO_ICONS)
+ GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
+#else
+ GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL
+#endif
+ }
+ //--------------------------------------------------------------------
+
+ *active = itemSelected;
+
+ // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item...
+ return result; // Mouse click: result = 1
+}
+
+// Text Box control
+// NOTE: Returns true on ENTER pressed (useful for data validation)
+int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
+{
+ #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)
+ #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 40 // Frames to wait for autocursor movement
+ #endif
+ #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY)
+ #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ bool multiline = false; // TODO: Consider multiline text input
+ int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE);
+
+ Rectangle textBounds = GetTextBounds(TEXTBOX, bounds);
+ int textLength = (int)strlen(text); // Get current text length
+ int thisCursorIndex = textBoxCursorIndex;
+ if (thisCursorIndex > textLength) thisCursorIndex = textLength;
+ int textWidth = GetTextWidth(text) - GetTextWidth(text + thisCursorIndex);
+ int textIndexOffset = 0; // Text index offset to start drawing in the box
+
+ // Cursor rectangle
+ // NOTE: Position X value should be updated
+ Rectangle cursor = {
+ textBounds.x + textWidth + GuiGetStyle(DEFAULT, TEXT_SPACING),
+ textBounds.y + textBounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE),
+ 2,
+ (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2
+ };
+
+ if (cursor.height >= bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2;
+ if (cursor.y < (bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH))) cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH);
+
+ // Mouse cursor rectangle
+ // NOTE: Initialized outside of screen
+ Rectangle mouseCursor = cursor;
+ mouseCursor.x = -1;
+ mouseCursor.width = 1;
+
+ // Auto-cursor movement logic
+ // NOTE: Cursor moves automatically when key down after some time
+ if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCooldownCounter++;
+ else
+ {
+ autoCursorCooldownCounter = 0; // GLOBAL: Cursor cooldown counter
+ autoCursorDelayCounter = 0; // GLOBAL: Cursor delay counter
+ }
+
+ // Blink-cursor frame counter
+ //if (!autoCursorMode) blinkCursorFrameCounter++;
+ //else blinkCursorFrameCounter = 0;
+
+ // Update control
+ //--------------------------------------------------------------------
+ // WARNING: Text editing is only supported under certain conditions:
+ if ((state != STATE_DISABLED) && // Control not disabled
+ !GuiGetStyle(TEXTBOX, TEXT_READONLY) && // TextBox not on read-only mode
+ !guiLocked && // Gui not locked
+ !guiControlExclusiveMode && // No gui slider on dragging
+ (wrapMode == TEXT_WRAP_NONE)) // No wrap mode
+ {
+ Vector2 mousePosition = GetMousePosition();
+
+ if (editMode)
+ {
+ state = STATE_PRESSED;
+
+ if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
+
+ // If text does not fit in the textbox and current cursor position is out of bounds,
+ // we add an index offset to text for drawing only what requires depending on cursor
+ while (textWidth >= textBounds.width)
+ {
+ int nextCodepointSize = 0;
+ GetCodepointNext(text + textIndexOffset, &nextCodepointSize);
+
+ textIndexOffset += nextCodepointSize;
+
+ textWidth = GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex);
+ }
+
+ int codepoint = GetCharPressed(); // Get Unicode codepoint
+ if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n';
+
+ // Encode codepoint as UTF-8
+ int codepointSize = 0;
+ const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize);
+
+ // Add codepoint to text, at current cursor position
+ // NOTE: Make sure we do not overflow buffer size
+ if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize))
+ {
+ // Move forward data from cursor position
+ for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize];
+
+ // Add new codepoint in current cursor position
+ for (int i = 0; i < codepointSize; i++) text[textBoxCursorIndex + i] = charEncoded[i];
+
+ textBoxCursorIndex += codepointSize;
+ textLength += codepointSize;
+
+ // Make sure text last character is EOL
+ text[textLength] = '\0';
+ }
+
+ // Move cursor to start
+ if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0;
+
+ // Move cursor to end
+ if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength;
+
+ // Delete codepoint from text, after current cursor position
+ if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
+ {
+ autoCursorDelayCounter++;
+
+ if (IsKeyPressed(KEY_DELETE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
+ {
+ int nextCodepointSize = 0;
+ GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
+
+ // Move backward text from cursor position
+ for (int i = textBoxCursorIndex; i < textLength; i++) text[i] = text[i + nextCodepointSize];
+
+ textLength -= codepointSize;
+ if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
+
+ // Make sure text last character is EOL
+ text[textLength] = '\0';
+ }
+ }
+
+ // Delete related codepoints from text, before current cursor position
+ if ((textLength > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)))
+ {
+ int i = textBoxCursorIndex - 1;
+ int accCodepointSize = 0;
+
+ // Move cursor to the end of word if on space already
+ while ((i > 0) && isspace(text[i]))
+ {
+ int prevCodepointSize = 0;
+ GetCodepointPrevious(text + i, &prevCodepointSize);
+ i -= prevCodepointSize;
+ accCodepointSize += prevCodepointSize;
+ }
+
+ // Move cursor to the start of the word
+ while ((i > 0) && !isspace(text[i]))
+ {
+ int prevCodepointSize = 0;
+ GetCodepointPrevious(text + i, &prevCodepointSize);
+ i -= prevCodepointSize;
+ accCodepointSize += prevCodepointSize;
+ }
+
+ // Move forward text from cursor position
+ for (int j = (textBoxCursorIndex - accCodepointSize); j < textLength; j++) text[j] = text[j + accCodepointSize];
+
+ // Prevent cursor index from decrementing past 0
+ if (textBoxCursorIndex > 0)
+ {
+ textBoxCursorIndex -= accCodepointSize;
+ textLength -= accCodepointSize;
+ }
+
+ // Make sure text last character is EOL
+ text[textLength] = '\0';
+ }
+ else if ((textLength > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && (autoCursorCooldownCounter >= RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN))))
+ {
+ autoCursorDelayCounter++;
+
+ if (IsKeyPressed(KEY_BACKSPACE) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
+ {
+ int prevCodepointSize = 0;
+
+ // Prevent cursor index from decrementing past 0
+ if (textBoxCursorIndex > 0)
+ {
+ GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
+
+ // Move backward text from cursor position
+ for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize];
+
+ textBoxCursorIndex -= codepointSize;
+ textLength -= codepointSize;
+ }
+
+ // Make sure text last character is EOL
+ text[textLength] = '\0';
+ }
+ }
+
+ // Move cursor position with keys
+ if (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
+ {
+ autoCursorDelayCounter++;
+
+ if (IsKeyPressed(KEY_LEFT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
+ {
+ int prevCodepointSize = 0;
+ if (textBoxCursorIndex > 0) GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize);
+
+ if (textBoxCursorIndex >= prevCodepointSize) textBoxCursorIndex -= prevCodepointSize;
+ }
+ }
+ else if (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && (autoCursorCooldownCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)))
+ {
+ autoCursorDelayCounter++;
+
+ if (IsKeyPressed(KEY_RIGHT) || (autoCursorDelayCounter%RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0) // Delay every movement some frames
+ {
+ int nextCodepointSize = 0;
+ GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize);
+
+ if ((textBoxCursorIndex + nextCodepointSize) <= textLength) textBoxCursorIndex += nextCodepointSize;
+ }
+ }
+
+ // Move cursor position with mouse
+ if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text
+ {
+ float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize;
+ int codepointIndex = 0;
+ float glyphWidth = 0.0f;
+ float widthToMouseX = 0;
+ int mouseCursorIndex = 0;
+
+ for (int i = textIndexOffset; i < textLength; i++)
+ {
+ codepoint = GetCodepointNext(&text[i], &codepointSize);
+ codepointIndex = GetGlyphIndex(guiFont, codepoint);
+
+ if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
+ else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
+
+ if (mousePosition.x <= (textBounds.x + (widthToMouseX + glyphWidth/2)))
+ {
+ mouseCursor.x = textBounds.x + widthToMouseX;
+ mouseCursorIndex = i;
+ break;
+ }
+
+ widthToMouseX += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ }
+
+ // Check if mouse cursor is at the last position
+ int textEndWidth = GetTextWidth(text + textIndexOffset);
+ if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2))
+ {
+ mouseCursor.x = textBounds.x + textEndWidth;
+ mouseCursorIndex = textLength;
+ }
+
+ // Place cursor at required index on mouse click
+ if ((mouseCursor.x >= 0) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ cursor.x = mouseCursor.x;
+ textBoxCursorIndex = mouseCursorIndex;
+ }
+ }
+ else mouseCursor.x = -1;
+
+ // Recalculate cursor position.y depending on textBoxCursorIndex
+ cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING);
+ //if (multiline) cursor.y = GetTextLines()
+
+ // Finish text editing on ENTER or mouse click outside bounds
+ if ((!multiline && IsKeyPressed(KEY_ENTER)) ||
+ (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
+ {
+ textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index
+ result = 1;
+ }
+ }
+ else
+ {
+ if (CheckCollisionPointRec(mousePosition, bounds))
+ {
+ state = STATE_FOCUSED;
+
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text
+ result = 1;
+ }
+ }
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state == STATE_PRESSED)
+ {
+ GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)));
+ }
+ else if (state == STATE_DISABLED)
+ {
+ GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)));
+ }
+ else GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), BLANK);
+
+ // Draw text considering index offset if required
+ // NOTE: Text index offset depends on cursor position
+ GuiDrawText(text + textIndexOffset, textBounds, GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))));
+
+ // Draw cursor
+ if (editMode && !GuiGetStyle(TEXTBOX, TEXT_READONLY))
+ {
+ //if (autoCursorMode || ((blinkCursorFrameCounter/40)%2 == 0))
+ GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)));
+
+ // Draw mouse position cursor (if required)
+ if (mouseCursor.x >= 0) GuiDrawRectangle(mouseCursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)));
+ }
+ else if (state == STATE_FOCUSED) GuiTooltip(bounds);
+ //--------------------------------------------------------------------
+
+ return result; // Mouse button pressed: result = 1
+}
+
+/*
+// Text Box control with multiple lines and word-wrap
+// NOTE: This text-box is readonly, no editing supported by default
+bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
+{
+ bool pressed = false;
+
+ GuiSetStyle(TEXTBOX, TEXT_READONLY, 1);
+ GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // WARNING: If wrap mode enabled, text editing is not supported
+ GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP);
+
+ // TODO: Implement methods to calculate cursor position properly
+ pressed = GuiTextBox(bounds, text, textSize, editMode);
+
+ GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE);
+ GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE);
+ GuiSetStyle(TEXTBOX, TEXT_READONLY, 0);
+
+ return pressed;
+}
+*/
+
+// Spinner control, returns selected value
+int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
+{
+ int result = 1;
+ GuiState state = guiState;
+
+ int tempValue = *value;
+
+ Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING), bounds.y,
+ bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_SPACING)), bounds.height };
+ Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
+ Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height };
+
+ Rectangle textBounds = { 0 };
+ if (text != NULL)
+ {
+ textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(SPINNER, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+ if (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SPINNER, TEXT_PADDING);
+ }
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check spinner state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+ }
+ }
+
+#if defined(RAYGUI_NO_ICONS)
+ if (GuiButton(leftButtonBound, "<")) tempValue--;
+ if (GuiButton(rightButtonBound, ">")) tempValue++;
+#else
+ if (GuiButton(leftButtonBound, GuiIconText(ICON_ARROW_LEFT_FILL, NULL))) tempValue--;
+ if (GuiButton(rightButtonBound, GuiIconText(ICON_ARROW_RIGHT_FILL, NULL))) tempValue++;
+#endif
+
+ if (!editMode)
+ {
+ if (tempValue < minValue) tempValue = minValue;
+ if (tempValue > maxValue) tempValue = maxValue;
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ result = GuiValueBox(spinner, NULL, &tempValue, minValue, maxValue, editMode);
+
+ // Draw value selector custom buttons
+ // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values
+ int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH);
+ int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH));
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth);
+
+ // Draw text label if provided
+ GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ *value = tempValue;
+ return result;
+}
+
+// Value Box control, updates input text with numbers
+// NOTE: Requires static variables: frameCounter
+int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode)
+{
+ #if !defined(RAYGUI_VALUEBOX_MAX_CHARS)
+ #define RAYGUI_VALUEBOX_MAX_CHARS 32
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
+ sprintf(textValue, "%i", *value);
+
+ Rectangle textBounds = { 0 };
+ if (text != NULL)
+ {
+ textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+ if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
+ }
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ bool valueHasChanged = false;
+
+ if (editMode)
+ {
+ state = STATE_PRESSED;
+
+ int keyCount = (int)strlen(textValue);
+
+ // Only allow keys in range [48..57]
+ if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
+ {
+ if (GetTextWidth(textValue) < bounds.width)
+ {
+ int key = GetCharPressed();
+ if ((key >= 48) && (key <= 57))
+ {
+ textValue[keyCount] = (char)key;
+ keyCount++;
+ valueHasChanged = true;
+ }
+ }
+ }
+
+ // Delete text
+ if (keyCount > 0)
+ {
+ if (IsKeyPressed(KEY_BACKSPACE))
+ {
+ keyCount--;
+ textValue[keyCount] = '\0';
+ valueHasChanged = true;
+ }
+ }
+
+ if (valueHasChanged) *value = TextToInteger(textValue);
+
+ // NOTE: We are not clamp values until user input finishes
+ //if (*value > maxValue) *value = maxValue;
+ //else if (*value < minValue) *value = minValue;
+
+ if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)))
+ {
+ if (*value > maxValue) *value = maxValue;
+ else if (*value < minValue) *value = minValue;
+
+ result = 1;
+ }
+ }
+ else
+ {
+ if (*value > maxValue) *value = maxValue;
+ else if (*value < minValue) *value = minValue;
+
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ state = STATE_FOCUSED;
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
+ }
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ Color baseColor = BLANK;
+ if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED));
+ else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED));
+
+ GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor);
+ GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))));
+
+ // Draw cursor
+ if (editMode)
+ {
+ // NOTE: ValueBox internal text is always centered
+ Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) };
+ GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)));
+ }
+
+ // Draw text label if provided
+ GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Floating point Value Box control, updates input val_str with numbers
+// NOTE: Requires static variables: frameCounter
+int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode)
+{
+ #if !defined(RAYGUI_VALUEBOX_MAX_CHARS)
+ #define RAYGUI_VALUEBOX_MAX_CHARS 32
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0";
+ //sprintf(textValue, "%2.2f", *value);
+
+ Rectangle textBounds = {0};
+ if (text != NULL)
+ {
+ textBounds.width = (float)GetTextWidth(text) + 2;
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+ if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING);
+ }
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ bool valueHasChanged = false;
+
+ if (editMode)
+ {
+ state = STATE_PRESSED;
+
+ int keyCount = (int)strlen(textValue);
+
+ // Only allow keys in range [48..57]
+ if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS)
+ {
+ if (GetTextWidth(textValue) < bounds.width)
+ {
+ int key = GetCharPressed();
+ if (((key >= 48) && (key <= 57)) ||
+ (key == '.') ||
+ ((keyCount == 0) && (key == '+')) || // NOTE: Sign can only be in first position
+ ((keyCount == 0) && (key == '-')))
+ {
+ textValue[keyCount] = (char)key;
+ keyCount++;
+
+ valueHasChanged = true;
+ }
+ }
+ }
+
+ // Pressed backspace
+ if (IsKeyPressed(KEY_BACKSPACE))
+ {
+ if (keyCount > 0)
+ {
+ keyCount--;
+ textValue[keyCount] = '\0';
+ valueHasChanged = true;
+ }
+ }
+
+ if (valueHasChanged) *value = TextToFloat(textValue);
+
+ if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1;
+ }
+ else
+ {
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ state = STATE_FOCUSED;
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1;
+ }
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ Color baseColor = BLANK;
+ if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED));
+ else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED));
+
+ GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor);
+ GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))));
+
+ // Draw cursor
+ if (editMode)
+ {
+ // NOTE: ValueBox internal text is always centered
+ Rectangle cursor = {bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 1,
+ bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4,
+ bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH)};
+ GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)));
+ }
+
+ // Draw text label if provided
+ GuiDrawText(text, textBounds,
+ (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT,
+ GetColor(GuiGetStyle(LABEL, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Slider control with pro parameters
+// NOTE: Other GuiSlider*() controls use this one
+int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue, int sliderWidth)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ float temp = (maxValue - minValue)/2.0f;
+ if (value == NULL) value = &temp;
+ float oldValue = *value;
+
+ Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
+ 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ {
+ state = STATE_PRESSED;
+ // Get equivalent value and slider position from mousePosition.x
+ *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue;
+ }
+ }
+ else
+ {
+ guiControlExclusiveMode = false;
+ guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ }
+ }
+ else if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ guiControlExclusiveMode = true;
+ guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+
+ if (!CheckCollisionPointRec(mousePoint, slider))
+ {
+ // Get equivalent value and slider position from mousePosition.x
+ *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue;
+ }
+ }
+ else state = STATE_FOCUSED;
+ }
+
+ if (*value > maxValue) *value = maxValue;
+ else if (*value < minValue) *value = minValue;
+ }
+
+ // Control value change check
+ if (oldValue == *value) result = 0;
+ else result = 1;
+
+ // Slider bar limits check
+ float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH)));
+ if (sliderWidth > 0) // Slider
+ {
+ slider.x += sliderValue;
+ slider.width = (float)sliderWidth;
+ if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH);
+ else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH);
+ }
+ else if (sliderWidth == 0) // SliderBar
+ {
+ slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH);
+ slider.width = sliderValue;
+ if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH);
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)));
+
+ // Draw slider internal bar (depends on state)
+ if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)));
+ else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)));
+ else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED)));
+
+ // Draw left/right text if provided
+ if (textLeft != NULL)
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GetTextWidth(textLeft);
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+ GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))));
+ }
+
+ if (textRight != NULL)
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GetTextWidth(textRight);
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+ GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))));
+ }
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Slider control extended, returns selected value and has text
+int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
+{
+ return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH));
+}
+
+// Slider Bar control extended, returns selected value
+int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
+{
+ return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, 0);
+}
+
+// Progress Bar control extended, shows current progress value
+int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ float temp = (maxValue - minValue)/2.0f;
+ if (value == NULL) value = &temp;
+
+ // Progress bar
+ Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH),
+ bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0,
+ bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if (*value > maxValue) *value = maxValue;
+
+ // WARNING: Working with floats could lead to rounding issues
+ if ((state != STATE_DISABLED)) progress.width = (float)(*value/(maxValue - minValue))*bounds.width - ((*value >= maxValue)? (float)(2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)) : 0.0f);
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state == STATE_DISABLED)
+ {
+ GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), BLANK);
+ }
+ else
+ {
+ if (*value > minValue)
+ {
+ // Draw progress bar with colored border, more visual
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
+ }
+ else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+
+ if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + 1, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED)));
+ else
+ {
+ // Draw borders not yet reached by value
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + 1, bounds.y + bounds.height - 1, bounds.width - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL)));
+ }
+
+ // Draw slider internal progress bar (depends on state)
+ GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED)));
+ }
+
+ // Draw left/right text if provided
+ if (textLeft != NULL)
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GetTextWidth(textLeft);
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+ GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))));
+ }
+
+ if (textRight != NULL)
+ {
+ Rectangle textBounds = { 0 };
+ textBounds.width = (float)GetTextWidth(textRight);
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING);
+ textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+
+ GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))));
+ }
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Status Bar control
+int GuiStatusBar(Rectangle bounds, const char *text)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3))));
+ GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), GetColor(GuiGetStyle(STATUSBAR, TEXT + (state*3))));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Dummy rectangle control, intended for placeholding
+int GuiDummyRec(Rectangle bounds, const char *text)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check button state
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED;
+ else state = STATE_FOCUSED;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)));
+ GuiDrawText(text, GetTextBounds(DEFAULT, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(BUTTON, (state != STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)));
+ //------------------------------------------------------------------
+
+ return result;
+}
+
+// List View control
+int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active)
+{
+ int result = 0;
+ int itemCount = 0;
+ const char **items = NULL;
+
+ if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL);
+
+ result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL);
+
+ return result;
+}
+
+// List View control with extended parameters
+int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus)
+{
+ int result = 0;
+ GuiState state = guiState;
+
+ int itemFocused = (focus == NULL)? -1 : *focus;
+ int itemSelected = (active == NULL)? -1 : *active;
+
+ // Check if we need a scroll bar
+ bool useScrollBar = false;
+ if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING))*count > bounds.height) useScrollBar = true;
+
+ // Define base item rectangle [0]
+ Rectangle itemBounds = { 0 };
+ itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING);
+ itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
+ itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
+ itemBounds.height = (float)GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
+ if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH);
+
+ // Get items on the list
+ int visibleItems = (int)bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING));
+ if (visibleItems > count) visibleItems = count;
+
+ int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex;
+ if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0;
+ int endIndex = startIndex + visibleItems;
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ // Check mouse inside list view
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ state = STATE_FOCUSED;
+
+ // Check focused and selected item
+ for (int i = 0; i < visibleItems; i++)
+ {
+ if (CheckCollisionPointRec(mousePoint, itemBounds))
+ {
+ itemFocused = startIndex + i;
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ if (itemSelected == (startIndex + i)) itemSelected = -1;
+ else itemSelected = startIndex + i;
+ }
+ break;
+ }
+
+ // Update item rectangle y position for next item
+ itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING));
+ }
+
+ if (useScrollBar)
+ {
+ int wheelMove = (int)GetMouseWheelMove();
+ startIndex -= wheelMove;
+
+ if (startIndex < 0) startIndex = 0;
+ else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems;
+
+ endIndex = startIndex + visibleItems;
+ if (endIndex > count) endIndex = count;
+ }
+ }
+ else itemFocused = -1;
+
+ // Reset item rectangle y to [0]
+ itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
+
+ // Draw visible items
+ for (int i = 0; ((i < visibleItems) && (text != NULL)); i++)
+ {
+ GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK);
+
+ if (state == STATE_DISABLED)
+ {
+ if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)));
+
+ GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)));
+ }
+ else
+ {
+ if (((startIndex + i) == itemSelected) && (active != NULL))
+ {
+ // Draw item selected
+ GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)));
+ GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)));
+ }
+ else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: We want items focused, despite not returned!
+ {
+ // Draw item focused
+ GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)));
+ GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)));
+ }
+ else
+ {
+ // Draw item normal
+ GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)));
+ }
+ }
+
+ // Update item rectangle y position for next item
+ itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING));
+ }
+
+ if (useScrollBar)
+ {
+ Rectangle scrollBarBounds = {
+ bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
+ bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
+ bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH)
+ };
+
+ // Calculate percentage of visible items and apply same percentage to scrollbar
+ float percentVisible = (float)(endIndex - startIndex)/count;
+ float sliderSize = bounds.height*percentVisible;
+
+ int prevSliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); // Save default slider size
+ int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)sliderSize); // Change slider size
+ GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed
+
+ startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems);
+
+ GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, prevSliderSize); // Reset slider size to default
+ }
+ //--------------------------------------------------------------------
+
+ if (active != NULL) *active = itemSelected;
+ if (focus != NULL) *focus = itemFocused;
+ if (scrollIndex != NULL) *scrollIndex = startIndex;
+
+ return result;
+}
+
+// Color Panel control - Color (RGBA) variant.
+int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
+{
+ int result = 0;
+
+ Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f };
+ Vector3 hsv = ConvertRGBtoHSV(vcolor);
+ Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv.
+
+ GuiColorPanelHSV(bounds, text, &hsv);
+
+ // Check if the hsv was changed, only then change the color.
+ // This is required, because the Color->HSV->Color conversion has precision errors.
+ // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value.
+ // Otherwise GuiColorPanel would often modify it's color without user input.
+ // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check.
+ if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z)
+ {
+ Vector3 rgb = ConvertHSVtoRGB(hsv);
+
+ // NOTE: Vector3ToColor() only available on raylib 1.8.1
+ *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x),
+ (unsigned char)(255.0f*rgb.y),
+ (unsigned char)(255.0f*rgb.z),
+ color->a };
+ }
+ return result;
+}
+
+// Color Bar Alpha control
+// NOTE: Returns alpha value normalized [0..1]
+int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
+{
+ #if !defined(RAYGUI_COLORBARALPHA_CHECKED_SIZE)
+ #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+ Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ {
+ state = STATE_PRESSED;
+
+ *alpha = (mousePoint.x - bounds.x)/bounds.width;
+ if (*alpha <= 0.0f) *alpha = 0.0f;
+ if (*alpha >= 1.0f) *alpha = 1.0f;
+ }
+ }
+ else
+ {
+ guiControlExclusiveMode = false;
+ guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ }
+ }
+ else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ guiControlExclusiveMode = true;
+ guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+
+ *alpha = (mousePoint.x - bounds.x)/bounds.width;
+ if (*alpha <= 0.0f) *alpha = 0.0f;
+ if (*alpha >= 1.0f) *alpha = 1.0f;
+ //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2;
+ }
+ else state = STATE_FOCUSED;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+
+ // Draw alpha bar: checked background
+ if (state != STATE_DISABLED)
+ {
+ int checksX = (int)bounds.width/RAYGUI_COLORBARALPHA_CHECKED_SIZE;
+ int checksY = (int)bounds.height/RAYGUI_COLORBARALPHA_CHECKED_SIZE;
+
+ for (int x = 0; x < checksX; x++)
+ {
+ for (int y = 0; y < checksY; y++)
+ {
+ Rectangle check = { bounds.x + x*RAYGUI_COLORBARALPHA_CHECKED_SIZE, bounds.y + y*RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE };
+ GuiDrawRectangle(check, 0, BLANK, ((x + y)%2)? Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f) : Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f));
+ }
+ }
+
+ DrawRectangleGradientEx(bounds, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha));
+ }
+ else DrawRectangleGradientEx(bounds, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha));
+
+ GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK);
+
+ // Draw alpha bar: selector
+ GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Color Bar Hue control
+// Returns hue value normalized [0..1]
+// NOTE: Other similar bars (for reference):
+// Color GuiColorBarSat() [WHITE->color]
+// Color GuiColorBarValue() [BLACK->color], HSV/HSL
+// float GuiColorBarLuminance() [BLACK->WHITE]
+int GuiColorBarHue(Rectangle bounds, const char *text, float *hue)
+{
+ int result = 0;
+ GuiState state = guiState;
+ Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ {
+ state = STATE_PRESSED;
+
+ *hue = (mousePoint.y - bounds.y)*360/bounds.height;
+ if (*hue <= 0.0f) *hue = 0.0f;
+ if (*hue >= 359.0f) *hue = 359.0f;
+ }
+ }
+ else
+ {
+ guiControlExclusiveMode = false;
+ guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ }
+ }
+ else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ guiControlExclusiveMode = true;
+ guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+
+ *hue = (mousePoint.y - bounds.y)*360/bounds.height;
+ if (*hue <= 0.0f) *hue = 0.0f;
+ if (*hue >= 359.0f) *hue = 359.0f;
+
+ }
+ else state = STATE_FOCUSED;
+
+ /*if (IsKeyDown(KEY_UP))
+ {
+ hue -= 2.0f;
+ if (hue <= 0.0f) hue = 0.0f;
+ }
+ else if (IsKeyDown(KEY_DOWN))
+ {
+ hue += 2.0f;
+ if (hue >= 360.0f) hue = 360.0f;
+ }*/
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state != STATE_DISABLED)
+ {
+ // Draw hue bar:color bars
+ // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1);
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha));
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha));
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha));
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha));
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha));
+ DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha));
+ }
+ else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha));
+
+ GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK);
+
+ // Draw hue bar: selector
+ GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)));
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Color Picker control
+// NOTE: It's divided in multiple controls:
+// Color GuiColorPanel(Rectangle bounds, Color color)
+// float GuiColorBarAlpha(Rectangle bounds, float alpha)
+// float GuiColorBarHue(Rectangle bounds, float value)
+// NOTE: bounds define GuiColorPanel() size
+// NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead
+int GuiColorPicker(Rectangle bounds, const char *text, Color *color)
+{
+ int result = 0;
+
+ Color temp = { 200, 0, 0, 255 };
+ if (color == NULL) color = &temp;
+
+ GuiColorPanel(bounds, NULL, color);
+
+ Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height };
+ //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) };
+
+ // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used.
+ Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f });
+
+ GuiColorBarHue(boundsHue, NULL, &hsv.x);
+
+ //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f);
+ Vector3 rgb = ConvertHSVtoRGB(hsv);
+
+ *color = RAYGUI_CLITERAL(Color){ (unsigned char)roundf(rgb.x*255.0f), (unsigned char)roundf(rgb.y*255.0f), (unsigned char)roundf(rgb.z*255.0f), (*color).a };
+
+ return result;
+}
+
+// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering.
+// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB.
+// NOTE: It's divided in multiple controls:
+// int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
+// int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
+// float GuiColorBarHue(Rectangle bounds, float value)
+// NOTE: bounds define GuiColorPanelHSV() size
+int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
+{
+ int result = 0;
+
+ Vector3 tempHsv = { 0 };
+
+ if (colorHsv == NULL)
+ {
+ const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f };
+ tempHsv = ConvertRGBtoHSV(tempColor);
+ colorHsv = &tempHsv;
+ }
+
+ GuiColorPanelHSV(bounds, NULL, colorHsv);
+
+ const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height };
+
+ GuiColorBarHue(boundsHue, NULL, &colorHsv->x);
+
+ return result;
+}
+
+// Color Panel control - HSV variant
+int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
+{
+ int result = 0;
+ GuiState state = guiState;
+ Vector2 pickerSelector = { 0 };
+
+ const Color colWhite = { 255, 255, 255, 255 };
+ const Color colBlack = { 0, 0, 0, 255 };
+
+ pickerSelector.x = bounds.x + (float)colorHsv->y*bounds.width; // HSV: Saturation
+ pickerSelector.y = bounds.y + (1.0f - (float)colorHsv->z)*bounds.height; // HSV: Value
+
+ Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f };
+ Vector3 rgbHue = ConvertHSVtoRGB(maxHue);
+ Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x),
+ (unsigned char)(255.0f*rgbHue.y),
+ (unsigned char)(255.0f*rgbHue.z), 255 };
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ {
+ pickerSelector = mousePoint;
+
+ if (pickerSelector.x < bounds.x) pickerSelector.x = bounds.x;
+ if (pickerSelector.x > bounds.x + bounds.width) pickerSelector.x = bounds.x + bounds.width;
+ if (pickerSelector.y < bounds.y) pickerSelector.y = bounds.y;
+ if (pickerSelector.y > bounds.y + bounds.height) pickerSelector.y = bounds.y + bounds.height;
+
+ // Calculate color from picker
+ Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y };
+
+ colorPick.x /= (float)bounds.width; // Get normalized value on x
+ colorPick.y /= (float)bounds.height; // Get normalized value on y
+
+ colorHsv->y = colorPick.x;
+ colorHsv->z = 1.0f - colorPick.y;
+
+ }
+ }
+ else
+ {
+ guiControlExclusiveMode = false;
+ guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ }
+ }
+ else if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ guiControlExclusiveMode = true;
+ guiControlExclusiveRec = bounds;
+ pickerSelector = mousePoint;
+
+ // Calculate color from picker
+ Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y };
+
+ colorPick.x /= (float)bounds.width; // Get normalized value on x
+ colorPick.y /= (float)bounds.height; // Get normalized value on y
+
+ colorHsv->y = colorPick.x;
+ colorHsv->z = 1.0f - colorPick.y;
+ }
+ else state = STATE_FOCUSED;
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state != STATE_DISABLED)
+ {
+ DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha));
+ DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0));
+
+ // Draw color picker: selector
+ Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) };
+ GuiDrawRectangle(selector, 0, BLANK, colWhite);
+ }
+ else
+ {
+ DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha));
+ }
+
+ GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK);
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Message Box control
+int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons)
+{
+ #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT)
+ #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24
+ #endif
+ #if !defined(RAYGUI_MESSAGEBOX_BUTTON_PADDING)
+ #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12
+ #endif
+
+ int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button
+
+ int buttonCount = 0;
+ const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
+ Rectangle buttonBounds = { 0 };
+ buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
+ buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING;
+ buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount;
+ buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT;
+
+ //int textWidth = GetTextWidth(message) + 2;
+
+ Rectangle textBounds = { 0 };
+ textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
+ textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
+ textBounds.width = bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*2;
+ textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT;
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (GuiWindowBox(bounds, title)) result = 0;
+
+ int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+ GuiLabel(textBounds, message);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment);
+
+ prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+ for (int i = 0; i < buttonCount; i++)
+ {
+ if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1;
+ buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
+ }
+
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment);
+ //--------------------------------------------------------------------
+
+ return result;
+}
+
+// Text Input Box control, ask for text
+int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive)
+{
+ #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT)
+ #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24
+ #endif
+ #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_PADDING)
+ #define RAYGUI_TEXTINPUTBOX_BUTTON_PADDING 12
+ #endif
+ #if !defined(RAYGUI_TEXTINPUTBOX_HEIGHT)
+ #define RAYGUI_TEXTINPUTBOX_HEIGHT 26
+ #endif
+
+ // Used to enable text edit mode
+ // WARNING: No more than one GuiTextInputBox() should be open at the same time
+ static bool textEditMode = false;
+
+ int result = -1;
+
+ int buttonCount = 0;
+ const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL);
+ Rectangle buttonBounds = { 0 };
+ buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
+ buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
+ buttonBounds.width = (bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount;
+ buttonBounds.height = RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT;
+
+ int messageInputHeight = (int)bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - 2*RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
+
+ Rectangle textBounds = { 0 };
+ if (message != NULL)
+ {
+ int textSize = GetTextWidth(message) + 2;
+
+ textBounds.x = bounds.x + bounds.width/2 - textSize/2;
+ textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2;
+ textBounds.width = (float)textSize;
+ textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+ }
+
+ Rectangle textBoxBounds = { 0 };
+ textBoxBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
+ textBoxBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - RAYGUI_TEXTINPUTBOX_HEIGHT/2;
+ if (message == NULL) textBoxBounds.y = bounds.y + 24 + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING;
+ else textBoxBounds.y += (messageInputHeight/2 + messageInputHeight/4);
+ textBoxBounds.width = bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*2;
+ textBoxBounds.height = RAYGUI_TEXTINPUTBOX_HEIGHT;
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (GuiWindowBox(bounds, title)) result = 0;
+
+ // Draw message if available
+ if (message != NULL)
+ {
+ int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+ GuiLabel(textBounds, message);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment);
+ }
+
+ if (secretViewActive != NULL)
+ {
+ static char stars[] = "****************";
+ if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height },
+ ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode;
+
+ GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive);
+ }
+ else
+ {
+ if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode;
+ }
+
+ int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT);
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+ for (int i = 0; i < buttonCount; i++)
+ {
+ if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1;
+ buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING);
+ }
+
+ if (result >= 0) textEditMode = false;
+
+ GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment);
+ //--------------------------------------------------------------------
+
+ return result; // Result is the pressed button index
+}
+
+// Grid control
+// NOTE: Returns grid mouse-hover selected cell
+// About drawing lines at subpixel spacing, simple put, not easy solution:
+// https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster
+int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell)
+{
+ // Grid lines alpha amount
+ #if !defined(RAYGUI_GRID_ALPHA)
+ #define RAYGUI_GRID_ALPHA 0.15f
+ #endif
+
+ int result = 0;
+ GuiState state = guiState;
+
+ Vector2 mousePoint = GetMousePosition();
+ Vector2 currentMouseCell = { -1, -1 };
+
+ float spaceWidth = spacing/(float)subdivs;
+ int linesV = (int)(bounds.width/spaceWidth) + 1;
+ int linesH = (int)(bounds.height/spaceWidth) + 1;
+
+ int color = GuiGetStyle(DEFAULT, LINE_COLOR);
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ {
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ // NOTE: Cell values must be the upper left of the cell the mouse is in
+ currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing);
+ currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing);
+ }
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ if (state == STATE_DISABLED) color = GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED);
+
+ if (subdivs > 0)
+ {
+ // Draw vertical grid lines
+ for (int i = 0; i < linesV; i++)
+ {
+ Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height + 1 };
+ GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA));
+ }
+
+ // Draw horizontal grid lines
+ for (int i = 0; i < linesH; i++)
+ {
+ Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width + 1, 1 };
+ GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA));
+ }
+ }
+
+ if (mouseCell != NULL) *mouseCell = currentMouseCell;
+ return result;
+}
+
+//----------------------------------------------------------------------------------
+// Tooltip management functions
+// NOTE: Tooltips requires some global variables: tooltipPtr
+//----------------------------------------------------------------------------------
+// Enable gui tooltips (global state)
+void GuiEnableTooltip(void) { guiTooltip = true; }
+
+// Disable gui tooltips (global state)
+void GuiDisableTooltip(void) { guiTooltip = false; }
+
+// Set tooltip string
+void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; }
+
+//----------------------------------------------------------------------------------
+// Styles loading functions
+//----------------------------------------------------------------------------------
+
+// Load raygui style file (.rgs)
+// NOTE: By default a binary file is expected, that file could contain a custom font,
+// in that case, custom font image atlas is GRAY+ALPHA and pixel data can be compressed (DEFLATE)
+void GuiLoadStyle(const char *fileName)
+{
+ #define MAX_LINE_BUFFER_SIZE 256
+
+ bool tryBinary = false;
+ if (!guiStyleLoaded) GuiLoadStyleDefault();
+
+ // Try reading the files as text file first
+ FILE *rgsFile = fopen(fileName, "rt");
+
+ if (rgsFile != NULL)
+ {
+ char buffer[MAX_LINE_BUFFER_SIZE] = { 0 };
+ fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile);
+
+ if (buffer[0] == '#')
+ {
+ int controlId = 0;
+ int propertyId = 0;
+ unsigned int propertyValue = 0;
+
+ while (!feof(rgsFile))
+ {
+ switch (buffer[0])
+ {
+ case 'p':
+ {
+ // Style property: p
+
+ sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue);
+ GuiSetStyle(controlId, propertyId, (int)propertyValue);
+
+ } break;
+ case 'f':
+ {
+ // Style font: f
+
+ int fontSize = 0;
+ char charmapFileName[256] = { 0 };
+ char fontFileName[256] = { 0 };
+ sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName);
+
+ Font font = { 0 };
+ int *codepoints = NULL;
+ int codepointCount = 0;
+
+ if (charmapFileName[0] != '0')
+ {
+ // Load text data from file
+ // NOTE: Expected an UTF-8 array of codepoints, no separation
+ char *textData = LoadFileText(TextFormat("%s/%s", GetDirectoryPath(fileName), charmapFileName));
+ codepoints = LoadCodepoints(textData, &codepointCount);
+ UnloadFileText(textData);
+ }
+
+ if (fontFileName[0] != '\0')
+ {
+ // In case a font is already loaded and it is not default internal font, unload it
+ if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
+
+ if (codepointCount > 0) font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, codepoints, codepointCount);
+ else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); // Default to 95 standard codepoints
+ }
+
+ // If font texture not properly loaded, revert to default font and size/spacing
+ if (font.texture.id == 0)
+ {
+ font = GetFontDefault();
+ GuiSetStyle(DEFAULT, TEXT_SIZE, 10);
+ GuiSetStyle(DEFAULT, TEXT_SPACING, 1);
+ }
+
+ UnloadCodepoints(codepoints);
+
+ if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font);
+
+ } break;
+ default: break;
+ }
+
+ fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile);
+ }
+ }
+ else tryBinary = true;
+
+ fclose(rgsFile);
+ }
+
+ if (tryBinary)
+ {
+ rgsFile = fopen(fileName, "rb");
+
+ if (rgsFile != NULL)
+ {
+ fseek(rgsFile, 0, SEEK_END);
+ int fileDataSize = ftell(rgsFile);
+ fseek(rgsFile, 0, SEEK_SET);
+
+ if (fileDataSize > 0)
+ {
+ unsigned char *fileData = (unsigned char *)RAYGUI_MALLOC(fileDataSize*sizeof(unsigned char));
+ fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile);
+
+ GuiLoadStyleFromMemory(fileData, fileDataSize);
+
+ RAYGUI_FREE(fileData);
+ }
+
+ fclose(rgsFile);
+ }
+ }
+}
+
+// Load style default over global style
+void GuiLoadStyleDefault(void)
+{
+ // We set this variable first to avoid cyclic function calls
+ // when calling GuiSetStyle() and GuiGetStyle()
+ guiStyleLoaded = true;
+
+ // Initialize default LIGHT style property values
+ // WARNING: Default value are applied to all controls on set but
+ // they can be overwritten later on for every custom control
+ GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff);
+ GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff);
+ GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff);
+ GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff);
+ GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff);
+ GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff);
+ GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff);
+ GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff);
+ GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff);
+ GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff);
+ GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff);
+ GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff);
+ GuiSetStyle(DEFAULT, BORDER_WIDTH, 1);
+ GuiSetStyle(DEFAULT, TEXT_PADDING, 0);
+ GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+
+ // Initialize default extended property values
+ // NOTE: By default, extended property values are initialized to 0
+ GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls
+ GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls
+ GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property
+ GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property
+ GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 15); // DEFAULT, 15 pixels between lines
+ GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds
+
+ // Initialize control-specific property values
+ // NOTE: Those properties are in default list but require specific values by control type
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+ GuiSetStyle(BUTTON, BORDER_WIDTH, 2);
+ GuiSetStyle(SLIDER, TEXT_PADDING, 4);
+ GuiSetStyle(PROGRESSBAR, TEXT_PADDING, 4);
+ GuiSetStyle(CHECKBOX, TEXT_PADDING, 4);
+ GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT);
+ GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0);
+ GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+ GuiSetStyle(TEXTBOX, TEXT_PADDING, 4);
+ GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+ GuiSetStyle(VALUEBOX, TEXT_PADDING, 0);
+ GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+ GuiSetStyle(SPINNER, TEXT_PADDING, 0);
+ GuiSetStyle(SPINNER, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+ GuiSetStyle(STATUSBAR, TEXT_PADDING, 8);
+ GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
+
+ // Initialize extended property values
+ // NOTE: By default, extended property values are initialized to 0
+ GuiSetStyle(TOGGLE, GROUP_PADDING, 2);
+ GuiSetStyle(SLIDER, SLIDER_WIDTH, 16);
+ GuiSetStyle(SLIDER, SLIDER_PADDING, 1);
+ GuiSetStyle(PROGRESSBAR, PROGRESS_PADDING, 1);
+ GuiSetStyle(CHECKBOX, CHECK_PADDING, 1);
+ GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 32);
+ GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2);
+ GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16);
+ GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2);
+ GuiSetStyle(SPINNER, SPIN_BUTTON_WIDTH, 24);
+ GuiSetStyle(SPINNER, SPIN_BUTTON_SPACING, 2);
+ GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0);
+ GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0);
+ GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6);
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING, 0);
+ GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, 16);
+ GuiSetStyle(SCROLLBAR, SCROLL_PADDING, 0);
+ GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12);
+ GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28);
+ GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2);
+ GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12);
+ GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE);
+ GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8);
+ GuiSetStyle(COLORPICKER, HUEBAR_WIDTH, 16);
+ GuiSetStyle(COLORPICKER, HUEBAR_PADDING, 8);
+ GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT, 8);
+ GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW, 2);
+
+ if (guiFont.texture.id != GetFontDefault().texture.id)
+ {
+ // Unload previous font texture
+ UnloadTexture(guiFont.texture);
+ RL_FREE(guiFont.recs);
+ RL_FREE(guiFont.glyphs);
+ guiFont.recs = NULL;
+ guiFont.glyphs = NULL;
+
+ // Setup default raylib font
+ guiFont = GetFontDefault();
+
+ // NOTE: Default raylib font character 95 is a white square
+ Rectangle whiteChar = guiFont.recs[95];
+
+ // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
+ SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 });
+ }
+}
+
+// Get text with icon id prepended
+// NOTE: Useful to add icons by name id (enum) instead of
+// a number that can change between ricon versions
+const char *GuiIconText(int iconId, const char *text)
+{
+#if defined(RAYGUI_NO_ICONS)
+ return NULL;
+#else
+ static char buffer[1024] = { 0 };
+ static char iconBuffer[16] = { 0 };
+
+ if (text != NULL)
+ {
+ memset(buffer, 0, 1024);
+ sprintf(buffer, "#%03i#", iconId);
+
+ for (int i = 5; i < 1024; i++)
+ {
+ buffer[i] = text[i - 5];
+ if (text[i - 5] == '\0') break;
+ }
+
+ return buffer;
+ }
+ else
+ {
+ sprintf(iconBuffer, "#%03i#", iconId);
+
+ return iconBuffer;
+ }
+#endif
+}
+
+#if !defined(RAYGUI_NO_ICONS)
+// Get full icons data pointer
+unsigned int *GuiGetIcons(void) { return guiIconsPtr; }
+
+// Load raygui icons file (.rgi)
+// NOTE: In case nameIds are required, they can be requested with loadIconsName,
+// they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH],
+// WARNING: guiIconsName[]][] memory should be manually freed!
+char **GuiLoadIcons(const char *fileName, bool loadIconsName)
+{
+ // Style File Structure (.rgi)
+ // ------------------------------------------------------
+ // Offset | Size | Type | Description
+ // ------------------------------------------------------
+ // 0 | 4 | char | Signature: "rGI "
+ // 4 | 2 | short | Version: 100
+ // 6 | 2 | short | reserved
+
+ // 8 | 2 | short | Num icons (N)
+ // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S)
+
+ // Icons name id (32 bytes per name id)
+ // foreach (icon)
+ // {
+ // 12+32*i | 32 | char | Icon NameId
+ // }
+
+ // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size)
+ // S*S pixels/32bit per unsigned int = K unsigned int per icon
+ // foreach (icon)
+ // {
+ // ... | K | unsigned int | Icon Data
+ // }
+
+ FILE *rgiFile = fopen(fileName, "rb");
+
+ char **guiIconsName = NULL;
+
+ if (rgiFile != NULL)
+ {
+ char signature[5] = { 0 };
+ short version = 0;
+ short reserved = 0;
+ short iconCount = 0;
+ short iconSize = 0;
+
+ fread(signature, 1, 4, rgiFile);
+ fread(&version, sizeof(short), 1, rgiFile);
+ fread(&reserved, sizeof(short), 1, rgiFile);
+ fread(&iconCount, sizeof(short), 1, rgiFile);
+ fread(&iconSize, sizeof(short), 1, rgiFile);
+
+ if ((signature[0] == 'r') &&
+ (signature[1] == 'G') &&
+ (signature[2] == 'I') &&
+ (signature[3] == ' '))
+ {
+ if (loadIconsName)
+ {
+ guiIconsName = (char **)RAYGUI_MALLOC(iconCount*sizeof(char **));
+ for (int i = 0; i < iconCount; i++)
+ {
+ guiIconsName[i] = (char *)RAYGUI_MALLOC(RAYGUI_ICON_MAX_NAME_LENGTH);
+ fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile);
+ }
+ }
+ else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR);
+
+ // Read icons data directly over internal icons array
+ fread(guiIconsPtr, sizeof(unsigned int), iconCount*(iconSize*iconSize/32), rgiFile);
+ }
+
+ fclose(rgiFile);
+ }
+
+ return guiIconsName;
+}
+
+// Draw selected icon using rectangles pixel-by-pixel
+void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color)
+{
+ #define BIT_CHECK(a,b) ((a) & (1u<<(b)))
+
+ for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++)
+ {
+ for (int k = 0; k < 32; k++)
+ {
+ if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k))
+ {
+ #if !defined(RAYGUI_STANDALONE)
+ GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color);
+ #endif
+ }
+
+ if ((k == 15) || (k == 31)) y++;
+ }
+ }
+}
+
+// Set icon drawing size
+void GuiSetIconScale(int scale)
+{
+ if (scale >= 1) guiIconScale = scale;
+}
+
+#endif // !RAYGUI_NO_ICONS
+
+//----------------------------------------------------------------------------------
+// Module Internal Functions Definition
+//----------------------------------------------------------------------------------
+
+// Load style from memory
+// WARNING: Binary files only
+static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize)
+{
+ unsigned char *fileDataPtr = (unsigned char *)fileData;
+
+ char signature[5] = { 0 };
+ short version = 0;
+ short reserved = 0;
+ int propertyCount = 0;
+
+ memcpy(signature, fileDataPtr, 4);
+ memcpy(&version, fileDataPtr + 4, sizeof(short));
+ memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short));
+ memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int));
+ fileDataPtr += 12;
+
+ if ((signature[0] == 'r') &&
+ (signature[1] == 'G') &&
+ (signature[2] == 'S') &&
+ (signature[3] == ' '))
+ {
+ short controlId = 0;
+ short propertyId = 0;
+ unsigned int propertyValue = 0;
+
+ for (int i = 0; i < propertyCount; i++)
+ {
+ memcpy(&controlId, fileDataPtr, sizeof(short));
+ memcpy(&propertyId, fileDataPtr + 2, sizeof(short));
+ memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int));
+ fileDataPtr += 8;
+
+ if (controlId == 0) // DEFAULT control
+ {
+ // If a DEFAULT property is loaded, it is propagated to all controls
+ // NOTE: All DEFAULT properties should be defined first in the file
+ GuiSetStyle(0, (int)propertyId, propertyValue);
+
+ if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue);
+ }
+ else GuiSetStyle((int)controlId, (int)propertyId, propertyValue);
+ }
+
+ // Font loading is highly dependant on raylib API to load font data and image
+
+#if !defined(RAYGUI_STANDALONE)
+ // Load custom font if available
+ int fontDataSize = 0;
+ memcpy(&fontDataSize, fileDataPtr, sizeof(int));
+ fileDataPtr += 4;
+
+ if (fontDataSize > 0)
+ {
+ Font font = { 0 };
+ int fontType = 0; // 0-Normal, 1-SDF
+
+ memcpy(&font.baseSize, fileDataPtr, sizeof(int));
+ memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int));
+ memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int));
+ fileDataPtr += 12;
+
+ // Load font white rectangle
+ Rectangle fontWhiteRec = { 0 };
+ memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle));
+ fileDataPtr += 16;
+
+ // Load font image parameters
+ int fontImageUncompSize = 0;
+ int fontImageCompSize = 0;
+ memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int));
+ memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int));
+ fileDataPtr += 8;
+
+ Image imFont = { 0 };
+ imFont.mipmaps = 1;
+ memcpy(&imFont.width, fileDataPtr, sizeof(int));
+ memcpy(&imFont.height, fileDataPtr + 4, sizeof(int));
+ memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int));
+ fileDataPtr += 12;
+
+ if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize))
+ {
+ // Compressed font atlas image data (DEFLATE), it requires DecompressData()
+ int dataUncompSize = 0;
+ unsigned char *compData = (unsigned char *)RAYGUI_MALLOC(fontImageCompSize);
+ memcpy(compData, fileDataPtr, fontImageCompSize);
+ fileDataPtr += fontImageCompSize;
+
+ imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize);
+
+ // Security check, dataUncompSize must match the provided fontImageUncompSize
+ if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted");
+
+ RAYGUI_FREE(compData);
+ }
+ else
+ {
+ // Font atlas image data is not compressed
+ imFont.data = (unsigned char *)RAYGUI_MALLOC(fontImageUncompSize);
+ memcpy(imFont.data, fileDataPtr, fontImageUncompSize);
+ fileDataPtr += fontImageUncompSize;
+ }
+
+ if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture);
+ font.texture = LoadTextureFromImage(imFont);
+
+ RAYGUI_FREE(imFont.data);
+
+ // Validate font atlas texture was loaded correctly
+ if (font.texture.id != 0)
+ {
+ // Load font recs data
+ int recsDataSize = font.glyphCount*sizeof(Rectangle);
+ int recsDataCompressedSize = 0;
+
+ // WARNING: Version 400 adds the compression size parameter
+ if (version >= 400)
+ {
+ // RGS files version 400 support compressed recs data
+ memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int));
+ fileDataPtr += sizeof(int);
+ }
+
+ if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize))
+ {
+ // Recs data is compressed, uncompress it
+ unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_MALLOC(recsDataCompressedSize);
+
+ memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize);
+ fileDataPtr += recsDataCompressedSize;
+
+ int recsDataUncompSize = 0;
+ font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize);
+
+ // Security check, data uncompressed size must match the expected original data size
+ if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted");
+
+ RAYGUI_FREE(recsDataCompressed);
+ }
+ else
+ {
+ // Recs data is uncompressed
+ font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle));
+ for (int i = 0; i < font.glyphCount; i++)
+ {
+ memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle));
+ fileDataPtr += sizeof(Rectangle);
+ }
+ }
+
+ // Load font glyphs info data
+ int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph
+ int glyphsDataCompressedSize = 0;
+
+ // WARNING: Version 400 adds the compression size parameter
+ if (version >= 400)
+ {
+ // RGS files version 400 support compressed glyphs data
+ memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int));
+ fileDataPtr += sizeof(int);
+ }
+
+ // Allocate required glyphs space to fill with data
+ font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo));
+
+ if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize))
+ {
+ // Glyphs data is compressed, uncompress it
+ unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_MALLOC(glyphsDataCompressedSize);
+
+ memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize);
+ fileDataPtr += glyphsDataCompressedSize;
+
+ int glyphsDataUncompSize = 0;
+ unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize);
+
+ // Security check, data uncompressed size must match the expected original data size
+ if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted");
+
+ unsigned char *glyphsDataUncompPtr = glyphsDataUncomp;
+
+ for (int i = 0; i < font.glyphCount; i++)
+ {
+ memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int));
+ memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int));
+ memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int));
+ memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int));
+ glyphsDataUncompPtr += 16;
+ }
+
+ RAYGUI_FREE(glypsDataCompressed);
+ RAYGUI_FREE(glyphsDataUncomp);
+ }
+ else
+ {
+ // Glyphs data is uncompressed
+ for (int i = 0; i < font.glyphCount; i++)
+ {
+ memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int));
+ memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int));
+ memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int));
+ memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int));
+ fileDataPtr += 16;
+ }
+ }
+ }
+ else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture
+
+ GuiSetFont(font);
+
+ // Set font texture source rectangle to be used as white texture to draw shapes
+ // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call
+ if ((fontWhiteRec.x > 0) &&
+ (fontWhiteRec.y > 0) &&
+ (fontWhiteRec.width > 0) &&
+ (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec);
+ }
+#endif
+ }
+}
+
+// Gui get text width considering icon
+static int GetTextWidth(const char *text)
+{
+ #if !defined(ICON_TEXT_PADDING)
+ #define ICON_TEXT_PADDING 4
+ #endif
+
+ Vector2 textSize = { 0 };
+ int textIconOffset = 0;
+
+ if ((text != NULL) && (text[0] != '\0'))
+ {
+ if (text[0] == '#')
+ {
+ for (int i = 1; (i < 5) && (text[i] != '\0'); i++)
+ {
+ if (text[i] == '#')
+ {
+ textIconOffset = i;
+ break;
+ }
+ }
+ }
+
+ text += textIconOffset;
+
+ // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly
+ float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE);
+
+ // Custom MeasureText() implementation
+ if ((guiFont.texture.id > 0) && (text != NULL))
+ {
+ // Get size in bytes of text, considering end of line and line break
+ int size = 0;
+ for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++)
+ {
+ if ((text[i] != '\0') && (text[i] != '\n')) size++;
+ else break;
+ }
+
+ float scaleFactor = fontSize/(float)guiFont.baseSize;
+ textSize.y = (float)guiFont.baseSize*scaleFactor;
+ float glyphWidth = 0.0f;
+
+ for (int i = 0, codepointSize = 0; i < size; i += codepointSize)
+ {
+ int codepoint = GetCodepointNext(&text[i], &codepointSize);
+ int codepointIndex = GetGlyphIndex(guiFont, codepoint);
+
+ if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor);
+ else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor);
+
+ textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ }
+ }
+
+ if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING);
+ }
+
+ return (int)textSize.x;
+}
+
+// Get text bounds considering control bounds
+static Rectangle GetTextBounds(int control, Rectangle bounds)
+{
+ Rectangle textBounds = bounds;
+
+ textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH);
+ textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, TEXT_PADDING);
+ textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING);
+ textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); // NOTE: Text is processed line per line!
+
+ // Depending on control, TEXT_PADDING and TEXT_ALIGNMENT properties could affect the text-bounds
+ switch (control)
+ {
+ case COMBOBOX:
+ case DROPDOWNBOX:
+ case LISTVIEW:
+ // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW
+ case SLIDER:
+ case CHECKBOX:
+ case VALUEBOX:
+ case SPINNER:
+ // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER
+ default:
+ {
+ // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText()
+ if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING);
+ else textBounds.x += GuiGetStyle(control, TEXT_PADDING);
+ }
+ break;
+ }
+
+ return textBounds;
+}
+
+// Get text icon if provided and move text cursor
+// NOTE: We support up to 999 values for iconId
+static const char *GetTextIcon(const char *text, int *iconId)
+{
+#if !defined(RAYGUI_NO_ICONS)
+ *iconId = -1;
+ if (text[0] == '#') // Maybe we have an icon!
+ {
+ char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0'
+
+ int pos = 1;
+ while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9'))
+ {
+ iconValue[pos - 1] = text[pos];
+ pos++;
+ }
+
+ if (text[pos] == '#')
+ {
+ *iconId = TextToInteger(iconValue);
+
+ // Move text pointer after icon
+ // WARNING: If only icon provided, it could point to EOL character: '\0'
+ if (*iconId >= 0) text += (pos + 1);
+ }
+ }
+#endif
+
+ return text;
+}
+
+// Get text divided into lines (by line-breaks '\n')
+const char **GetTextLines(const char *text, int *count)
+{
+ #define RAYGUI_MAX_TEXT_LINES 128
+
+ static const char *lines[RAYGUI_MAX_TEXT_LINES] = { 0 };
+ for (int i = 0; i < RAYGUI_MAX_TEXT_LINES; i++) lines[i] = NULL; // Init NULL pointers to substrings
+
+ int textSize = (int)strlen(text);
+
+ lines[0] = text;
+ int len = 0;
+ *count = 1;
+ //int lineSize = 0; // Stores current line size, not returned
+
+ for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++)
+ {
+ if (text[i] == '\n')
+ {
+ //lineSize = len;
+ k++;
+ lines[k] = &text[i + 1]; // WARNING: next value is valid?
+ len = 0;
+ *count += 1;
+ }
+ else len++;
+ }
+
+ //lines[*count - 1].size = len;
+
+ return lines;
+}
+
+// Get text width to next space for provided string
+static float GetNextSpaceWidth(const char *text, int *nextSpaceIndex)
+{
+ float width = 0;
+ int codepointByteCount = 0;
+ int codepoint = 0;
+ int index = 0;
+ float glyphWidth = 0;
+ float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize;
+
+ for (int i = 0; text[i] != '\0'; i++)
+ {
+ if (text[i] != ' ')
+ {
+ codepoint = GetCodepoint(&text[i], &codepointByteCount);
+ index = GetGlyphIndex(guiFont, codepoint);
+ glyphWidth = (guiFont.glyphs[index].advanceX == 0)? guiFont.recs[index].width*scaleFactor : guiFont.glyphs[index].advanceX*scaleFactor;
+ width += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ }
+ else
+ {
+ *nextSpaceIndex = i;
+ break;
+ }
+ }
+
+ return width;
+}
+
+// Gui draw text using default font
+static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint)
+{
+ #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect
+
+ #if !defined(ICON_TEXT_PADDING)
+ #define ICON_TEXT_PADDING 4
+ #endif
+
+ if ((text == NULL) || (text[0] == '\0')) return; // Security check
+
+ // PROCEDURE:
+ // - Text is processed line per line
+ // - For every line, horizontal alignment is defined
+ // - For all text, vertical alignment is defined (multiline text only)
+ // - For every line, wordwrap mode is checked (useful for GuitextBox(), read-only)
+
+ // Get text lines (using '\n' as delimiter) to be processed individually
+ // WARNING: We can't use GuiTextSplit() function because it can be already used
+ // before the GuiDrawText() call and its buffer is static, it would be overriden :(
+ int lineCount = 0;
+ const char **lines = GetTextLines(text, &lineCount);
+
+ // Text style variables
+ //int alignment = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT);
+ int alignmentVertical = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL);
+ int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); // Wrap-mode only available in read-only mode, no for text editing
+
+ // TODO: WARNING: This totalHeight is not valid for vertical alignment in case of word-wrap
+ float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_SIZE)/2);
+ float posOffsetY = 0.0f;
+
+ for (int i = 0; i < lineCount; i++)
+ {
+ int iconId = 0;
+ lines[i] = GetTextIcon(lines[i], &iconId); // Check text for icon and move cursor
+
+ // Get text position depending on alignment and iconId
+ //---------------------------------------------------------------------------------
+ Vector2 textBoundsPosition = { textBounds.x, textBounds.y };
+ float textBoundsWidthOffset = 0.0f;
+
+ // NOTE: We get text size after icon has been processed
+ // WARNING: GetTextWidth() also processes text icon to get width! -> Really needed?
+ int textSizeX = GetTextWidth(lines[i]);
+
+ // If text requires an icon, add size to measure
+ if (iconId >= 0)
+ {
+ textSizeX += RAYGUI_ICON_SIZE*guiIconScale;
+
+ // WARNING: If only icon provided, text could be pointing to EOF character: '\0'
+#if !defined(RAYGUI_NO_ICONS)
+ if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING;
+#endif
+ }
+
+ // Check guiTextAlign global variables
+ switch (alignment)
+ {
+ case TEXT_ALIGN_LEFT: textBoundsPosition.x = textBounds.x; break;
+ case TEXT_ALIGN_CENTER: textBoundsPosition.x = textBounds.x + textBounds.width/2 - textSizeX/2; break;
+ case TEXT_ALIGN_RIGHT: textBoundsPosition.x = textBounds.x + textBounds.width - textSizeX; break;
+ default: break;
+ }
+
+ if (textSizeX > textBounds.width && (lines[i] != NULL) && (lines[i][0] != '\0')) textBoundsPosition.x = textBounds.x;
+
+ switch (alignmentVertical)
+ {
+ // Only valid in case of wordWrap = 0;
+ case TEXT_ALIGN_TOP: textBoundsPosition.y = textBounds.y + posOffsetY; break;
+ case TEXT_ALIGN_MIDDLE: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break;
+ case TEXT_ALIGN_BOTTOM: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height - totalHeight + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break;
+ default: break;
+ }
+
+ // NOTE: Make sure we get pixel-perfect coordinates,
+ // In case of decimals we got weird text positioning
+ textBoundsPosition.x = (float)((int)textBoundsPosition.x);
+ textBoundsPosition.y = (float)((int)textBoundsPosition.y);
+ //---------------------------------------------------------------------------------
+
+ // Draw text (with icon if available)
+ //---------------------------------------------------------------------------------
+#if !defined(RAYGUI_NO_ICONS)
+ if (iconId >= 0)
+ {
+ // NOTE: We consider icon height, probably different than text size
+ GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint);
+ textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
+ textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
+ }
+#endif
+ // Get size in bytes of text,
+ // considering end of line and line break
+ int lineSize = 0;
+ for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ }
+ float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize;
+
+ int lastSpaceIndex = 0;
+ bool tempWrapCharMode = false;
+
+ int textOffsetY = 0;
+ float textOffsetX = 0.0f;
+ float glyphWidth = 0;
+
+ int ellipsisWidth = GetTextWidth("...");
+ bool textOverflow = false;
+ for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize)
+ {
+ int codepoint = GetCodepointNext(&lines[i][c], &codepointSize);
+ int index = GetGlyphIndex(guiFont, codepoint);
+
+ // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
+ // but we need to draw all of the bad bytes using the '?' symbol moving one byte
+ if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size
+
+ // Get glyph width to check if it goes out of bounds
+ if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor);
+ else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor;
+
+ // Wrap mode text measuring, to validate if
+ // it can be drawn or a new line is required
+ if (wrapMode == TEXT_WRAP_CHAR)
+ {
+ // Jump to next line if current character reach end of the box limits
+ if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset)
+ {
+ textOffsetX = 0.0f;
+ textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
+
+ if (tempWrapCharMode) // Wrap at char level when too long words
+ {
+ wrapMode = TEXT_WRAP_WORD;
+ tempWrapCharMode = false;
+ }
+ }
+ }
+ else if (wrapMode == TEXT_WRAP_WORD)
+ {
+ if (codepoint == 32) lastSpaceIndex = c;
+
+ // Get width to next space in line
+ int nextSpaceIndex = 0;
+ float nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex);
+
+ int nextSpaceIndex2 = 0;
+ float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2);
+
+ if (nextWordSize > textBounds.width - textBoundsWidthOffset)
+ {
+ // Considering the case the next word is longer than bounds
+ tempWrapCharMode = true;
+ wrapMode = TEXT_WRAP_CHAR;
+ }
+ else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset)
+ {
+ textOffsetX = 0.0f;
+ textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
+ }
+ }
+
+ if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint
+ else
+ {
+ // TODO: There are multiple types of spaces in Unicode,
+ // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html
+ if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph
+ {
+ if (wrapMode == TEXT_WRAP_NONE)
+ {
+ // Draw only required text glyphs fitting the textBounds.width
+ if (textSizeX > textBounds.width)
+ {
+ if (textOffsetX <= (textBounds.width - glyphWidth - textBoundsWidthOffset - ellipsisWidth))
+ {
+ DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
+ }
+ else if (!textOverflow)
+ {
+ textOverflow = true;
+
+ for (int j = 0; j < ellipsisWidth; j += ellipsisWidth/3)
+ {
+ DrawTextCodepoint(guiFont, '.', RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX + j, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
+ }
+ }
+ }
+ else
+ {
+ DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
+ }
+ }
+ else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD))
+ {
+ // Draw only glyphs inside the bounds
+ if ((textBoundsPosition.y + textOffsetY) <= (textBounds.y + textBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE)))
+ {
+ DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
+ }
+ }
+ }
+
+ if (guiFont.glyphs[index].advanceX == 0) textOffsetX += ((float)guiFont.recs[index].width*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ else textOffsetX += ((float)guiFont.glyphs[index].advanceX*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+ }
+ }
+
+ if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
+ else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING));
+ //---------------------------------------------------------------------------------
+ }
+
+#if defined(RAYGUI_DEBUG_TEXT_BOUNDS)
+ GuiDrawRectangle(textBounds, 0, WHITE, Fade(BLUE, 0.4f));
+#endif
+}
+
+// Gui draw rectangle using default raygui plain style with borders
+static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color)
+{
+ if (color.a > 0)
+ {
+ // Draw rectangle filled with color
+ DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, GuiFade(color, guiAlpha));
+ }
+
+ if (borderWidth > 0)
+ {
+ // Draw rectangle border lines with color
+ DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha));
+ DrawRectangle((int)rec.x, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha));
+ DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha));
+ DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha));
+ }
+
+#if defined(RAYGUI_DEBUG_RECS_BOUNDS)
+ DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, Fade(RED, 0.4f));
+#endif
+}
+
+// Draw tooltip using control bounds
+static void GuiTooltip(Rectangle controlRec)
+{
+ if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode)
+ {
+ Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
+
+ if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width);
+
+ GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, NULL);
+
+ int textPadding = GuiGetStyle(LABEL, TEXT_PADDING);
+ int textAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT);
+ GuiSetStyle(LABEL, TEXT_PADDING, 0);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER);
+ GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.f }, guiTooltipPtr);
+ GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment);
+ GuiSetStyle(LABEL, TEXT_PADDING, textPadding);
+ }
+}
+
+// Split controls text into multiple strings
+// Also check for multiple columns (required by GuiToggleGroup())
+static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow)
+{
+ // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
+ // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
+ // all used memory is static... it has some limitations:
+ // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS
+ // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE
+ // NOTE: Those definitions could be externally provided if required
+
+ // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user
+ // textRow is an externally provided array of integers that stores row number for every splitted string
+
+ #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS)
+ #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128
+ #endif
+ #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE)
+ #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024
+ #endif
+
+ static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data)
+ static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added)
+ memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE);
+
+ result[0] = buffer;
+ int counter = 1;
+
+ if (textRow != NULL) textRow[0] = 0;
+
+ // Count how many substrings we have on text and point to every one
+ for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++)
+ {
+ buffer[i] = text[i];
+ if (buffer[i] == '\0') break;
+ else if ((buffer[i] == delimiter) || (buffer[i] == '\n'))
+ {
+ result[counter] = buffer + i + 1;
+
+ if (textRow != NULL)
+ {
+ if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1;
+ else textRow[counter] = textRow[counter - 1];
+ }
+
+ buffer[i] = '\0'; // Set an end of string at this point
+
+ counter++;
+ if (counter > RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
+ }
+ }
+
+ *count = counter;
+
+ return result;
+}
+
+// Convert color data from RGB to HSV
+// NOTE: Color data should be passed normalized
+static Vector3 ConvertRGBtoHSV(Vector3 rgb)
+{
+ Vector3 hsv = { 0 };
+ float min = 0.0f;
+ float max = 0.0f;
+ float delta = 0.0f;
+
+ min = (rgb.x < rgb.y)? rgb.x : rgb.y;
+ min = (min < rgb.z)? min : rgb.z;
+
+ max = (rgb.x > rgb.y)? rgb.x : rgb.y;
+ max = (max > rgb.z)? max : rgb.z;
+
+ hsv.z = max; // Value
+ delta = max - min;
+
+ if (delta < 0.00001f)
+ {
+ hsv.y = 0.0f;
+ hsv.x = 0.0f; // Undefined, maybe NAN?
+ return hsv;
+ }
+
+ if (max > 0.0f)
+ {
+ // NOTE: If max is 0, this divide would cause a crash
+ hsv.y = (delta/max); // Saturation
+ }
+ else
+ {
+ // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined
+ hsv.y = 0.0f;
+ hsv.x = 0.0f; // Undefined, maybe NAN?
+ return hsv;
+ }
+
+ // NOTE: Comparing float values could not work properly
+ if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta
+ else
+ {
+ if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow
+ else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan
+ }
+
+ hsv.x *= 60.0f; // Convert to degrees
+
+ if (hsv.x < 0.0f) hsv.x += 360.0f;
+
+ return hsv;
+}
+
+// Convert color data from HSV to RGB
+// NOTE: Color data should be passed normalized
+static Vector3 ConvertHSVtoRGB(Vector3 hsv)
+{
+ Vector3 rgb = { 0 };
+ float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f;
+ long i = 0;
+
+ // NOTE: Comparing float values could not work properly
+ if (hsv.y <= 0.0f)
+ {
+ rgb.x = hsv.z;
+ rgb.y = hsv.z;
+ rgb.z = hsv.z;
+ return rgb;
+ }
+
+ hh = hsv.x;
+ if (hh >= 360.0f) hh = 0.0f;
+ hh /= 60.0f;
+
+ i = (long)hh;
+ ff = hh - i;
+ p = hsv.z*(1.0f - hsv.y);
+ q = hsv.z*(1.0f - (hsv.y*ff));
+ t = hsv.z*(1.0f - (hsv.y*(1.0f - ff)));
+
+ switch (i)
+ {
+ case 0:
+ {
+ rgb.x = hsv.z;
+ rgb.y = t;
+ rgb.z = p;
+ } break;
+ case 1:
+ {
+ rgb.x = q;
+ rgb.y = hsv.z;
+ rgb.z = p;
+ } break;
+ case 2:
+ {
+ rgb.x = p;
+ rgb.y = hsv.z;
+ rgb.z = t;
+ } break;
+ case 3:
+ {
+ rgb.x = p;
+ rgb.y = q;
+ rgb.z = hsv.z;
+ } break;
+ case 4:
+ {
+ rgb.x = t;
+ rgb.y = p;
+ rgb.z = hsv.z;
+ } break;
+ case 5:
+ default:
+ {
+ rgb.x = hsv.z;
+ rgb.y = p;
+ rgb.z = q;
+ } break;
+ }
+
+ return rgb;
+}
+
+// Scroll bar control (used by GuiScrollPanel())
+static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
+{
+ GuiState state = guiState;
+
+ // Is the scrollbar horizontal or vertical?
+ bool isVertical = (bounds.width > bounds.height)? false : true;
+
+ // The size (width or height depending on scrollbar type) of the spinner buttons
+ const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)?
+ (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) :
+ (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0;
+
+ // Arrow buttons [<] [>] [∧] [∨]
+ Rectangle arrowUpLeft = { 0 };
+ Rectangle arrowDownRight = { 0 };
+
+ // Actual area of the scrollbar excluding the arrow buttons
+ Rectangle scrollbar = { 0 };
+
+ // Slider bar that moves --[///]-----
+ Rectangle slider = { 0 };
+
+ // Normalize value
+ if (value > maxValue) value = maxValue;
+ if (value < minValue) value = minValue;
+
+ int valueRange = maxValue - minValue;
+ if (valueRange <= 0) valueRange = 1;
+
+ int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE);
+ if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size
+
+ // Calculate rectangles for all of the components
+ arrowUpLeft = RAYGUI_CLITERAL(Rectangle){
+ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH),
+ (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH),
+ (float)spinnerSize, (float)spinnerSize };
+
+ if (isVertical)
+ {
+ arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize };
+ scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) };
+
+ // Make sure the slider won't get outside of the scrollbar
+ sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize;
+ slider = RAYGUI_CLITERAL(Rectangle){
+ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING),
+ scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)),
+ bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)),
+ (float)sliderSize };
+ }
+ else // horizontal
+ {
+ arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize };
+ scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) };
+
+ // Make sure the slider won't get outside of the scrollbar
+ sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize;
+ slider = RAYGUI_CLITERAL(Rectangle){
+ scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)),
+ bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING),
+ (float)sliderSize,
+ bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) };
+ }
+
+ // Update control
+ //--------------------------------------------------------------------
+ if ((state != STATE_DISABLED) && !guiLocked)
+ {
+ Vector2 mousePoint = GetMousePosition();
+
+ if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) &&
+ !CheckCollisionPointRec(mousePoint, arrowUpLeft) &&
+ !CheckCollisionPointRec(mousePoint, arrowDownRight))
+ {
+ if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ {
+ state = STATE_PRESSED;
+
+ if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue);
+ else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue);
+ }
+ }
+ else
+ {
+ guiControlExclusiveMode = false;
+ guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ }
+ }
+ else if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ state = STATE_FOCUSED;
+
+ // Handle mouse wheel
+ int wheel = (int)GetMouseWheelMove();
+ if (wheel != 0) value += wheel;
+
+ // Handle mouse button down
+ if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
+ {
+ guiControlExclusiveMode = true;
+ guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+
+ // Check arrows click
+ if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
+ else if (!CheckCollisionPointRec(mousePoint, slider))
+ {
+ // If click on scrollbar position but not on slider, place slider directly on that position
+ if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue);
+ else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue);
+ }
+
+ state = STATE_PRESSED;
+ }
+
+ // Keyboard control on mouse hover scrollbar
+ /*
+ if (isVertical)
+ {
+ if (IsKeyDown(KEY_DOWN)) value += 5;
+ else if (IsKeyDown(KEY_UP)) value -= 5;
+ }
+ else
+ {
+ if (IsKeyDown(KEY_RIGHT)) value += 5;
+ else if (IsKeyDown(KEY_LEFT)) value -= 5;
+ }
+ */
+ }
+
+ // Normalize value
+ if (value > maxValue) value = maxValue;
+ if (value < minValue) value = minValue;
+ }
+ //--------------------------------------------------------------------
+
+ // Draw control
+ //--------------------------------------------------------------------
+ GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background
+
+ GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background
+ GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar
+
+ // Draw arrows (using icon if available)
+ if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE))
+ {
+#if defined(RAYGUI_NO_ICONS)
+ GuiDrawText(isVertical? "^" : "<",
+ RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
+ GuiDrawText(isVertical? "v" : ">",
+ RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))));
+#else
+ GuiDrawText(isVertical? "#121#" : "#118#",
+ RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL
+ GuiDrawText(isVertical? "#120#" : "#119#",
+ RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height },
+ TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL
+#endif
+ }
+ //--------------------------------------------------------------------
+
+ return value;
+}
+
+// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
+// WARNING: It multiplies current alpha by alpha scale factor
+static Color GuiFade(Color color, float alpha)
+{
+ if (alpha < 0.0f) alpha = 0.0f;
+ else if (alpha > 1.0f) alpha = 1.0f;
+
+ Color result = { color.r, color.g, color.b, (unsigned char)(color.a*alpha) };
+
+ return result;
+}
+
+#if defined(RAYGUI_STANDALONE)
+// Returns a Color struct from hexadecimal value
+static Color GetColor(int hexValue)
+{
+ Color color;
+
+ color.r = (unsigned char)(hexValue >> 24) & 0xFF;
+ color.g = (unsigned char)(hexValue >> 16) & 0xFF;
+ color.b = (unsigned char)(hexValue >> 8) & 0xFF;
+ color.a = (unsigned char)hexValue & 0xFF;
+
+ return color;
+}
+
+// Returns hexadecimal value for a Color
+static int ColorToInt(Color color)
+{
+ return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a);
+}
+
+// Check if point is inside rectangle
+static bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
+{
+ bool collision = false;
+
+ if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) &&
+ (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true;
+
+ return collision;
+}
+
+// Formatting of text with variables to 'embed'
+static const char *TextFormat(const char *text, ...)
+{
+ #if !defined(RAYGUI_TEXTFORMAT_MAX_SIZE)
+ #define RAYGUI_TEXTFORMAT_MAX_SIZE 256
+ #endif
+
+ static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE];
+
+ va_list args;
+ va_start(args, text);
+ vsprintf(buffer, text, args);
+ va_end(args);
+
+ return buffer;
+}
+
+// Draw rectangle with vertical gradient fill color
+// NOTE: This function is only used by GuiColorPicker()
+static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2)
+{
+ Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height };
+ DrawRectangleGradientEx(bounds, color1, color2, color2, color1);
+}
+
+// Split string into multiple strings
+const char **TextSplit(const char *text, char delimiter, int *count)
+{
+ // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
+ // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
+ // all used memory is static... it has some limitations:
+ // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS
+ // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE
+
+ #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS)
+ #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128
+ #endif
+ #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE)
+ #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024
+ #endif
+
+ static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL };
+ static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 };
+ memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE);
+
+ result[0] = buffer;
+ int counter = 0;
+
+ if (text != NULL)
+ {
+ counter = 1;
+
+ // Count how many substrings we have on text and point to every one
+ for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++)
+ {
+ buffer[i] = text[i];
+ if (buffer[i] == '\0') break;
+ else if (buffer[i] == delimiter)
+ {
+ buffer[i] = '\0'; // Set an end of string at this point
+ result[counter] = buffer + i + 1;
+ counter++;
+
+ if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
+ }
+ }
+ }
+
+ *count = counter;
+ return result;
+}
+
+// Get integer value from text
+// NOTE: This function replaces atoi() [stdlib.h]
+static int TextToInteger(const char *text)
+{
+ int value = 0;
+ int sign = 1;
+
+ if ((text[0] == '+') || (text[0] == '-'))
+ {
+ if (text[0] == '-') sign = -1;
+ text++;
+ }
+
+ for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
+
+ return value*sign;
+}
+
+// Get float value from text
+// NOTE: This function replaces atof() [stdlib.h]
+// WARNING: Only '.' character is understood as decimal point
+static float TextToFloat(const char *text)
+{
+ float value = 0.0f;
+ float sign = 1.0f;
+
+ if ((text[0] == '+') || (text[0] == '-'))
+ {
+ if (text[0] == '-') sign = -1.0f;
+ text++;
+ }
+
+ int i = 0;
+ for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0');
+
+ if (text[i++] != '.') value *= sign;
+ else
+ {
+ float divisor = 10.0f;
+ for (; ((text[i] >= '0') && (text[i] <= '9')); i++)
+ {
+ value += ((float)(text[i] - '0'))/divisor;
+ divisor = divisor*10.0f;
+ }
+ }
+
+ return value;
+}
+
+// Encode codepoint into UTF-8 text (char array size returned as parameter)
+static const char *CodepointToUTF8(int codepoint, int *byteSize)
+{
+ static char utf8[6] = { 0 };
+ int size = 0;
+
+ if (codepoint <= 0x7f)
+ {
+ utf8[0] = (char)codepoint;
+ size = 1;
+ }
+ else if (codepoint <= 0x7ff)
+ {
+ utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
+ utf8[1] = (char)((codepoint & 0x3f) | 0x80);
+ size = 2;
+ }
+ else if (codepoint <= 0xffff)
+ {
+ utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
+ utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
+ utf8[2] = (char)((codepoint & 0x3f) | 0x80);
+ size = 3;
+ }
+ else if (codepoint <= 0x10ffff)
+ {
+ utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
+ utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
+ utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
+ utf8[3] = (char)((codepoint & 0x3f) | 0x80);
+ size = 4;
+ }
+
+ *byteSize = size;
+
+ return utf8;
+}
+
+// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found
+// When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
+// Total number of bytes processed are returned as a parameter
+// NOTE: the standard says U+FFFD should be returned in case of errors
+// but that character is not supported by the default font in raylib
+static int GetCodepointNext(const char *text, int *codepointSize)
+{
+ const char *ptr = text;
+ int codepoint = 0x3f; // Codepoint (defaults to '?')
+ *codepointSize = 1;
+
+ // Get current codepoint and bytes processed
+ if (0xf0 == (0xf8 & ptr[0]))
+ {
+ // 4 byte UTF-8 codepoint
+ if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks
+ codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]);
+ *codepointSize = 4;
+ }
+ else if (0xe0 == (0xf0 & ptr[0]))
+ {
+ // 3 byte UTF-8 codepoint */
+ if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks
+ codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]);
+ *codepointSize = 3;
+ }
+ else if (0xc0 == (0xe0 & ptr[0]))
+ {
+ // 2 byte UTF-8 codepoint
+ if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks
+ codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]);
+ *codepointSize = 2;
+ }
+ else if (0x00 == (0x80 & ptr[0]))
+ {
+ // 1 byte UTF-8 codepoint
+ codepoint = ptr[0];
+ *codepointSize = 1;
+ }
+
+ return codepoint;
+}
+#endif // RAYGUI_STANDALONE
+
+#endif // RAYGUI_IMPLEMENTATION
diff --git a/examples/shaders/resources/LICENSE.md b/examples/shaders/resources/LICENSE.md
index 7210e34b2..078036df7 100644
--- a/examples/shaders/resources/LICENSE.md
+++ b/examples/shaders/resources/LICENSE.md
@@ -10,4 +10,7 @@
| space.png | ❔ | ❔ | - |
| texel_checker.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | Made with [UV Checker Map Maker](http://uvchecker.byvalle.com/) |
| cubicmap.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | - |
-| spark_flame.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | Made with [EffectTextureMaker](https://mebiusbox.github.io/contents/EffectTextureMaker/) |
\ No newline at end of file
+| spark_flame.png | [@raysan5](https://github.com/raysan5) | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | Made with [EffectTextureMaker](https://mebiusbox.github.io/contents/EffectTextureMaker/) |
+| parrots.png | [Kodak set](http://r0k.us/graphics/kodak/) | ❔ | Original name: `kodim23.png` |
+| cat.png | ❔ | ❔ | - |
+| mandrill.png | ❔ | [CC0](https://creativecommons.org/publicdomain/zero/1.0/) | Mandrill (a.k.a. Baboon) |
\ No newline at end of file
diff --git a/examples/shaders/resources/cat.png b/examples/shaders/resources/cat.png
new file mode 100644
index 000000000..db56b9ead
Binary files /dev/null and b/examples/shaders/resources/cat.png differ
diff --git a/examples/shaders/resources/mandrill.png b/examples/shaders/resources/mandrill.png
new file mode 100644
index 000000000..02d058eb0
Binary files /dev/null and b/examples/shaders/resources/mandrill.png differ
diff --git a/examples/shaders/resources/parrots.png b/examples/shaders/resources/parrots.png
new file mode 100644
index 000000000..9a0e7f806
Binary files /dev/null and b/examples/shaders/resources/parrots.png differ
diff --git a/examples/shaders/resources/shaders/glsl100/color_correction.fs b/examples/shaders/resources/shaders/glsl100/color_correction.fs
new file mode 100644
index 000000000..a678c6ed2
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl100/color_correction.fs
@@ -0,0 +1,34 @@
+#version 100
+
+precision mediump float;
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+uniform float contrast;
+uniform float saturation;
+uniform float brightness;
+
+void main()
+{
+ // Get texel color
+ vec4 texel = texture2D(texture0, fragTexCoord);
+
+ // Apply contrast
+ texel.rgb = (texel.rgb - 0.5)*(contrast/100.0 + 1.0) + 0.5;
+
+ // Apply brightness
+ texel.rgb = texel.rgb + brightness/100.0;
+
+ // Apply saturation
+ float intensity = dot(texel.rgb, vec3(0.299, 0.587, 0.114));
+ texel.rgb = (texel.rgb - intensity)*saturation/100.0 + texel.rgb;
+
+ // Output resulting color
+ gl_FragColor = texel;
+}
diff --git a/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs b/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs
new file mode 100644
index 000000000..fb6dee8b3
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs
@@ -0,0 +1,62 @@
+#version 100
+
+#define PI 3.1415926535897932384626433832795
+
+precision highp float;
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+uniform vec2 offset; // Offset of the scale
+uniform float zoom; // Zoom of the scale
+// NOTE: Maximum number of shader for-loop iterations depend on GPU,
+// For example, on RasperryPi for this examply only supports up to 60
+uniform int maxIterations; // Max iterations per pixel
+
+const float max = 4.0; // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity
+const float max2 = max*max; // Square of max to avoid computing square root
+
+// WebGL shaders for loop iteration limit only const
+const int maxIterationsLimit = 20000;
+
+void main()
+{
+ // The pixel coordinates are scaled so they are on the mandelbrot scale
+ // NOTE: fragTexCoord already comes as normalized screen coordinates but offset must be normalized before scaling and zoom
+ vec2 c = vec2((fragTexCoord.x - 0.5)*2.5, (fragTexCoord.y - 0.5)*1.5)/zoom;
+ c.x += offset.x;
+ c.y += offset.y;
+ float a = 0.0;
+ float b = 0.0;
+
+ // The Mandelbrot set is a two-dimensional set defined in the complex plane on which the iteration of the function
+ // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0
+ // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i
+
+ for (int iter = 0; iter < maxIterationsLimit; ++iter)
+ {
+ float aa = a*a;
+ float bb = b*b;
+ if (iter >= maxIterations)
+ {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+ return;
+ }
+ if (aa + bb > max2)
+ {
+ float normR = float(iter - (iter/55)*55)/55.0;
+ float normG = float(iter - (iter/69)*69)/69.0;
+ float normB = float(iter - (iter/40)*40)/40.0;
+
+ gl_FragColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0);
+ return;
+ }
+
+ float twoab = 2.0*a*b;
+ a = aa - bb + c.x;
+ b = twoab + c.y;
+ }
+
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+}
diff --git a/examples/shaders/resources/shaders/glsl120/color_correction.fs b/examples/shaders/resources/shaders/glsl120/color_correction.fs
new file mode 100644
index 000000000..520275ca4
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl120/color_correction.fs
@@ -0,0 +1,31 @@
+#version 120
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+uniform float contrast;
+uniform float saturation;
+uniform float brightness;
+
+void main()
+{
+ vec4 texel = texture2D(texture0, fragTexCoord); // Get texel color
+
+ // Apply contrast
+ texel.rgb = (texel.rgb - 0.5)*(contrast/100.0 + 1.0) + 0.5;
+
+ // Apply brightness
+ texel.rgb = texel.rgb + brightness/100.0;
+
+ // Apply saturation
+ float intensity = dot(texel.rgb, vec3(0.299, 0.587, 0.114));
+ texel.rgb = (texel.rgb - intensity)*saturation/100.0 + texel.rgb;
+
+ // Output resulting color
+ gl_FragColor = texel;
+}
\ No newline at end of file
diff --git a/examples/shaders/resources/shaders/glsl120/mandelbrot_set.fs b/examples/shaders/resources/shaders/glsl120/mandelbrot_set.fs
new file mode 100644
index 000000000..5da3ef437
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl120/mandelbrot_set.fs
@@ -0,0 +1,59 @@
+#version 120
+
+#define PI 3.1415926535897932384626433832795
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+uniform vec2 offset; // Offset of the scale
+uniform float zoom; // Zoom of the scale
+// NOTE: Maximum number of shader for-loop iterations depend on GPU,
+// For example, on RasperryPi for this examply only supports up to 60
+uniform int maxIterations; // Max iterations per pixel
+
+const float max = 4.0; // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity
+const float max2 = max*max; // Square of max to avoid computing square root
+
+void main()
+{
+ // The pixel coordinates are scaled so they are on the mandelbrot scale
+ // NOTE: fragTexCoord already comes as normalized screen coordinates but offset must be normalized before scaling and zoom
+ vec2 c = vec2((fragTexCoord.x - 0.5)*2.5, (fragTexCoord.y - 0.5)*1.5)/zoom;
+ c.x += offset.x;
+ c.y += offset.y;
+ float a = 0.0;
+ float b = 0.0;
+
+ // The Mandelbrot set is a two-dimensional set defined in the complex plane on which the iteration of the function
+ // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0
+ // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i
+
+ int iter = 0;
+ while (iter < maxIterations)
+ {
+ float aa = a*a;
+ float bb = b*b;
+ if (aa + bb > max2)
+ break;
+
+ float twoab = 2.0*a*b;
+ a = aa - bb + c.x;
+ b = twoab + c.y;
+
+ ++iter;
+ }
+
+ if (iter >= maxIterations)
+ {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+ }
+ else
+ {
+ float normR = float(iter - (iter/55)*55)/55.0;
+ float normG = float(iter - (iter/69)*69)/69.0;
+ float normB = float(iter - (iter/40)*40)/40.0;
+
+ gl_FragColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0);
+ }
+}
diff --git a/examples/shaders/resources/shaders/glsl330/color_correction.fs b/examples/shaders/resources/shaders/glsl330/color_correction.fs
new file mode 100644
index 000000000..c489d6df1
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl330/color_correction.fs
@@ -0,0 +1,34 @@
+#version 330
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+uniform float contrast;
+uniform float saturation;
+uniform float brightness;
+
+// Output fragment color
+out vec4 finalColor;
+
+void main()
+{
+ vec4 texel = texture(texture0, fragTexCoord); // Get texel color
+
+ // Apply contrast
+ texel.rgb = (texel.rgb - 0.5f)*(contrast/100.0f + 1.0f) + 0.5f;
+
+ // Apply brightness
+ texel.rgb = texel.rgb + brightness/100.0f;
+
+ // Apply saturation
+ float intensity = dot(texel.rgb, vec3(0.299f, 0.587f, 0.114f));
+ texel.rgb = (texel.rgb - intensity)*saturation/100.0f + texel.rgb;
+
+ // Output resulting color
+ finalColor = texel;
+}
\ No newline at end of file
diff --git a/examples/shaders/resources/shaders/glsl330/mandelbrot_set.fs b/examples/shaders/resources/shaders/glsl330/mandelbrot_set.fs
new file mode 100644
index 000000000..bde74565f
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl330/mandelbrot_set.fs
@@ -0,0 +1,58 @@
+#version 330
+
+#define PI 3.1415926535897932384626433832795
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+// Output fragment color
+out vec4 finalColor;
+
+uniform vec2 offset; // Offset of the scale
+uniform float zoom; // Zoom of the scale
+uniform int maxIterations; // Max iterations per pixel
+
+const float max = 4.0; // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity
+const float max2 = max*max; // Square of max to avoid computing square root
+
+void main()
+{
+ // The pixel coordinates are scaled so they are on the mandelbrot scale
+ // NOTE: fragTexCoord already comes as normalized screen coordinates but offset must be normalized before scaling and zoom
+ vec2 c = vec2((fragTexCoord.x - 0.5)*2.5, (fragTexCoord.y - 0.5)*1.5)/zoom;
+ c.x += offset.x;
+ c.y += offset.y;
+ float a = 0.0;
+ float b = 0.0;
+
+ // The Mandelbrot set is a two-dimensional set defined in the complex plane on which the iteration of the function
+ // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0
+ // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i
+
+ int iter = 0;
+ for (iter = 0; iter < maxIterations; ++iter)
+ {
+ float aa = a*a;
+ float bb = b*b;
+ if (aa + bb > max2)
+ break;
+
+ float twoab = 2.0*a*b;
+ a = aa - bb + c.x;
+ b = twoab + c.y;
+ }
+
+ if (iter >= maxIterations)
+ {
+ finalColor = vec4(0.0, 0.0, 0.0, 1.0);
+ }
+ else
+ {
+ float normR = float(iter%55)/55.0;
+ float normG = float(iter%69)/69.0;
+ float normB = float(iter%40)/40.0;
+
+ finalColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0);
+ }
+}
diff --git a/examples/shaders/shaders_color_correction.c b/examples/shaders/shaders_color_correction.c
new file mode 100644
index 000000000..3abf29840
--- /dev/null
+++ b/examples/shaders/shaders_color_correction.c
@@ -0,0 +1,148 @@
+/*******************************************************************************************
+*
+* raylib [shaders] example - color correction
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
+* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
+*
+* Example originally created with raylib 5.6, last time updated with raylib 5.6
+*
+* Example contributed by Jordi Santonja (@JordSant) and reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 Jordi Santonja (@JordSant)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h" // Required for GUI controls
+
+#if defined(PLATFORM_DESKTOP)
+ #define GLSL_VERSION 330
+#else // PLATFORM_ANDROID, PLATFORM_WEB
+ #define GLSL_VERSION 100
+#endif
+
+#define MAX_TEXTURES 4
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [shaders] example - color correction");
+
+ Texture2D texture[MAX_TEXTURES] = {
+ LoadTexture("resources/parrots.png"),
+ LoadTexture("resources/cat.png"),
+ LoadTexture("resources/mandrill.png"),
+ LoadTexture("resources/fudesumi.png")
+ };
+
+ Shader shdrColorCorrection = LoadShader(0, TextFormat("resources/shaders/glsl%i/color_correction.fs", GLSL_VERSION));
+
+ int imageIndex = 0;
+ int resetButtonClicked = 0;
+
+ float contrast = 0.0f;
+ float saturation = 0.0f;
+ float brightness = 0.0f;
+
+ // Get shader locations
+ int contrastLoc = GetShaderLocation(shdrColorCorrection, "contrast");
+ int saturationLoc = GetShaderLocation(shdrColorCorrection, "saturation");
+ int brightnessLoc = GetShaderLocation(shdrColorCorrection, "brightness");
+
+ // Set shader values (they can be changed later)
+ SetShaderValue(shdrColorCorrection, contrastLoc, &contrast, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shdrColorCorrection, saturationLoc, &saturation, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shdrColorCorrection, brightnessLoc, &brightness, SHADER_UNIFORM_FLOAT);
+
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ // Select texture to draw
+ if (IsKeyPressed(KEY_ONE)) imageIndex = 0;
+ else if (IsKeyPressed(KEY_TWO)) imageIndex = 1;
+ else if (IsKeyPressed(KEY_THREE)) imageIndex = 2;
+ else if (IsKeyPressed(KEY_FOUR)) imageIndex = 3;
+
+ // Reset values to 0
+ if (IsKeyPressed(KEY_R) || resetButtonClicked)
+ {
+ contrast = 0.0f;
+ saturation = 0.0f;
+ brightness = 0.0f;
+ }
+
+ // Send the values to the shader
+ SetShaderValue(shdrColorCorrection, contrastLoc, &contrast, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shdrColorCorrection, saturationLoc, &saturation, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shdrColorCorrection, brightnessLoc, &brightness, SHADER_UNIFORM_FLOAT);
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ BeginShaderMode(shdrColorCorrection);
+
+ DrawTexture(texture[imageIndex], 580/2 - texture[imageIndex].width/2, GetScreenHeight()/2 - texture[imageIndex].height/2, WHITE);
+
+ EndShaderMode();
+
+ DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 });
+ DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 232, 232, 232, 255 });
+
+ // Draw UI info text
+ DrawText("Color Correction", 585, 40, 20, GRAY);
+
+ DrawText("Picture", 602, 75, 10, GRAY);
+ DrawText("Press [1] - [4] to Change Picture", 600, 230, 8, GRAY);
+ DrawText("Press [R] to Reset Values", 600, 250, 8, GRAY);
+
+ // Draw GUI controls
+ //------------------------------------------------------------------------------
+ GuiToggleGroup((Rectangle){ 645, 70, 20, 20 }, "1;2;3;4", &imageIndex);
+
+ GuiSliderBar((Rectangle){ 645, 100, 120, 20 }, "Contrast", TextFormat("%.0f", contrast), &contrast, -100.0f, 100.0f);
+ GuiSliderBar((Rectangle){ 645, 130, 120, 20 }, "Saturation", TextFormat("%.0f", saturation), &saturation, -100.0f, 100.0f);
+ GuiSliderBar((Rectangle){ 645, 160, 120, 20 }, "Brightness", TextFormat("%.0f", brightness), &brightness, -100.0f, 100.0f);
+
+ resetButtonClicked = GuiButton((Rectangle){ 645, 190, 40, 20 }, "Reset");
+ //------------------------------------------------------------------------------
+
+ DrawFPS(710, 10);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ for (int i = 0; i < MAX_TEXTURES; ++i) UnloadTexture(texture[i]);
+ UnloadShader(shdrColorCorrection);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
diff --git a/examples/shaders/shaders_color_correction.png b/examples/shaders/shaders_color_correction.png
new file mode 100644
index 000000000..5bf5dcba6
Binary files /dev/null and b/examples/shaders/shaders_color_correction.png differ
diff --git a/examples/shaders/shaders_mandelbrot_set.c b/examples/shaders/shaders_mandelbrot_set.c
new file mode 100644
index 000000000..dc592b6e4
--- /dev/null
+++ b/examples/shaders/shaders_mandelbrot_set.c
@@ -0,0 +1,229 @@
+/*******************************************************************************************
+*
+* raylib [shaders] example - mandelbrot set
+*
+* Example complexity rating: [★★★☆] 3/4
+*
+* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
+* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
+*
+* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
+*
+* Example originally created with raylib 5.6, last time updated with raylib 5.6
+*
+* Example contributed by Jordi Santonja (@JordSant)
+* Based on previous work by Josh Colclough (@joshcol9232)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 Jordi Santonja (@JordSant)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include
+
+#if defined(PLATFORM_DESKTOP)
+ #define GLSL_VERSION 330
+#else // PLATFORM_ANDROID, PLATFORM_WEB
+ #define GLSL_VERSION 100
+#endif
+
+// A few good interesting places
+const float pointsOfInterest[6][3] =
+{
+ { -1.76826775f, -0.00422996283f, 28435.9238f },
+ { 0.322004497f, -0.0357099883f, 56499.7266f },
+ { -0.748880744f, -0.0562955774f, 9237.59082f },
+ { -1.78385007f, -0.0156200649f, 14599.5283f },
+ { -0.0985441282f, -0.924688697f, 26259.8535f },
+ { 0.317785531f, -0.0322612226f, 29297.9258f },
+};
+
+const int screenWidth = 800;
+const int screenHeight = 450;
+const float zoomSpeed = 1.01f;
+const float offsetSpeedMul = 2.0f;
+
+const float startingZoom = 0.6f;
+const float startingOffset[2] = { -0.5f, 0.0f };
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "raylib [shaders] example - mandelbrot set");
+
+ // Load mandelbrot set shader
+ // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
+ Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/mandelbrot_set.fs", GLSL_VERSION));
+
+ // Create a RenderTexture2D to be used for render to texture
+ RenderTexture2D target = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
+
+ // Offset and zoom to draw the mandelbrot set at. (centered on screen and default size)
+ float offset[2] = { startingOffset[0], startingOffset[1] };
+ float zoom = startingZoom;
+ // Depending on the zoom the mximum number of iterations must be adapted to get more detail as we zzoom in
+ // The solution is not perfect, so a control has been added to increase/decrease the number of iterations with UP/DOWN keys
+#if defined(PLATFORM_DESKTOP)
+ int maxIterations = 333;
+ float maxIterationsMultiplier = 166.5f;
+#else
+ int maxIterations = 43;
+ float maxIterationsMultiplier = 22.0f;
+#endif
+
+ // Get variable (uniform) locations on the shader to connect with the program
+ // NOTE: If uniform variable could not be found in the shader, function returns -1
+ int zoomLoc = GetShaderLocation(shader, "zoom");
+ int offsetLoc = GetShaderLocation(shader, "offset");
+ int maxIterationsLoc = GetShaderLocation(shader, "maxIterations");
+
+ // Upload the shader uniform values!
+ SetShaderValue(shader, zoomLoc, &zoom, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shader, offsetLoc, offset, SHADER_UNIFORM_VEC2);
+ SetShaderValue(shader, maxIterationsLoc, &maxIterations, SHADER_UNIFORM_INT);
+
+ bool showControls = true; // Show controls
+
+ 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
+ //----------------------------------------------------------------------------------
+ bool updateShader = false;
+
+ // Press [1 - 6] to reset c to a point of interest
+ if (IsKeyPressed(KEY_ONE) ||
+ IsKeyPressed(KEY_TWO) ||
+ IsKeyPressed(KEY_THREE) ||
+ IsKeyPressed(KEY_FOUR) ||
+ IsKeyPressed(KEY_FIVE) ||
+ IsKeyPressed(KEY_SIX))
+ {
+ int interestIndex = 0;
+ if (IsKeyPressed(KEY_ONE)) interestIndex = 0;
+ else if (IsKeyPressed(KEY_TWO)) interestIndex = 1;
+ else if (IsKeyPressed(KEY_THREE)) interestIndex = 2;
+ else if (IsKeyPressed(KEY_FOUR)) interestIndex = 3;
+ else if (IsKeyPressed(KEY_FIVE)) interestIndex = 4;
+ else if (IsKeyPressed(KEY_SIX)) interestIndex = 5;
+
+ offset[0] = pointsOfInterest[interestIndex][0];
+ offset[1] = pointsOfInterest[interestIndex][1];
+ zoom = pointsOfInterest[interestIndex][2];
+ updateShader = true;
+ }
+
+ // If "R" is pressed, reset zoom and offset
+ if (IsKeyPressed(KEY_R))
+ {
+ offset[0] = startingOffset[0];
+ offset[1] = startingOffset[1];
+ zoom = startingZoom;
+ updateShader = true;
+ }
+
+ if (IsKeyPressed(KEY_F1)) showControls = !showControls; // Toggle whether or not to show controls
+
+ // Change number of max iterations with UP and DOWN keys
+ // WARNING: Increasing the number of max iterations greatly impacts performance
+ if (IsKeyPressed(KEY_UP))
+ {
+ maxIterationsMultiplier *= 1.4f;
+ updateShader = true;
+ }
+ else if (IsKeyPressed(KEY_DOWN))
+ {
+ maxIterationsMultiplier /= 1.4f;
+ updateShader = true;
+ }
+
+ // If either left or right button is pressed, zoom in/out
+ if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
+ {
+ // Change zoom. If Mouse left -> zoom in. Mouse right -> zoom out
+ zoom *= IsMouseButtonDown(MOUSE_BUTTON_LEFT)? zoomSpeed : (1.0f/zoomSpeed);
+
+ const Vector2 mousePos = GetMousePosition();
+ Vector2 offsetVelocity;
+ // Find the velocity at which to change the camera. Take the distance of the mouse
+ // From the center of the screen as the direction, and adjust magnitude based on the current zoom
+ offsetVelocity.x = (mousePos.x/(float)screenWidth - 0.5f)*offsetSpeedMul/zoom;
+ offsetVelocity.y = (mousePos.y/(float)screenHeight - 0.5f)*offsetSpeedMul/zoom;
+
+ // Apply move velocity to camera
+ offset[0] += GetFrameTime()*offsetVelocity.x;
+ offset[1] += GetFrameTime()*offsetVelocity.y;
+
+ updateShader = true;
+ }
+
+ // In case a parameter has been changed, update the shader values
+ if (updateShader)
+ {
+ // As we zoom in, increase the number of max iterations to get more detail
+ // Aproximate formula, but it works-ish
+ maxIterations = (int)(sqrtf(2.0f*sqrtf(fabsf(1.0f - sqrtf(37.5f*zoom))))*maxIterationsMultiplier);
+
+ // Update the shader uniform values!
+ SetShaderValue(shader, zoomLoc, &zoom, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shader, offsetLoc, offset, SHADER_UNIFORM_VEC2);
+ SetShaderValue(shader, maxIterationsLoc, &maxIterations, SHADER_UNIFORM_INT);
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ // Using a render texture to draw Mandelbrot set
+ BeginTextureMode(target); // Enable drawing to texture
+ ClearBackground(BLACK); // Clear the render texture
+
+ // Draw a rectangle in shader mode to be used as shader canvas
+ // NOTE: Rectangle uses font white character texture coordinates,
+ // So shader can not be applied here directly because input vertexTexCoord
+ // Do not represent full screen coordinates (space where want to apply shader)
+ DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK);
+ EndTextureMode();
+
+ BeginDrawing();
+ ClearBackground(BLACK); // Clear screen background
+
+ // Draw the saved texture and rendered mandelbrot set with shader
+ // NOTE: We do not invert texture on Y, already considered inside shader
+ BeginShaderMode(shader);
+ // WARNING: If FLAG_WINDOW_HIGHDPI is enabled, HighDPI monitor scaling should be considered
+ // When rendering the RenderTexture2D to fit in the HighDPI scaled Window
+ DrawTextureEx(target.texture, (Vector2){ 0.0f, 0.0f }, 0.0f, 1.0f, WHITE);
+ EndShaderMode();
+
+ if (showControls)
+ {
+ DrawText("Press Mouse buttons right/left to zoom in/out and move", 10, 15, 10, RAYWHITE);
+ DrawText("Press F1 to toggle these controls", 10, 30, 10, RAYWHITE);
+ DrawText("Press [1 - 6] to change point of interest", 10, 45, 10, RAYWHITE);
+ DrawText("Press UP | DOWN to change number of iterations", 10, 60, 10, RAYWHITE);
+ DrawText("Press R to recenter the camera", 10, 75, 10, RAYWHITE);
+ }
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadShader(shader); // Unload shader
+ UnloadRenderTexture(target); // Unload render texture
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
diff --git a/examples/shaders/shaders_mandelbrot_set.png b/examples/shaders/shaders_mandelbrot_set.png
new file mode 100644
index 000000000..6d112931d
Binary files /dev/null and b/examples/shaders/shaders_mandelbrot_set.png differ
diff --git a/examples/shaders/shaders_normalmap_rendering.c b/examples/shaders/shaders_normalmap_rendering.c
index 4859ec813..07399a78e 100644
--- a/examples/shaders/shaders_normalmap_rendering.c
+++ b/examples/shaders/shaders_normalmap_rendering.c
@@ -49,7 +49,7 @@ int main(void)
camera.projection = CAMERA_PERSPECTIVE;
// Load basic normal map lighting shader
- Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/normalmap.vs", GLSL_VERSION),
+ Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/normalmap.vs", GLSL_VERSION),
TextFormat("resources/shaders/glsl%i/normalmap.fs", GLSL_VERSION));
// Get some required shader locations
diff --git a/examples/shapes/shapes_bullet_hell.c b/examples/shapes/shapes_bullet_hell.c
index 235df4d16..95abc4dc9 100644
--- a/examples/shapes/shapes_bullet_hell.c
+++ b/examples/shapes/shapes_bullet_hell.c
@@ -197,7 +197,7 @@ int main(void)
bullets[i].color);
}
}
- }
+ }
else
{
// Draw bullets using DrawCircle(), less performant
diff --git a/examples/shapes/shapes_clock_of_clocks.c b/examples/shapes/shapes_clock_of_clocks.c
index 493e53b5e..3fc24aa92 100644
--- a/examples/shapes/shapes_clock_of_clocks.c
+++ b/examples/shapes/shapes_clock_of_clocks.c
@@ -14,6 +14,9 @@
* Copyright (c) 2025 JP Mortiboys (@themushroompirates)
*
********************************************************************************************/
+#if defined(WIN32)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
#include "raylib.h"
diff --git a/examples/shapes/shapes_lines_drawing.c b/examples/shapes/shapes_lines_drawing.c
new file mode 100644
index 000000000..aeaae3d45
--- /dev/null
+++ b/examples/shapes/shapes_lines_drawing.c
@@ -0,0 +1,146 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - lines drawing
+*
+* Example complexity rating: [★☆☆☆] 1/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6
+*
+* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 Robin (@RobinsAviary)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "raymath.h"
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - lines drawing");
+
+ // Hint text that shows before you click the screen
+ bool startText = true;
+
+ // The mouse's position on the previous frame
+ Vector2 mousePositionPrevious = GetMousePosition();
+
+ // The canvas to draw lines on
+ RenderTexture canvas = LoadRenderTexture(screenWidth, screenHeight);
+
+ // The background color of the canvas
+ const Color backgroundColor = RAYWHITE;
+
+ // The line's thickness
+ float lineThickness = 8.0f;
+ // The lines hue (in HSV, from 0-360)
+ float lineHue = 0.0f;
+
+ // Clear the canvas to the background color
+ BeginTextureMode(canvas);
+ ClearBackground(backgroundColor);
+ EndTextureMode();
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ // Disable the hint text once the user clicks
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && startText)
+ {
+ startText = false;
+ }
+
+ // Clear the canvas when the user middle-clicks
+ if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))
+ {
+ BeginTextureMode(canvas);
+ ClearBackground(backgroundColor);
+ EndTextureMode();
+ }
+
+ // Store whether the left and right buttons are down
+ bool leftButtonDown = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
+ bool rightButtonDown = IsMouseButtonDown(MOUSE_BUTTON_RIGHT);
+
+ if (leftButtonDown || rightButtonDown)
+ {
+ // The color for the line
+ Color drawColor;
+
+ if (leftButtonDown)
+ {
+ // Increase the hue value by the distance our cursor has moved since the last frame (divided by 3)
+ lineHue += Vector2Distance(mousePositionPrevious, GetMousePosition())/3.0f;
+
+ // While the hue is >=360, subtract it to bring it down into the range 0-360
+ // This is more visually accurate than resetting to zero
+ while (lineHue >= 360.0f)
+ {
+ lineHue -= 360.0f;
+ }
+
+ // Create the final color
+ drawColor = ColorFromHSV(lineHue, 1.0f, 1.0f);
+ }
+ else if (rightButtonDown)
+ {
+ // Use the background color as an "eraser"
+ drawColor = backgroundColor;
+ }
+
+ // Draw the line onto the canvas
+ BeginTextureMode(canvas);
+ // Circles act as "caps", smoothing corners
+ DrawCircleV(mousePositionPrevious, lineThickness/2.0f, drawColor);
+ DrawCircleV(GetMousePosition(), lineThickness/2.0f, drawColor);
+ DrawLineEx(mousePositionPrevious, GetMousePosition(), lineThickness, drawColor);
+ EndTextureMode();
+ }
+
+ // Update line thickness based on mousewheel
+ lineThickness += GetMouseWheelMove();
+ lineThickness = Clamp(lineThickness, 1.0, 500.0f);
+
+ // Update mouse's previous position
+ mousePositionPrevious = GetMousePosition();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ // Draw the render texture to the screen, flipped vertically to make it appear top-side up
+ DrawTextureRec(canvas.texture, (Rectangle){ 0.0f, 0.0f, (float)canvas.texture.width,(float)-canvas.texture.height }, Vector2Zero(), WHITE);
+
+ // Draw the preview circle
+ if (!leftButtonDown) DrawCircleLinesV(GetMousePosition(), lineThickness/2.0f, (Color){ 127, 127, 127, 127 });
+
+ // Draw the hint text
+ if (startText) DrawText("try clicking and dragging!", 275, 215, 20, LIGHTGRAY);
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ // Unload the canvas render texture
+ UnloadRenderTexture(canvas);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/shapes/shapes_lines_drawing.png b/examples/shapes/shapes_lines_drawing.png
new file mode 100644
index 000000000..59ef65934
Binary files /dev/null and b/examples/shapes/shapes_lines_drawing.png differ
diff --git a/examples/shapes/shapes_math_angle_rotation.c b/examples/shapes/shapes_math_angle_rotation.c
new file mode 100644
index 000000000..f895026f5
--- /dev/null
+++ b/examples/shapes/shapes_math_angle_rotation.c
@@ -0,0 +1,105 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - math angle rotation
+*
+* Example complexity rating: [★☆☆☆] 1/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6
+*
+* Example contributed by Kris (@krispy-snacc) and reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 Kris (@krispy-snacc)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "raymath.h" // for DEG2RAD
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 720;
+ const int screenHeight = 400;
+
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - math angle rotation");
+ SetTargetFPS(60);
+
+ Vector2 center = { screenWidth / 2.0f, screenHeight / 2.0f };
+ const float lineLength = 150.0f;
+
+ // Predefined angles for fixed lines
+ int angles[] = { 0, 30, 60, 90 };
+ int numAngles = sizeof(angles)/sizeof(angles[0]);
+
+ float totalAngle = 0.0f; // Animated rotation angle
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose())
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ totalAngle += 1.0f; // degrees per frame
+ if (totalAngle >= 360.0f) totalAngle -= 360.0f;
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(WHITE);
+
+ DrawText("Fixed angles + rotating line", 10, 10, 20, LIGHTGRAY);
+
+ // Draw fixed-angle lines with colorful gradient
+ for (int i = 0; i < numAngles; i++)
+ {
+ float rad = angles[i] * DEG2RAD;
+ Vector2 end = { center.x + cosf(rad) * lineLength,
+ center.y + sinf(rad) * lineLength };
+
+ // Gradient color from green → cyan → blue → magenta
+ Color col;
+ switch(i)
+ {
+ case 0: col = GREEN; break;
+ case 1: col = ORANGE; break;
+ case 2: col = BLUE; break;
+ case 3: col = MAGENTA; break;
+ default: col = WHITE; break;
+ }
+
+ DrawLineEx(center, end, 5.0f, col);
+
+ // Draw angle label slightly offset along the line
+ Vector2 textPos = { center.x + cosf(rad) * (lineLength + 20),
+ center.y + sinf(rad) * (lineLength + 20) };
+ DrawText(TextFormat("%d°", angles[i]), (int)textPos.x, (int)textPos.y, 20, col);
+ }
+
+ // Draw animated rotating line with changing color
+ float animRad = totalAngle * DEG2RAD;
+ Vector2 animEnd = { center.x + cosf(animRad) * lineLength,
+ center.y + sinf(animRad) * lineLength };
+
+ // Cycle through HSV colors for animated line
+ Color animCol = ColorFromHSV(fmodf(totalAngle, 360.0f), 0.8f, 0.9f);
+ DrawLineEx(center, animEnd, 5.0f, animCol);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow();
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
diff --git a/examples/shapes/shapes_math_angle_rotation.png b/examples/shapes/shapes_math_angle_rotation.png
new file mode 100644
index 000000000..fd9a92360
Binary files /dev/null and b/examples/shapes/shapes_math_angle_rotation.png differ
diff --git a/examples/shapes/shapes_math_sine_cosine.c b/examples/shapes/shapes_math_sine_cosine.c
new file mode 100644
index 000000000..d8d13920e
--- /dev/null
+++ b/examples/shapes/shapes_math_sine_cosine.c
@@ -0,0 +1,176 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - math sine cosine
+*
+* Example complexity rating: [★★☆☆] 2/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6-dev
+*
+* Example contributed by Jopestpe (@jopestpe) and reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 Jopestpe (@jopestpe)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include
+#include "raymath.h"
+
+#define RAYGUI_IMPLEMENTATION
+#include "raygui.h" // Required for GUI controls
+
+// Wave points for sine/cosine visualization
+#define WAVE_POINTS 36
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ SetConfigFlags(FLAG_MSAA_4X_HINT);
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - math sine cosine");
+
+ Vector2 sinePoints[WAVE_POINTS];
+ Vector2 cosPoints[WAVE_POINTS];
+ Vector2 center = { (screenWidth/2.0f) - 30.f, screenHeight/2.0f };
+ Rectangle start = { 20.f, screenHeight - 120.f , 200.0f, 100.0f};
+ float radius = 130.0f;
+ float angle = 0.0f;
+ bool pause = false;
+
+ for (int i = 0; i < WAVE_POINTS; i++)
+ {
+ float t = i/(float)(WAVE_POINTS - 1);
+ float currentAngle = t*360.0f*DEG2RAD;
+ sinePoints[i] = (Vector2){ start.x + t*start.width, start.y + start.height/2.0f - sinf(currentAngle)*(start.height/2.0f) };
+ cosPoints[i] = (Vector2){ start.x + t*start.width, start.y + start.height/2.0f - cosf(currentAngle)*(start.height/2.0f) };
+ }
+
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ float angleRad = angle*DEG2RAD;
+ float cosRad = cosf(angleRad);
+ float sinRad = sinf(angleRad);
+
+ Vector2 point = { center.x + cosRad*radius, center.y - sinRad*radius };
+ Vector2 limitMin = { center.x - radius, center.y - radius };
+ Vector2 limitMax = { center.x + radius, center.y + radius };
+
+ float complementary = 90.0f - angle;
+ float supplementary = 180.0f - angle;
+ float explementary = 360.0f - angle;
+
+ float tangent = Clamp(tanf(angleRad), -10.0f, 10.0f);
+ float cotangent = (fabsf(tangent) > 0.001f) ? Clamp(1.0f/tangent, -radius, radius) : 0.0f;
+ Vector2 tangentPoint = { center.x + radius, center.y - tangent*radius };
+ Vector2 cotangentPoint = { center.x + cotangent*radius, center.y - radius };
+
+ angle = Wrap(angle + (!pause ? 1.0f : 0.0f), 0.0f, 360.0f);
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(RAYWHITE);
+
+ // Cotangent (orange)
+ DrawLineEx((Vector2){ center.x , limitMin.y }, (Vector2){ cotangentPoint.x, limitMin.y }, 2.0f, ORANGE);
+ DrawLineDashed(center, cotangentPoint, 10.0f, 4.0f, ORANGE);
+
+ // Side background
+ DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 });
+ DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 232, 232, 232, 255 });
+
+ // Base circle and axes
+ DrawCircleLinesV(center, radius, GRAY);
+ DrawLineEx((Vector2){ center.x, limitMin.y }, (Vector2){ center.x, limitMax.y }, 1.0f, GRAY);
+ DrawLineEx((Vector2){ limitMin.x, center.y }, (Vector2){ limitMax.x, center.y }, 1.f, GRAY);
+
+ // Wave graph axes
+ DrawLineEx((Vector2){ start.x , start.y }, (Vector2){ start.x , start.y + start.height }, 2.0f, GRAY);
+ DrawLineEx((Vector2){ start.x + start.width, start.y }, (Vector2){ start.x + start.width, start.y + start.height }, 2.0f, GRAY);
+ DrawLineEx((Vector2){ start.x, start.y + start.height/2 }, (Vector2){ start.x + start.width, start.y + start.height/2 }, 2.0f, GRAY);
+
+ // Wave graph axis labels
+ DrawText("1", start.x - 8, start.y, 6, GRAY);
+ DrawText("0", start.x - 8, start.y + start.height/2 - 6, 6, GRAY);
+ DrawText("-1", start.x - 12, start.y + start.height - 8, 6, GRAY);
+ DrawText("0", start.x - 2, start.y + start.height + 4, 6, GRAY);
+ DrawText("360", start.x + start.width - 8, start.y + start.height + 4, 6, GRAY);
+
+ // Sine (red - vertical)
+ DrawLineEx((Vector2){ center.x, center.y }, (Vector2){ center.x, point.y }, 2.0f, RED);
+ DrawLineDashed((Vector2){ point.x, center.y }, (Vector2){ point.x, point.y }, 10.0f, 4.0f, RED);
+ DrawText(TextFormat("Sine %.2f", sinRad), 640, 190, 6, RED);
+ DrawCircleV((Vector2){ start.x + (angle/360.0f)*start.width, start.y + ((-sinRad + 1)*start.height/2.0f) }, 4.0f, RED);
+ DrawSplineLinear(sinePoints, WAVE_POINTS, 1.0f, RED);
+
+ // Cosine (blue - horizontal)
+ DrawLineEx((Vector2){ center.x, center.y }, (Vector2){ point.x, center.y }, 2.0f, BLUE);
+ DrawLineDashed((Vector2){ center.x , point.y }, (Vector2){ point.x, point.y }, 10.0f, 4.0f, BLUE);
+ DrawText(TextFormat("Cosine %.2f", cosRad), 640, 210, 6, BLUE);
+ DrawCircleV((Vector2){ start.x + (angle/360.0f)*start.width, start.y + ((-cosRad + 1)*start.height/2.0f) }, 4.0f, BLUE);
+ DrawSplineLinear(cosPoints, WAVE_POINTS, 1.0f, BLUE);
+
+ // Tangent (purple)
+ DrawLineEx((Vector2){ limitMax.x , center.y }, (Vector2){ limitMax.x, tangentPoint.y }, 2.0f, PURPLE);
+ DrawLineDashed(center, tangentPoint, 10.0f, 4.0f, PURPLE);
+ DrawText(TextFormat("Tangent %.2f", tangent), 640, 230, 6, PURPLE);
+
+ // Cotangent (orange)
+ DrawText(TextFormat("Cotangent %.2f", cotangent), 640, 250, 6, ORANGE);
+
+ // Complementary angle (beige)
+ DrawCircleSectorLines(center, radius*0.6f , -angle, -90.f , 36.0f, BEIGE);
+ DrawText(TextFormat("Complementary %0.f°",complementary), 640, 150, 6, BEIGE);
+
+ // Supplementary angle (darkblue)
+ DrawCircleSectorLines(center, radius*0.5f , -angle, -180.f , 36.0f, DARKBLUE);
+ DrawText(TextFormat("Supplementary %0.f°",supplementary), 640, 130, 6, DARKBLUE);
+
+ // Explementary angle (pink)
+ DrawCircleSectorLines(center, radius*0.4f , -angle, -360.f , 36.0f, PINK);
+ DrawText(TextFormat("Explementary %0.f°",explementary), 640, 170, 6, PINK);
+
+ // Current angle - arc (lime), radius (black), endpoint (black)
+ DrawCircleSectorLines(center, radius*0.7f , -angle, 0.f, 36.0f, LIME);
+ DrawLineEx((Vector2){ center.x , center.y }, point, 2.0f, BLACK);
+ DrawCircleV(point, 4.0f, BLACK);
+
+ // Draw GUI controls
+ //------------------------------------------------------------------------------
+ GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(GRAY));
+ GuiToggle((Rectangle){ 640, 70, 120, 20}, TextFormat("Pause"), &pause);
+ GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(LIME));
+ GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f°", angle), &angle, 0.0f, 360.f);
+
+ // Angle values panel
+ GuiGroupBox((Rectangle){ 620, 110, 140, 170}, "Angle Values");
+ //------------------------------------------------------------------------------
+ DrawFPS(10, 10);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/shapes/shapes_math_sine_cosine.png b/examples/shapes/shapes_math_sine_cosine.png
new file mode 100644
index 000000000..b561f74fb
Binary files /dev/null and b/examples/shapes/shapes_math_sine_cosine.png differ
diff --git a/examples/shapes/shapes_simple_particles.c b/examples/shapes/shapes_simple_particles.c
index 7c2a598c2..c5d9612c3 100644
--- a/examples/shapes/shapes_simple_particles.c
+++ b/examples/shapes/shapes_simple_particles.c
@@ -74,7 +74,7 @@ int main(void)
// Definition of particles
Particle *particles = (Particle*)RL_CALLOC(MAX_PARTICLES, sizeof(Particle)); // Particle array
CircularBuffer circularBuffer = { 0, 0, particles };
-
+
// Particle emitter parameters
int emissionRate = -2; // Negative: on average every -X frames. Positive: particles per frame
ParticleType currentType = WATER;
@@ -100,7 +100,7 @@ int main(void)
// Update the parameters of each particle
UpdateParticles(&circularBuffer, screenWidth, screenHeight);
-
+
// Remove dead particles from the circular buffer
UpdateCircularBuffer(&circularBuffer);
@@ -252,10 +252,10 @@ static void UpdateParticles(CircularBuffer *circularBuffer, int screenWidth, int
// Disable particle when out of screen
Vector2 center = circularBuffer->buffer[i].position;
float radius = circularBuffer->buffer[i].radius;
-
+
if ((center.x < -radius) || (center.x > (screenWidth + radius)) ||
(center.y < -radius) || (center.y > (screenHeight + radius)))
- {
+ {
circularBuffer->buffer[i].alive = false;
}
}
diff --git a/examples/shapes/shapes_starfield_effect.c b/examples/shapes/shapes_starfield_effect.c
index 8dd90fe0b..ca409c926 100644
--- a/examples/shapes/shapes_starfield_effect.c
+++ b/examples/shapes/shapes_starfield_effect.c
@@ -32,18 +32,18 @@ int main(void)
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - starfield effect");
-
+
Color bgColor = ColorLerp(DARKBLUE, BLACK, 0.69f);
-
+
// Speed at which we fly forward
float speed = 10.0f/9.0f;
-
+
// We're either drawing lines or circles
bool drawLines = true;
-
+
Vector3 stars[STAR_COUNT] = { 0 };
Vector2 starsScreenPos[STAR_COUNT] = { 0 };
-
+
// Setup the stars with a random position
for (int i = 0; i < STAR_COUNT; i++)
{
@@ -65,22 +65,22 @@ int main(void)
if ((int)mouseMove != 0) speed += 2.0f*mouseMove/9.0f;
if (speed < 0.0f) speed = 0.1f;
else if (speed > 2.0f) speed = 2.0f;
-
+
// Toggle lines / points with space bar
if (IsKeyPressed(KEY_SPACE)) drawLines = !drawLines;
-
+
float dt = GetFrameTime();
- for (int i = 0; i < STAR_COUNT; i++)
+ for (int i = 0; i < STAR_COUNT; i++)
{
// Update star's timer
stars[i].z -= dt*speed;
-
+
// Calculate the screen position
starsScreenPos[i] = (Vector2){
screenWidth*0.5f + stars[i].x/stars[i].z,
screenHeight*0.5f + stars[i].y/stars[i].z,
};
-
+
// If the star is too old, or offscreen, it dies and we make a new random one
if ((stars[i].z < 0.0f) || (starsScreenPos[i].x < 0) || (starsScreenPos[i].y < 0.0f) ||
(starsScreenPos[i].x > screenWidth) || (starsScreenPos[i].y > screenHeight))
@@ -97,14 +97,14 @@ int main(void)
BeginDrawing();
ClearBackground(bgColor);
-
+
for (int i = 0; i < STAR_COUNT; i++)
{
if (drawLines)
{
// Get the time a little while ago for this star, but clamp it
float t = Clamp(stars[i].z + 1.0f/32.0f, 0.0f, 1.0f);
-
+
// If it's different enough from the current time, we proceed
if ((t - stars[i].z) > 1e-3)
{
@@ -113,26 +113,26 @@ int main(void)
screenWidth*0.5f + stars[i].x/t,
screenHeight*0.5f + stars[i].y/t,
};
-
+
// Draw a line connecting the old point to the current point
DrawLineV(startPos, starsScreenPos[i], RAYWHITE);
}
}
- else
+ else
{
// Make the radius grow as the star ages
float radius = Lerp(stars[i].z, 1.0f, 5.0f);
-
+
// Draw the circle
DrawCircleV(starsScreenPos[i], radius, RAYWHITE);
}
}
-
+
DrawText(TextFormat("[MOUSE WHEEL] Current Speed: %.0f", 9.0f*speed/2.0f), 10, 40, 20, RAYWHITE);
DrawText(TextFormat("[SPACE] Current draw mode: %s", drawLines ? "Lines" : "Circles"), 10, 70, 20, RAYWHITE);
-
+
DrawFPS(10, 10);
-
+
EndDrawing();
//----------------------------------------------------------------------------------
}
diff --git a/examples/text/text_font_loading.c b/examples/text/text_font_loading.c
index f1582348b..151b63d45 100644
--- a/examples/text/text_font_loading.c
+++ b/examples/text/text_font_loading.c
@@ -9,7 +9,7 @@
* - TTF/OTF > Sprite font atlas is generated on loading, user can configure
* some of the generation parameters (size, characters to include)
* - BMFonts > Angel code font fileformat, sprite font image must be provided
-* together with the .fnt file, font generation cna not be configured
+* together with the .fnt file, font generation can not be configured
* - XNA Spritefont > Sprite font image, following XNA Spritefont conventions,
* Characters in image must follow some spacing and order rules
*
diff --git a/projects/VS2022/examples/core_text_file_loading.vcxproj b/projects/VS2022/examples/core_text_file_loading.vcxproj
index c2e25e042..15324701d 100644
--- a/projects/VS2022/examples/core_text_file_loading.vcxproj
+++ b/projects/VS2022/examples/core_text_file_loading.vcxproj
@@ -51,7 +51,7 @@
- {6B1A933E-71B8-4C1F-9E79-02D98830E671}
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}
Win32Proj
core_text_file_loading
10.0
diff --git a/projects/VS2022/examples/models_decals.vcxproj b/projects/VS2022/examples/models_decals.vcxproj
new file mode 100644
index 000000000..a7a5e2f2b
--- /dev/null
+++ b/projects/VS2022/examples/models_decals.vcxproj
@@ -0,0 +1,569 @@
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}
+ Win32Proj
+ models_decals
+ 10.0
+ models_decals
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;shcore.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shaders_color_correction.vcxproj b/projects/VS2022/examples/shaders_color_correction.vcxproj
new file mode 100644
index 000000000..520c041cb
--- /dev/null
+++ b/projects/VS2022/examples/shaders_color_correction.vcxproj
@@ -0,0 +1,569 @@
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}
+ Win32Proj
+ shaders_color_correction
+ 10.0
+ shaders_color_correction
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shaders_mandelbrot_set.vcxproj b/projects/VS2022/examples/shaders_mandelbrot_set.vcxproj
new file mode 100644
index 000000000..4ed5581e1
--- /dev/null
+++ b/projects/VS2022/examples/shaders_mandelbrot_set.vcxproj
@@ -0,0 +1,569 @@
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}
+ Win32Proj
+ shaders_mandelbrot_set
+ 10.0
+ shaders_mandelbrot_set
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shapes_lines_drawing.vcxproj b/projects/VS2022/examples/shapes_lines_drawing.vcxproj
new file mode 100644
index 000000000..49159676b
--- /dev/null
+++ b/projects/VS2022/examples/shapes_lines_drawing.vcxproj
@@ -0,0 +1,569 @@
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}
+ Win32Proj
+ shapes_lines_drawing
+ 10.0
+ shapes_lines_drawing
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;shcore.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shapes_math_angle_rotation.vcxproj b/projects/VS2022/examples/shapes_math_angle_rotation.vcxproj
new file mode 100644
index 000000000..48da9d846
--- /dev/null
+++ b/projects/VS2022/examples/shapes_math_angle_rotation.vcxproj
@@ -0,0 +1,569 @@
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}
+ Win32Proj
+ shapes_math_angle_rotation
+ 10.0
+ shapes_math_angle_rotation
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/examples/shapes_math_sine_cosine.vcxproj b/projects/VS2022/examples/shapes_math_sine_cosine.vcxproj
new file mode 100644
index 000000000..8b2457b83
--- /dev/null
+++ b/projects/VS2022/examples/shapes_math_sine_cosine.vcxproj
@@ -0,0 +1,569 @@
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}
+ Win32Proj
+ shapes_math_sine_cosine
+ 10.0
+ shapes_math_sine_cosine
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shapes
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;shcore.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln
index 7a7eca297..c15632182 100644
--- a/projects/VS2022/raylib.sln
+++ b/projects/VS2022/raylib.sln
@@ -391,7 +391,19 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_highdpi_testbed", "exa
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_screen_recording", "examples\core_screen_recording.vcxproj", "{9DE2FC01-A839-4F89-8319-9071D4C54821}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_text_file_loading", "examples\core_text_file_loading.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_text_file_loading", "examples\core_text_file_loading.vcxproj", "{2F578155-D51F-4C03-AB7F-5C5122CA46CC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_mandelbrot_set", "examples\shaders_mandelbrot_set.vcxproj", "{1C829D1A-892C-451C-AF0B-AC65C85F5CC6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_math_angle_rotation", "examples\shapes_math_angle_rotation.vcxproj", "{84DE22BB-C25F-425C-A7FE-0120CF107B83}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_color_correction", "examples\shaders_color_correction.vcxproj", "{98152EDD-7E28-4FA3-89D8-B636ED5D5F65}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_math_sine_cosine", "examples\shapes_math_sine_cosine.vcxproj", "{B7FDD40F-DDA4-468E-9C40-EEB175964A26}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_decals", "examples\models_decals.vcxproj", "{028F0967-B253-45DA-B1C4-FACCE45D0D8D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_lines_drawing", "examples\shapes_lines_drawing.vcxproj", "{666346D7-C84B-498D-AE17-53B20C62DB1A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -4847,6 +4859,174 @@ Global
{9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x64.Build.0 = Release|x64
{9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x86.ActiveCfg = Release|Win32
{9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x86.Build.0 = Release|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|ARM64.Build.0 = Debug|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x64.ActiveCfg = Debug|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x64.Build.0 = Debug|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x86.ActiveCfg = Debug|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x86.Build.0 = Debug|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|ARM64.ActiveCfg = Release|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|ARM64.Build.0 = Release|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x64.ActiveCfg = Release|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x64.Build.0 = Release|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x86.ActiveCfg = Release|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x86.Build.0 = Release|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|ARM64.Build.0 = Debug|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x64.ActiveCfg = Debug|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x64.Build.0 = Debug|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x86.ActiveCfg = Debug|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x86.Build.0 = Debug|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|ARM64.ActiveCfg = Release|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|ARM64.Build.0 = Release|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x64.ActiveCfg = Release|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x64.Build.0 = Release|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x86.ActiveCfg = Release|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x86.Build.0 = Release|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|ARM64.Build.0 = Debug|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|x64.ActiveCfg = Debug|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|x64.Build.0 = Debug|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|x86.ActiveCfg = Debug|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Debug|x86.Build.0 = Debug|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|ARM64.ActiveCfg = Release|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|ARM64.Build.0 = Release|ARM64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|x64.ActiveCfg = Release|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|x64.Build.0 = Release|x64
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|x86.ActiveCfg = Release|Win32
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83}.Release|x86.Build.0 = Release|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|ARM64.Build.0 = Debug|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|x64.ActiveCfg = Debug|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|x64.Build.0 = Debug|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|x86.ActiveCfg = Debug|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Debug|x86.Build.0 = Debug|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|ARM64.ActiveCfg = Release|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|ARM64.Build.0 = Release|ARM64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|x64.ActiveCfg = Release|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|x64.Build.0 = Release|x64
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|x86.ActiveCfg = Release|Win32
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65}.Release|x86.Build.0 = Release|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|ARM64.Build.0 = Debug|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|x64.ActiveCfg = Debug|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|x64.Build.0 = Debug|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|x86.ActiveCfg = Debug|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Debug|x86.Build.0 = Debug|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|ARM64.ActiveCfg = Release|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|ARM64.Build.0 = Release|ARM64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|x64.ActiveCfg = Release|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|x64.Build.0 = Release|x64
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|x86.ActiveCfg = Release|Win32
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26}.Release|x86.Build.0 = Release|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|x64.ActiveCfg = Debug|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|x64.Build.0 = Debug|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|x86.ActiveCfg = Debug|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Debug|x86.Build.0 = Debug|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|ARM64.Build.0 = Release|ARM64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|x64.ActiveCfg = Release|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|x64.Build.0 = Release|x64
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|x86.ActiveCfg = Release|Win32
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D}.Release|x86.Build.0 = Release|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|ARM64.Build.0 = Debug|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|x64.ActiveCfg = Debug|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|x64.Build.0 = Debug|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|x86.ActiveCfg = Debug|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Debug|x86.Build.0 = Debug|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|ARM64.ActiveCfg = Release|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|ARM64.Build.0 = Release|ARM64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|x64.ActiveCfg = Release|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|x64.Build.0 = Release|x64
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|x86.ActiveCfg = Release|Win32
+ {666346D7-C84B-498D-AE17-53B20C62DB1A}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -5014,7 +5194,7 @@ Global
{C54703BF-D68A-480D-BE27-49B62E45D582} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
{9CD8BCAD-F212-4BCC-BA98-899743CE3279} = {CC132A4D-D081-4C26-BFB9-AB11984054F8}
{0981CA28-E4A5-4DF1-987F-A41D09131EFC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
- {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {6B1A933E-71B8-4C1F-9E79-02D98830E671} = {278D8859-20B1-428F-8448-064F46E1F021}
{6BFF72EA-7362-4A3B-B6E5-9A3655BBBDA3} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
{6777EC3C-077C-42FC-B4AD-B799CE55CCE4} = {8D3C83B7-F1E0-4C2E-9E34-EE5F6AB2502A}
{A61DAD9C-271C-4E95-81AA-DB4CD58564D4} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
@@ -5023,7 +5203,7 @@ Global
{3B27F358-2679-4F38-B297-17B536F580BB} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{718FCBD0-591D-448C-B7D5-9F1CA8544E7B} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{19CA0070-B4B2-4394-90B7-D0C259AA35BA} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
- {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {2CCCD9E4-9058-4291-BD89-39C979F0CA1E} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
{9DB1F875-6E65-4195-B23F-ED8095C0B99C} = {278D8859-20B1-428F-8448-064F46E1F021}
{52BA9067-A5FC-4CE8-82AD-7204ECFDEF9F} = {278D8859-20B1-428F-8448-064F46E1F021}
{8E132D5A-2C00-48D0-8747-97E41356F26F} = {278D8859-20B1-428F-8448-064F46E1F021}
@@ -5044,6 +5224,13 @@ Global
{EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} = {278D8859-20B1-428F-8448-064F46E1F021}
{1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{9DE2FC01-A839-4F89-8319-9071D4C54821} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
+ {84DE22BB-C25F-425C-A7FE-0120CF107B83} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {98152EDD-7E28-4FA3-89D8-B636ED5D5F65} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
+ {B7FDD40F-DDA4-468E-9C40-EEB175964A26} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {028F0967-B253-45DA-B1C4-FACCE45D0D8D} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
+ {666346D7-C84B-498D-AE17-53B20C62DB1A} = {278D8859-20B1-428F-8448-064F46E1F021}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29}
diff --git a/src/Makefile b/src/Makefile
index 0d4ca9ac7..41867da1c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -130,7 +130,7 @@ HOST_PLATFORM_OS ?= WINDOWS
PLATFORM_OS ?= WINDOWS
# Determine PLATFORM_OS when required
-ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW PLATFORM_WEB PLATFORM_WEB_RGFW PLATFORM_ANDROID))
+ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW PLATFORM_DESKTOP_WIN32 PLATFORM_WEB PLATFORM_WEB_RGFW PLATFORM_ANDROID))
# No uname.exe on MinGW!, but OS=Windows_NT on Windows!
# ifeq ($(UNAME),Msys) -> Windows
ifeq ($(OS),Windows_NT)
@@ -228,7 +228,6 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
ifeq ($(ANDROID_ARCH),x86_64)
ANDROID_COMPILER_ARCH = x86_64
endif
-
endif
# Define raylib graphics api depending on selected platform
@@ -252,18 +251,26 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
#GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
#GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
endif
+ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32)
+ GRAPHICS ?= GRAPHICS_API_OPENGL_33
+ #GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering
+ #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
+ #GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
+ #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
+ #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
+endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
- # On DRM OpenGL ES 2.0 must be used
- GRAPHICS = GRAPHICS_API_OPENGL_ES2
+ GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
+ #GRAPHICS = GRAPHICS_API_OPENGL_11_SOFTWARE # Uncomment to use software rendering
endif
ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_WEB PLATFORM_WEB_RGFW))
# On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0
- GRAPHICS = GRAPHICS_API_OPENGL_ES2
+ GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
#GRAPHICS = GRAPHICS_API_OPENGL_ES3
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
# By default use OpenGL ES 2.0 on Android
- GRAPHICS = GRAPHICS_API_OPENGL_ES2
+ GRAPHICS ?= GRAPHICS_API_OPENGL_ES2
endif
# Define default C compiler and archiver to pack library: CC, AR
@@ -283,7 +290,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
- ifeq ($(USE_RPI_CROSS_COMPILER),TRUE)
+ ifeq ($(USE_RPI_CROSSCOMPILER),TRUE)
# Define RPI cross-compiler
#CC = armv6j-hardfloat-linux-gnueabi-gcc
CC = $(RPI_TOOLCHAIN)/bin/$(RPI_TOOLCHAIN_NAME)-gcc
@@ -519,7 +526,7 @@ endif
#------------------------------------------------------------------------------------------------
LDFLAGS = $(CUSTOM_LDFLAGS) -L. -L$(RAYLIB_RELEASE_PATH)
-ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW))
+ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW PLATFORM_DESKTOP_WIN32))
ifeq ($(PLATFORM_OS),WINDOWS)
ifneq ($(CC), tcc)
LDFLAGS += -Wl,--out-implib,$(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME)dll.a
@@ -628,13 +635,19 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
- LDLIBS = -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl
+ LDLIBS = -ldrm -lgbm -lpthread -lrt -lm -ldl
+ ifeq ($(GRAPHICS),GRAPHICS_API_OPENGL_ES2)
+ LDLIBS += -lGLESv2 -lEGL
+ endif
ifeq ($(RAYLIB_MODULE_AUDIO),TRUE)
LDLIBS += -latomic
endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_WIN32)
- LDLIBS = -lgdi32 -lwinmm -lopengl32 -lshcore
+ LDLIBS = -lgdi32 -lwinmm -lshcore
+ ifneq ($(GRAPHICS),GRAPHICS_API_OPENGL_11_SOFTWARE)
+ LDLIBS += -lopengl32
+ endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
LDLIBS = -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lc -lm
diff --git a/src/external/rlsw.h b/src/external/rlsw.h
index 49050f848..9c510e945 100644
--- a/src/external/rlsw.h
+++ b/src/external/rlsw.h
@@ -6,7 +6,7 @@
* rlsw is a custom OpenGL 1.1-style implementation on software, intended to provide all
* functionality available on rlgl.h library used by raylib, becoming a direct software
* rendering replacement for OpenGL 1.1 backend and allowing to run raylib on GPU-less
-* devices when required.
+* devices when required
*
* FEATURES:
* - Rendering to custom internal framebuffer with multiple color modes supported:
@@ -94,11 +94,9 @@
#ifndef SW_MALLOC
#define SW_MALLOC(sz) malloc(sz)
#endif
-
#ifndef SW_REALLOC
#define SW_REALLOC(ptr, newSz) realloc(ptr, newSz)
#endif
-
#ifndef SW_FREE
#define SW_FREE(ptr) free(ptr)
#endif
@@ -115,16 +113,12 @@
#define SW_GL_FRAMEBUFFER_COPY_BGRA true
#endif
-#ifndef SW_GL_BINDING_COPY_TEXTURE
- #define SW_GL_BINDING_COPY_TEXTURE true
-#endif
-
#ifndef SW_COLOR_BUFFER_BITS
- #define SW_COLOR_BUFFER_BITS 24
+ #define SW_COLOR_BUFFER_BITS 32 //< 32 (rgba), 16 (rgb packed) or 8 (rgb packed)
#endif
#ifndef SW_DEPTH_BUFFER_BITS
- #define SW_DEPTH_BUFFER_BITS 16
+ #define SW_DEPTH_BUFFER_BITS 16 //< 32, 24 or 16
#endif
#ifndef SW_MAX_PROJECTION_STACK_SIZE
@@ -196,6 +190,7 @@ typedef double GLclampd;
//#define GL_ATTRIB_STACK_DEPTH 0x0BB0
//#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1
#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
//#define GL_COLOR_WRITEMASK 0x0C23
//#define GL_CURRENT_INDEX 0x0B01
#define GL_CURRENT_COLOR 0x0B00
@@ -330,6 +325,7 @@ typedef double GLclampd;
#define glViewport(x, y, w, h) swViewport((x), (y), (w), (h))
#define glScissor(x, y, w, h) swScissor((x), (y), (w), (h))
#define glClearColor(r, g, b, a) swClearColor((r), (g), (b), (a))
+#define glClearDepth(d) swClearDepth((d))
#define glClear(bitmask) swClear((bitmask))
#define glBlendFunc(sfactor, dfactor) swBlendFunc((sfactor), (dfactor))
#define glPolygonMode(face, mode) swPolygonMode((mode))
@@ -374,14 +370,14 @@ typedef double GLclampd;
#define glTexCoordPointer(sz, t, s, p) swBindArray(SW_TEXTURE_COORD_ARRAY, (p))
#define glColorPointer(sz, t, s, p) swBindArray(SW_COLOR_ARRAY, (p))
#define glDrawArrays(m, o, c) swDrawArrays((m), (o), (c))
+#define glDrawElements(m,c,t,i) swDrawElements((m),(c),(t),(i))
#define glGenTextures(c, v) swGenTextures((c), (v))
#define glDeleteTextures(c, v) swDeleteTextures((c), (v))
-#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), SW_GL_BINDING_COPY_TEXTURE, (p))
+#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), (p))
#define glTexParameteri(tr, pname, param) swTexParameteri((pname), (param))
#define glBindTexture(tr, id) swBindTexture((id))
// OpenGL functions NOT IMPLEMENTED by rlsw
-#define glClearDepth(X) ((void)(X))
#define glDepthMask(X) ((void)(X))
#define glColorMask(X,Y,Z,W) ((void)(X),(void)(Y),(void)(Z),(void)(W))
#define glPixelStorei(X,Y) ((void)(X),(void)(Y))
@@ -391,7 +387,6 @@ typedef double GLclampd;
#define glDepthFunc(X) ((void)(X))
#define glTexSubImage2D(X,Y,Z,W,A,B,C,D,E) ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A),(void)(B),(void)(C),(void)(D),(void)(E))
#define glGetTexImage(X,Y,Z,W,A) ((void)(X),(void)(Y),(void)(Z),(void)(W),(void)(A))
-#define glDrawElements(X,Y,Z,W) ((void)(X),(void)(Y),(void)(Z),(void)(W))
#define glNormal3f(X,Y,Z) ((void)(X),(void)(Y),(void)(Z))
#define glNormal3fv(X) ((void)(X))
#define glNormalPointer(X,Y,Z) ((void)(X),(void)(Y),(void)(Z))
@@ -413,6 +408,7 @@ typedef enum {
SW_VERSION = GL_VERSION,
SW_EXTENSIONS = GL_EXTENSIONS,
SW_COLOR_CLEAR_VALUE = GL_COLOR_CLEAR_VALUE,
+ SW_DEPTH_CLEAR_VALUE = GL_DEPTH_CLEAR_VALUE,
SW_CURRENT_COLOR = GL_CURRENT_COLOR,
SW_CURRENT_TEXTURE_COORDS = GL_CURRENT_TEXTURE_COORDS,
SW_POINT_SIZE = GL_POINT_SIZE,
@@ -527,7 +523,6 @@ SWAPI void swClose(void);
SWAPI bool swResizeFramebuffer(int w, int h);
SWAPI void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels);
SWAPI void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels);
-SWAPI void *swGetColorBuffer(int *w, int *h);
SWAPI void swEnable(SWstate state);
SWAPI void swDisable(SWstate state);
@@ -540,6 +535,7 @@ SWAPI void swViewport(int x, int y, int width, int height);
SWAPI void swScissor(int x, int y, int width, int height);
SWAPI void swClearColor(float r, float g, float b, float a);
+SWAPI void swClearDepth(float depth);
SWAPI void swClear(uint32_t bitmask);
SWAPI void swBlendFunc(SWfactor sfactor, SWfactor dfactor);
@@ -587,11 +583,12 @@ SWAPI void swTexCoord2fv(const float *v);
SWAPI void swBindArray(SWarray type, void *buffer);
SWAPI void swDrawArrays(SWdraw mode, int offset, int count);
+SWAPI void swDrawElements(SWdraw mode, int count, int type, const void *indices);
SWAPI void swGenTextures(int count, uint32_t *textures);
SWAPI void swDeleteTextures(int count, uint32_t *textures);
-SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void *data);
+SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data);
SWAPI void swTexParameteri(int param, int value);
SWAPI void swBindTexture(uint32_t id);
@@ -605,21 +602,182 @@ SWAPI void swBindTexture(uint32_t id);
#define RLSW_IMPLEMENTATION
#if defined(RLSW_IMPLEMENTATION)
-#include
-#include
-#include // Required for: floorf(), fabsf()
+#include // Required for: malloc(), free()
+#include // Required for: NULL, size_t, uint8_t, uint16_t, uint32_t...
+#include // Required for: sinf(), cosf(), floorf(), fabsf(), sqrtf(), roundf()
+
+// Simple log system to avoid printf() calls if required
+// NOTE: Avoiding those calls, also avoids const strings memory usage
+#define SW_SUPPORT_LOG_INFO
+#if defined(SW_SUPPORT_LOG_INFO) //&& defined(_DEBUG) // WARNING: LOG() output required for this tool
+ #include
+ #define SW_LOG(...) printf(__VA_ARGS__)
+#else
+ #define SW_LOG(...)
+#endif
+
+#if defined(_MSC_VER)
+ #define SW_ALIGN(x) __declspec(align(x))
+#elif defined(__GNUC__) || defined(__clang__)
+ #define SW_ALIGN(x) __attribute__((aligned(x)))
+#else
+ #define SW_ALIGN(x) // Do nothing if not available
+#endif
+
+#if defined(_M_X64) || defined(__x86_64__)
+ #define SW_ARCH_X86_64
+#elif defined(_M_IX86) || defined(__i386__)
+ #define SW_ARCH_X86
+#elif defined(_M_ARM) || defined(__arm__)
+ #define SW_ARCH_ARM32
+#elif defined(_M_ARM64) || defined(__aarch64__)
+ #define SW_ARCH_ARM64
+#elif defined(__riscv)
+ #define SW_ARCH_RISCV
+#endif
+
+// Check for SIMD vector instructions
+#if defined(__FMA__) && defined(__AVX2__)
+ #define SW_HAS_FMA_AVX2
+ #include
+#endif
+#if defined(__FMA__) && defined(__AVX__)
+ #define SW_HAS_FMA_AVX
+ #include
+#endif
+#if defined(__AVX2__)
+ #define SW_HAS_AVX2
+ #include
+#endif
+#if defined(__AVX__)
+ #define SW_HAS_AVX
+ #include
+#endif
+#if defined(__SSE4_2__)
+ #define SW_HAS_SSE42
+ #include
+#endif
+#if defined(__SSE4_1__)
+ #define SW_HAS_SSE41
+ #include
+#endif
+#if defined(__SSSE3__)
+ #define SW_HAS_SSSE3
+ #include
+#endif
+#if defined(__SSE3__)
+ #define SW_HAS_SSE3
+ #include
+#endif
+#if defined(__SSE2__) || (defined(_M_AMD64) || defined(_M_X64)) // SSE2 x64
+ #define SW_HAS_SSE2
+ #include
+#endif
+#if defined(__SSE__)
+ #define SW_HAS_SSE
+ #include
+#endif
+#if defined(__ARM_NEON) || defined(__aarch64__)
+ #if defined(__ARM_FEATURE_FMA)
+ #define SW_HAS_NEON_FMA
+ #else
+ #define SW_HAS_NEON
+ #endif
+ #include
+#endif
+#if defined(__riscv_vector)
+ #define SW_HAS_RVV
+ #include
+#endif
+
+#ifdef __cplusplus
+ #define SW_CURLY_INIT(name) name
+#else
+ #define SW_CURLY_INIT(name) (name)
+#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define SW_PI 3.14159265358979323846f
+#define SW_INV_255 0.00392156862745098f // 1.0f/255.0f
#define SW_DEG2RAD (SW_PI/180.0f)
#define SW_RAD2DEG (180.0f/SW_PI)
-#define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS/8)
-#define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS/8)
+#define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS >> 3)
+#define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS >> 3)
+#define SW_PIXEL_SIZE (SW_COLOR_PIXEL_SIZE + SW_DEPTH_PIXEL_SIZE)
-#define SW_STATE_CHECK(flags) ((RLSW.stateFlags & (flags)) == (flags))
+#if (SW_PIXEL_SIZE <= 4)
+ #define SW_PIXEL_ALIGNMENT 4
+#else // if (SW_PIXEL_SIZE <= 8)
+ #define SW_PIXEL_ALIGNMENT 8
+#endif
+
+#if (SW_COLOR_BUFFER_BITS == 8)
+ #define SW_COLOR_TYPE uint8_t
+ #define SW_COLOR_IS_PACKED 1
+ #define SW_COLOR_PACK_COMP 1
+ #define SW_PACK_COLOR(r,g,b) ((((uint8_t)((r)*7+0.5f))&0x07)<<5 | (((uint8_t)((g)*7+0.5f))&0x07)<<2 | ((uint8_t)((b)*3+0.5f))&0x03)
+ #define SW_UNPACK_R(p) (((p)>>5)&0x07)
+ #define SW_UNPACK_G(p) (((p)>>2)&0x07)
+ #define SW_UNPACK_B(p) ((p)&0x03)
+ #define SW_SCALE_R(v) ((v)*255+3)/7
+ #define SW_SCALE_G(v) ((v)*255+3)/7
+ #define SW_SCALE_B(v) ((v)*255+1)/3
+ #define SW_TO_FLOAT_R(v) ((v)*(1.0f/7.0f))
+ #define SW_TO_FLOAT_G(v) ((v)*(1.0f/7.0f))
+ #define SW_TO_FLOAT_B(v) ((v)*(1.0f/3.0f))
+#elif (SW_COLOR_BUFFER_BITS == 16)
+ #define SW_COLOR_TYPE uint16_t
+ #define SW_COLOR_IS_PACKED 1
+ #define SW_COLOR_PACK_COMP 1
+ #define SW_PACK_COLOR(r,g,b) ((((uint16_t)((r)*31+0.5f))&0x1F)<<11 | (((uint16_t)((g)*63+0.5f))&0x3F)<<5 | ((uint16_t)((b)*31+0.5f))&0x1F)
+ #define SW_UNPACK_R(p) (((p)>>11)&0x1F)
+ #define SW_UNPACK_G(p) (((p)>>5)&0x3F)
+ #define SW_UNPACK_B(p) ((p)&0x1F)
+ #define SW_SCALE_R(v) ((v)*255+15)/31
+ #define SW_SCALE_G(v) ((v)*255+31)/63
+ #define SW_SCALE_B(v) ((v)*255+15)/31
+ #define SW_TO_FLOAT_R(v) ((v)*(1.0f/31.0f))
+ #define SW_TO_FLOAT_G(v) ((v)*(1.0f/63.0f))
+ #define SW_TO_FLOAT_B(v) ((v)*(1.0f/31.0f))
+#else // 32 bits
+ #define SW_COLOR_TYPE uint8_t
+ #define SW_COLOR_IS_PACKED 0
+ #define SW_COLOR_PACK_COMP 4
+#endif
+
+#if (SW_DEPTH_BUFFER_BITS == 16)
+ #define SW_DEPTH_TYPE uint16_t
+ #define SW_DEPTH_IS_PACKED 1
+ #define SW_DEPTH_PACK_COMP 1
+ #define SW_DEPTH_MAX UINT16_MAX
+ #define SW_DEPTH_SCALE (1.0f/UINT16_MAX)
+ #define SW_PACK_DEPTH(d) ((SW_DEPTH_TYPE)((d)*SW_DEPTH_MAX))
+ #define SW_UNPACK_DEPTH(p) (p)
+#elif (SW_DEPTH_BUFFER_BITS == 24)
+ #define SW_DEPTH_TYPE uint8_t
+ #define SW_DEPTH_IS_PACKED 0
+ #define SW_DEPTH_PACK_COMP 3
+ #define SW_DEPTH_MAX 0xFFFFFFU
+ #define SW_DEPTH_SCALE (1.0f/0xFFFFFFU)
+ #define SW_PACK_DEPTH_0(d) ((uint8_t)(((uint32_t)((d)*SW_DEPTH_MAX)>>16)&0xFFU))
+ #define SW_PACK_DEPTH_1(d) ((uint8_t)(((uint32_t)((d)*SW_DEPTH_MAX)>>8)&0xFFU))
+ #define SW_PACK_DEPTH_2(d) ((uint8_t)((uint32_t)((d)*SW_DEPTH_MAX)&0xFFU))
+ #define SW_UNPACK_DEPTH(p) ((((uint32_t)(p)[0]<<16)|((uint32_t)(p)[1]<<8)|(uint32_t)(p)[2]))
+#else // 32 bits
+ #define SW_DEPTH_TYPE float
+ #define SW_DEPTH_IS_PACKED 1
+ #define SW_DEPTH_PACK_COMP 1
+ #define SW_DEPTH_MAX 1.0f
+ #define SW_DEPTH_SCALE 1.0f
+ #define SW_PACK_DEPTH(d) ((SW_DEPTH_TYPE)(d))
+ #define SW_UNPACK_DEPTH(p) (p)
+#endif
+
+#define SW_STATE_CHECK(flags) (SW_STATE_CHECK_EX(RLSW.stateFlags, (flags)))
+#define SW_STATE_CHECK_EX(state, flags) (((state) & (flags)) == (flags))
#define SW_STATE_SCISSOR_TEST (1 << 0)
#define SW_STATE_TEXTURE_2D (1 << 1)
@@ -668,16 +826,10 @@ typedef struct {
} sw_vertex_t;
typedef struct {
- // Dirty hack for copied data
- // TODO: Rework copied image handling
- union {
- const void *cptr; // NOTE: Is used for all data reads
- void *ptr; // WARNING: Should only be used to allocate and free data
- } pixels;
+ uint8_t *pixels; // Texture pixels (RGBA32)
int width, height; // Dimensions of the texture
int wMinus1, hMinus1; // Dimensions minus one
- sw_pixelformat_t format; // Pixel format (internal representation)
SWfilter minFilter; // Minification filter
SWfilter magFilter; // Magnification filter
@@ -687,14 +839,19 @@ typedef struct {
float tx; // Texel width
float ty; // Texel height
-
- bool copy; // Flag indicating whether memory has been allocated
-
} sw_texture_t;
+// Pixel data type
+typedef SW_ALIGN(SW_PIXEL_ALIGNMENT) struct {
+ SW_COLOR_TYPE color[SW_COLOR_PACK_COMP];
+ SW_DEPTH_TYPE depth[SW_DEPTH_PACK_COMP];
+#if (SW_PIXEL_SIZE % SW_PIXEL_ALIGNMENT != 0)
+ uint8_t padding[SW_PIXEL_ALIGNMENT - SW_PIXEL_SIZE % SW_PIXEL_ALIGNMENT];
+#endif
+} sw_pixel_t;
+
typedef struct {
- void *color;
- void *depth;
+ sw_pixel_t *pixels;
int width;
int height;
int allocSz;
@@ -702,11 +859,10 @@ typedef struct {
typedef struct {
sw_framebuffer_t framebuffer; // Main framebuffer
- float clearColor[4]; // Color used to clear the screen
- float clearDepth; // Depth value used to clear the screen
+ sw_pixel_t clearValue; // Clear value of the framebuffer
- int vpCenter[2]; // Viewport center
- int vpHalfSize[2]; // Viewport half dimensions
+ float vpCenter[2]; // Viewport center
+ float vpHalf[2]; // Viewport half dimensions
int vpSize[2]; // Viewport dimensions (minus one)
int vpMin[2]; // Viewport minimum renderable point (top-left)
int vpMax[2]; // Viewport maximum renderable point (bottom-right)
@@ -765,7 +921,6 @@ typedef struct {
int freeTextureIdCount;
uint32_t stateFlags;
-
} sw_context_t;
//----------------------------------------------------------------------------------
@@ -850,11 +1005,7 @@ static inline int sw_clampi(int v, int min, int max)
return v;
}
-static inline void sw_lerp_vertex_PTCH(
- sw_vertex_t *SW_RESTRICT out,
- const sw_vertex_t *SW_RESTRICT a,
- const sw_vertex_t *SW_RESTRICT b,
- float t)
+static inline void sw_lerp_vertex_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t)
{
const float tInv = 1.0f - t;
@@ -881,11 +1032,7 @@ static inline void sw_lerp_vertex_PTCH(
out->homogeneous[3] = a->homogeneous[3]*tInv + b->homogeneous[3]*t;
}
-static inline void sw_get_vertex_grad_PTCH(
- sw_vertex_t *SW_RESTRICT out,
- const sw_vertex_t *SW_RESTRICT a,
- const sw_vertex_t *SW_RESTRICT b,
- float scale)
+static inline void sw_get_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale)
{
// Calculate gradients for Position
out->position[0] = (b->position[0] - a->position[0])*scale;
@@ -910,9 +1057,7 @@ static inline void sw_get_vertex_grad_PTCH(
out->homogeneous[3] = (b->homogeneous[3] - a->homogeneous[3])*scale;
}
-static inline void sw_add_vertex_grad_PTCH(
- sw_vertex_t *SW_RESTRICT out,
- const sw_vertex_t *SW_RESTRICT gradients)
+static inline void sw_add_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients)
{
// Add gradients to Position
out->position[0] += gradients->position[0];
@@ -937,8 +1082,130 @@ static inline void sw_add_vertex_grad_PTCH(
out->homogeneous[3] += gradients->homogeneous[3];
}
-// Half floating point management functions
-static inline uint32_t sw_f16_to_f32_ui(uint16_t h)
+static inline void sw_add_vertex_grad_scaled_PTCH(
+ sw_vertex_t *SW_RESTRICT out,
+ const sw_vertex_t *SW_RESTRICT gradients,
+ float scale)
+{
+ // Add gradients to Position
+ out->position[0] += gradients->position[0]*scale;
+ out->position[1] += gradients->position[1]*scale;
+ out->position[2] += gradients->position[2]*scale;
+ out->position[3] += gradients->position[3]*scale;
+
+ // Add gradients to Texture coordinates
+ out->texcoord[0] += gradients->texcoord[0]*scale;
+ out->texcoord[1] += gradients->texcoord[1]*scale;
+
+ // Add gradients to Color
+ out->color[0] += gradients->color[0]*scale;
+ out->color[1] += gradients->color[1]*scale;
+ out->color[2] += gradients->color[2]*scale;
+ out->color[3] += gradients->color[3]*scale;
+
+ // Add gradients to Homogeneous coordinates
+ out->homogeneous[0] += gradients->homogeneous[0]*scale;
+ out->homogeneous[1] += gradients->homogeneous[1]*scale;
+ out->homogeneous[2] += gradients->homogeneous[2]*scale;
+ out->homogeneous[3] += gradients->homogeneous[3]*scale;
+}
+
+static inline void sw_float_to_unorm8_simd(uint8_t dst[4], const float src[4])
+{
+#if defined(SW_HAS_NEON)
+ float32x4_t values = vld1q_f32(src);
+ float32x4_t scaled = vmulq_n_f32(values, 255.0f);
+ int32x4_t clamped_s32 = vcvtq_s32_f32(scaled); // f32 -> s32 (truncated)
+ int16x4_t narrow16_s = vqmovn_s32(clamped_s32);
+ int16x8_t combined16_s = vcombine_s16(narrow16_s, narrow16_s);
+ uint8x8_t narrow8_u = vqmovun_s16(combined16_s);
+ vst1_lane_u32((uint32_t*)dst, vreinterpret_u32_u8(narrow8_u), 0);
+#elif defined(SW_HAS_SSE41)
+ __m128 values = _mm_loadu_ps(src);
+ __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f));
+ __m128i clamped = _mm_cvtps_epi32(scaled); // f32 -> s32 (truncated)
+ clamped = _mm_packus_epi32(clamped, clamped); // s32 -> u16 (saturated < 0 to 0)
+ clamped = _mm_packus_epi16(clamped, clamped); // u16 -> u8 (saturated > 255 to 255)
+ *(uint32_t*)dst = _mm_cvtsi128_si32(clamped);
+#elif defined(SW_HAS_SSE2)
+ __m128 values = _mm_loadu_ps(src);
+ __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f));
+ __m128i clamped = _mm_cvtps_epi32(scaled); // f32 -> s32 (truncated)
+ clamped = _mm_packs_epi32(clamped, clamped); // s32 -> s16 (saturated)
+ clamped = _mm_packus_epi16(clamped, clamped); // s16 -> u8 (saturated < 0 to 0)
+ *(uint32_t*)dst = _mm_cvtsi128_si32(clamped);
+#elif defined(SW_HAS_RVV)
+ // TODO: Sample code generated by AI, needs testing and review
+ size_t vl = vsetvl_e32m1(4); // Load up to 4 floats into a vector register
+ vfloat32m1_t vsrc = vle32_v_f32m1(src, vl); // Load float32 values
+
+ // Clamp to [0.0f, 1.0f]
+ vfloat32m1_t vzero = vfmv_v_f_f32m1(0.0f, vl);
+ vfloat32m1_t vone = vfmv_v_f_f32m1(1.0f, vl);
+ vsrc = vfmin_vv_f32m1(vsrc, vone, vl);
+ vsrc = vfmax_vv_f32m1(vsrc, vzero, vl);
+
+ // Multiply by 255.0f and add 0.5f for rounding
+ vfloat32m1_t vscaled = vfmul_vf_f32m1(vsrc, 255.0f, vl);
+ vscaled = vfadd_vf_f32m1(vscaled, 0.5f, vl);
+
+ // Convert to unsigned integer (truncate toward zero)
+ vuint32m1_t vu32 = vfcvt_xu_f_v_u32m1(vscaled, vl);
+
+ // Narrow from u32 -> u8
+ vuint8m1_t vu8 = vnclipu_wx_u8m1(vu32, 0, vl); // Round toward zero
+ vse8_v_u8m1(dst, vu8, vl); // Store result
+#else
+ for (int i = 0; i < 4; i++)
+ {
+ float val = src[i]*255.0f;
+ val = (val > 255.0f)? 255.0f : val;
+ val = (val < 0.0f)? 0.0f : val;
+ dst[i] = (uint8_t)val;
+ }
+#endif
+}
+
+static inline void sw_float_from_unorm8_simd(float dst[4], const uint8_t src[4])
+{
+#if defined(SW_HAS_NEON)
+ uint8x8_t bytes8 = vld1_u8(src); //< Read 8 bytes, faster, but let's hope we're not at the end of the page (unlikely)...
+ uint16x8_t bytes16 = vmovl_u8(bytes8);
+ uint32x4_t ints = vmovl_u16(vget_low_u16(bytes16));
+ float32x4_t floats = vcvtq_f32_u32(ints);
+ floats = vmulq_n_f32(floats, SW_INV_255);
+ vst1q_f32(dst, floats);
+#elif defined(SW_HAS_SSE41)
+ __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t *)src);
+ __m128i ints = _mm_cvtepu8_epi32(bytes);
+ __m128 floats = _mm_cvtepi32_ps(ints);
+ floats = _mm_mul_ps(floats, _mm_set1_ps(SW_INV_255));
+ _mm_storeu_ps(dst, floats);
+#elif defined(SW_HAS_SSE2)
+ __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t *)src);
+ bytes = _mm_unpacklo_epi8(bytes, _mm_setzero_si128());
+ __m128i ints = _mm_unpacklo_epi16(bytes, _mm_setzero_si128());
+ __m128 floats = _mm_cvtepi32_ps(ints);
+ floats = _mm_mul_ps(floats, _mm_set1_ps(SW_INV_255));
+ _mm_storeu_ps(dst, floats);
+#elif defined(SW_HAS_RVV)
+ // TODO: Sample code generated by AI, needs testing and review
+ size_t vl = vsetvl_e8m1(4); // Set vector length for 8-bit input elements
+ vuint8m1_t vsrc_u8 = vle8_v_u8m1(src, vl); // Load 4 unsigned 8-bit integers
+ vuint32m1_t vsrc_u32 = vwcvt_xu_u_v_u32m1(vsrc_u8, vl); // Widen to 32-bit unsigned integers
+ vfloat32m1_t vsrc_f32 = vfcvt_f_xu_v_f32m1(vsrc_u32, vl); // Convert to float32
+ vfloat32m1_t vnorm = vfmul_vf_f32m1(vsrc_f32, SW_INV_255, vl); // Multiply by 1/255.0 to normalize
+ vse32_v_f32m1(dst, vnorm, vl); // Store result
+#else
+ dst[0] = (float)src[0]*SW_INV_255;
+ dst[1] = (float)src[1]*SW_INV_255;
+ dst[2] = (float)src[2]*SW_INV_255;
+ dst[3] = (float)src[3]*SW_INV_255;
+#endif
+}
+
+// Half conversion functions
+static inline uint32_t sw_half_to_float_ui(uint16_t h)
{
uint32_t s = (uint32_t)(h & 0x8000) << 16;
int32_t em = h & 0x7fff;
@@ -956,14 +1223,14 @@ static inline uint32_t sw_f16_to_f32_ui(uint16_t h)
return s | r;
}
-static inline float sw_f16_to_f32(sw_half_t y)
+static inline float sw_half_to_float(sw_half_t y)
{
- union { float f; uint32_t i; } v = { .i = sw_f16_to_f32_ui(y) };
+ union { float f; uint32_t i; } v = { .i = sw_half_to_float_ui(y) };
return v.f;
}
-static inline uint16_t sw_f16_from_f32_ui(uint32_t ui)
+static inline uint16_t sw_half_from_float_ui(uint32_t ui)
{
int32_t s = (ui >> 16) & 0x8000;
int32_t em = ui & 0x7fffffff;
@@ -983,23 +1250,21 @@ static inline uint16_t sw_f16_from_f32_ui(uint32_t ui)
return (uint16_t)(s | h);
}
-static inline sw_half_t sw_f16_from_f32(float i)
+static inline sw_half_t sw_half_from_float(float i)
{
union { float f; uint32_t i; } v;
v.f = i;
- return sw_f16_from_f32_ui(v.i);
+ return sw_half_from_float_ui(v.i);
}
// Framebuffer management functions
+//-------------------------------------------------------------------------------------------
static inline bool sw_framebuffer_load(int w, int h)
{
int size = w*h;
- RLSW.framebuffer.color = SW_MALLOC(SW_COLOR_PIXEL_SIZE*size);
- if (RLSW.framebuffer.color == NULL) return false;
-
- RLSW.framebuffer.depth = SW_MALLOC(SW_DEPTH_PIXEL_SIZE*size);
- if (RLSW.framebuffer.depth == NULL) return false;
+ RLSW.framebuffer.pixels = SW_MALLOC(sizeof(sw_pixel_t)*size);
+ if (RLSW.framebuffer.pixels == NULL) return false;
RLSW.framebuffer.width = w;
RLSW.framebuffer.height = h;
@@ -1019,14 +1284,10 @@ static inline bool sw_framebuffer_resize(int w, int h)
return true;
}
- void *newColor = SW_REALLOC(RLSW.framebuffer.color, newSize);
- if (newColor == NULL) return false;
+ void *newPixels = SW_REALLOC(RLSW.framebuffer.pixels, sizeof(sw_pixel_t)*newSize);
+ if (newPixels == NULL) return false;
- void *newDepth = SW_REALLOC(RLSW.framebuffer.depth, newSize);
- if (newDepth == NULL) return false;
-
- RLSW.framebuffer.color = newColor;
- RLSW.framebuffer.depth = newDepth;
+ RLSW.framebuffer.pixels = newPixels;
RLSW.framebuffer.width = w;
RLSW.framebuffer.height = h;
@@ -1035,481 +1296,175 @@ static inline bool sw_framebuffer_resize(int w, int h)
return true;
}
-static inline void *sw_framebuffer_get_color_addr(const void *ptr, uint32_t offset)
+static inline void sw_framebuffer_read_color(float dst[4], const sw_pixel_t *src)
{
- return (uint8_t *)ptr + offset*SW_COLOR_PIXEL_SIZE;
-}
-
-static inline void sw_framebuffer_inc_color_addr(void **ptr)
-{
- *ptr = (void *)(((uint8_t *)*ptr) + SW_COLOR_PIXEL_SIZE);
-}
-
-static inline void sw_framebuffer_inc_const_color_addr(const void **ptr)
-{
- *ptr = (const void *)(((const uint8_t *)*ptr) + SW_COLOR_PIXEL_SIZE);
-}
-
-static inline void *sw_framebuffer_get_depth_addr(const void *ptr, uint32_t offset)
-{
- return (uint8_t *)ptr + offset*SW_DEPTH_PIXEL_SIZE;
-}
-
-static inline void sw_framebuffer_inc_depth_addr(void* *ptr)
-{
- *ptr = (void*)(((uint8_t *)*ptr) + SW_DEPTH_PIXEL_SIZE);
-}
-
-#if (SW_COLOR_BUFFER_BITS == 8) // RGB - (3:3:2)
-static inline void sw_framebuffer_read_color(float dst[4], const void *src)
-{
- uint8_t pixel = ((uint8_t *)src)[0];
-
- dst[0] = ((pixel >> 5) & 0x07)*(1.0f/7.0f);
- dst[1] = ((pixel >> 2) & 0x07)*(1.0f/7.0f);
- dst[2] = (pixel & 0x03)*(1.0f/3.0f);
+#if SW_COLOR_IS_PACKED
+ SW_COLOR_TYPE pixel = src->color[0];
+ dst[0] = SW_TO_FLOAT_R(SW_UNPACK_R(pixel));
+ dst[1] = SW_TO_FLOAT_G(SW_UNPACK_G(pixel));
+ dst[2] = SW_TO_FLOAT_B(SW_UNPACK_B(pixel));
dst[3] = 1.0f;
+#else
+ sw_float_from_unorm8_simd(dst, src->color);
+#endif
}
-static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src)
+static inline void sw_framebuffer_read_color8(uint8_t dst[4], const sw_pixel_t *src)
{
- uint8_t pixel = ((const uint8_t *)src)[0];
-
- uint8_t r = (pixel >> 5) & 0x07;
- uint8_t g = (pixel >> 2) & 0x07;
- uint8_t b = pixel & 0x03;
-
- dst[0] = (r*255 + 3)/7;
- dst[1] = (g*255 + 3)/7;
- dst[2] = (b*255 + 1)/3;
+#if SW_COLOR_IS_PACKED
+ SW_COLOR_TYPE pixel = src->color[0];
+ dst[0] = SW_SCALE_R(SW_UNPACK_R(pixel));
+ dst[1] = SW_SCALE_G(SW_UNPACK_G(pixel));
+ dst[2] = SW_SCALE_B(SW_UNPACK_B(pixel));
dst[3] = 255;
+#else
+ const SW_COLOR_TYPE *p = src->color;
+ dst[0] = p[0];
+ dst[1] = p[1];
+ dst[2] = p[2];
+ dst[3] = p[3];
+#endif
}
-static inline void sw_framebuffer_write_color(void *dst, const float color[3])
+static inline float sw_framebuffer_read_depth(const sw_pixel_t *src)
{
- uint8_t r = ((uint8_t)(color[0]*UINT8_MAX) >> 5) & 0x07;
- uint8_t g = ((uint8_t)(color[1]*UINT8_MAX) >> 5) & 0x07;
- uint8_t b = ((uint8_t)(color[2]*UINT8_MAX) >> 6) & 0x03;
-
- ((uint8_t *)dst)[0] = (r << 5) | (g << 2) | b;
+#if SW_DEPTH_IS_PACKED
+ return src->depth[0]*SW_DEPTH_SCALE;
+#else
+ return SW_UNPACK_DEPTH(src->depth)*SW_DEPTH_SCALE;
+#endif
}
-static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3])
+static inline void sw_framebuffer_write_color(sw_pixel_t *dst, const float src[4])
{
- uint8_t r8 = (uint8_t)(color[0]*7.0f + 0.5f);
- uint8_t g8 = (uint8_t)(color[1]*7.0f + 0.5f);
- uint8_t b8 = (uint8_t)(color[2]*3.0f + 0.5f);
+#if SW_COLOR_IS_PACKED
+ dst->color[0] = SW_PACK_COLOR(src[0], src[1], src[2]);
+#else
+ sw_float_to_unorm8_simd(dst->color, src);
+#endif
+}
- uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03);
+static inline void sw_framebuffer_write_depth(sw_pixel_t *dst, float depth)
+{
+ depth = sw_saturate(depth); // REVIEW: An overflow can occur in certain circumstances with clipping, and needs to be reviewed...
- uint8_t *p = (uint8_t *)ptr;
+#if SW_DEPTH_IS_PACKED
+ dst->depth[0] = SW_PACK_DEPTH(depth);
+#else
+ dst->depth[0] = SW_PACK_DEPTH_0(depth);
+ dst->depth[1] = SW_PACK_DEPTH_1(depth);
+ dst->depth[2] = SW_PACK_DEPTH_2(depth);
+#endif
+}
+static inline void sw_framebuffer_fill_color(sw_pixel_t *ptr, int size, const SW_COLOR_TYPE color[SW_COLOR_PACK_COMP])
+{
if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
{
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
+ int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
{
- uint8_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = packedColor;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = packedColor;
- }
-}
-
-#elif (SW_COLOR_BUFFER_BITS == 16) // RGB - (5:6:5)
-
-static inline void sw_framebuffer_read_color(float dst[4], const void *src)
-{
- uint16_t pixel = ((uint16_t *)src)[0];
-
- dst[0] = ((pixel >> 11) & 0x1F)*(1.0f/31.0f);
- dst[1] = ((pixel >> 5) & 0x3F)*(1.0f/63.0f);
- dst[2] = (pixel & 0x1F)*(1.0f/31.0f);
- dst[3] = 1.0f;
-}
-
-static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src)
-{
- uint16_t pixel = ((const uint16_t *)src)[0];
-
- uint8_t r = (pixel >> 11) & 0x1F;
- uint8_t g = (pixel >> 5) & 0x3F;
- uint8_t b = pixel & 0x1F;
-
- dst[0] = (r*255 + 15)/31;
- dst[1] = (g*255 + 31)/63;
- dst[2] = (b*255 + 15)/31;
- dst[3] = 255;
-}
-
-static inline void sw_framebuffer_write_color(void *dst, const float color[3])
-{
- uint8_t r = (uint8_t)(color[0]*31.0f + 0.5f) & 0x1F;
- uint8_t g = (uint8_t)(color[1]*63.0f + 0.5f) & 0x3F;
- uint8_t b = (uint8_t)(color[2]*31.0f + 0.5f) & 0x1F;
-
- ((uint16_t *)dst)[0] = (r << 11) | (g << 5) | b;
-}
-
-static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3])
-{
- uint16_t r16 = (uint16_t)(color[0]*31.0f + 0.5f);
- uint16_t g_16 = (uint16_t)(color[1]*63.0f + 0.5f);
- uint16_t b_16 = (uint16_t)(color[2]*31.0f + 0.5f);
-
- uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g_16 & 0x3F) << 5) | (b_16 & 0x1F);
-
- uint16_t *p = (uint16_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint16_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = packedColor;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = packedColor;
- }
-}
-
-#elif (SW_COLOR_BUFFER_BITS == 24) // RGB - (8:8:8)
-
-static inline void sw_framebuffer_read_color(float dst[4], const void *src)
-{
- dst[0] = ((uint8_t *)src)[0]*(1.0f/255.0f);
- dst[1] = ((uint8_t *)src)[1]*(1.0f/255.0f);
- dst[2] = ((uint8_t *)src)[2]*(1.0f/255.0f);
- dst[3] = 1.0f;
-}
-
-static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src)
-{
- dst[0] = ((uint8_t *)src)[0];
- dst[1] = ((uint8_t *)src)[1];
- dst[2] = ((uint8_t *)src)[2];
- dst[3] = 255;
-}
-
-static inline void sw_framebuffer_write_color(void *dst, const float color[3])
-{
- ((uint8_t *)dst)[0] = (uint8_t)(color[0]*UINT8_MAX);
- ((uint8_t *)dst)[1] = (uint8_t)(color[1]*UINT8_MAX);
- ((uint8_t *)dst)[2] = (uint8_t)(color[2]*UINT8_MAX);
-}
-
-static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3])
-{
- uint8_t r = (uint8_t)(color[0]*255.0f);
- uint8_t g = (uint8_t)(color[1]*255.0f);
- uint8_t b = (uint8_t)(color[2]*255.0f);
-
- uint8_t *p = (uint8_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint8_t *curPtr = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]);
- for (int xCount = 0; xCount < wScissor; xCount++)
+ sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0];
+ for (int x = 0; x < w; x++, row++)
{
- *curPtr++ = r;
- *curPtr++ = g;
- *curPtr++ = b;
+ for (int i = 0; i < SW_COLOR_PACK_COMP; i++) row->color[i] = color[i];
}
}
}
else
{
+ for (int i = 0; i < size; i++, ptr++)
+ {
+ for (int j = 0; j < SW_COLOR_PACK_COMP; j++) ptr->color[j] = color[j];
+ }
+ }
+}
+
+static inline void sw_framebuffer_fill_depth(sw_pixel_t *ptr, int size, const SW_DEPTH_TYPE depth[SW_DEPTH_PACK_COMP])
+{
+ if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
+ {
+ int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
+ for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
+ {
+ sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0];
+ for (int x = 0; x < w; x++, row++)
+ {
+ for (int i = 0; i < SW_DEPTH_PACK_COMP; i++) row->depth[i] = depth[i];
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < size; i++, ptr++)
+ {
+ for (int j = 0; j < SW_DEPTH_PACK_COMP; j++) ptr->depth[j] = depth[j];
+ }
+ }
+}
+
+static inline void sw_framebuffer_fill(sw_pixel_t *ptr, int size, sw_pixel_t value)
+{
+ if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
+ {
+ int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
+ for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
+ {
+ sw_pixel_t *row = ptr + y*RLSW.framebuffer.width + RLSW.scMin[0];
+ for (int x = 0; x < w; x++, row++) *row = value;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < size; i++, ptr++) *ptr = value;
+ }
+}
+
+static inline void sw_framebuffer_copy_fast(void* dst)
+{
+ int size = RLSW.framebuffer.width*RLSW.framebuffer.height;
+ const sw_pixel_t *pixels = RLSW.framebuffer.pixels;
+
+#if SW_COLOR_BUFFER_BITS == 8
+ uint8_t *dst8 = (uint8_t*)dst;
+ for (int i = 0; i < size; i++) dst8[i] = pixels[i].color[0];
+#elif SW_COLOR_BUFFER_BITS == 16
+ uint16_t *dst16 = (uint16_t*)dst;
+ for (int i = 0; i < size; i++) dst16[i] = *(uint16_t*)pixels[i].color;
+#else // 32 bits
+ uint32_t *dst32 = (uint32_t*)dst;
+ #if SW_GL_FRAMEBUFFER_COPY_BGRA
for (int i = 0; i < size; i++)
{
- *p++ = r;
- *p++ = g;
- *p++ = b;
+ const uint8_t *c = pixels[i].color;
+ dst32[i] = (uint32_t)c[2] | ((uint32_t)c[1] << 8) | ((uint32_t)c[0] << 16) | ((uint32_t)c[3] << 24);
}
- }
-}
-
-#endif // SW_COLOR_BUFFER_BITS
-
-#if (SW_DEPTH_BUFFER_BITS == 8)
-
-static inline float sw_framebuffer_read_depth(const void *src)
-{
- return (float)((uint8_t *)src)[0]*(1.0f/UINT8_MAX);
-}
-
-static inline void sw_framebuffer_write_depth(void *dst, float depth)
-{
- ((uint8_t *)dst)[0] = (uint8_t)(depth*UINT8_MAX);
-}
-
-static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value)
-{
- uint8_t d8 = (uint8_t)(value*UINT8_MAX);
- uint8_t *p = (uint8_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint8_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = d8;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = d8;
- }
-}
-
-#elif (SW_DEPTH_BUFFER_BITS == 16)
-
-static inline float sw_framebuffer_read_depth(const void *src)
-{
- return (float)((uint16_t *)src)[0]*(1.0f/UINT16_MAX);
-}
-
-static inline void sw_framebuffer_write_depth(void *dst, float depth)
-{
- ((uint16_t *)dst)[0] = (uint16_t)(depth*UINT16_MAX);
-}
-
-static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value)
-{
- uint16_t d16 = (uint16_t)(value*UINT16_MAX);
- uint16_t *p = (uint16_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint16_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = d16;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = d16;
- }
-}
-
-#elif (SW_DEPTH_BUFFER_BITS == 24)
-
-static inline float sw_framebuffer_read_depth(const void *src)
-{
- uint32_t depth24 = (((uint8_t *)src)[0] << 16) |
- (((uint8_t *)src)[1] << 8) |
- ((uint8_t *)src)[2];
-
- return depth24/(float)0xFFFFFF;
-}
-
-static inline void sw_framebuffer_write_depth(void *dst, float depth)
-{
- uint32_t depth24 = (uint32_t)(depth*0xFFFFFF);
-
- ((uint8_t *)dst)[0] = (depth24 >> 16) & 0xFF;
- ((uint8_t *)dst)[1] = (depth24 >> 8) & 0xFF;
- ((uint8_t *)dst)[2] = depth24 & 0xFF;
-}
-
-static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value)
-{
- uint32_t d32 = (uint32_t)(value*UINT32_MAX);
- uint8_t d_byte0 = (uint8_t)((d32 >> 16) & 0xFF);
- uint8_t d_byte1 = (uint8_t)((d32 >> 8) & 0xFF);
- uint8_t d_byte2 = (uint8_t)(d32 & 0xFF);
-
- uint8_t *p = (uint8_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint8_t *curPtr = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]);
- for (int xCount = 0; xCount < wScissor; xCount++)
- {
- *curPtr++ = d_byte0;
- *curPtr++ = d_byte1;
- *curPtr++ = d_byte2;
- }
- }
- }
- else
- {
- for (int i = 0; i < size; i++)
- {
- *p++ = d_byte0;
- *p++ = d_byte1;
- *p++ = d_byte2;
- }
- }
-}
-
-#endif // SW_DEPTH_BUFFER_BITS
-
-static inline void sw_framebuffer_fill(void *colorPtr, void *depthPtr, int size, float color[4], float depth_value)
-{
-#if (SW_COLOR_BUFFER_BITS == 8)
- // Calculate and pack 3:3:2 color
- // Scale color components to the max value for each bit depth and round
- uint8_t r8 = (uint8_t)(color[0]*7.0f + 0.5f);
- uint8_t g8 = (uint8_t)(color[1]*7.0f + 0.5f);
- uint8_t b8 = (uint8_t)(color[2]*3.0f + 0.5f);
- // Pack the components into a single byte
- uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03);
- uint8_t *cptr = (uint8_t *)colorPtr;
-#elif (SW_COLOR_BUFFER_BITS == 16)
- // Calculate and pack 5:6:5 color
- // Scale color components to the max value for each bit depth and round
- uint16_t r16 = (uint16_t)(color[0]*31.0f + 0.5f);
- uint16_t g16 = (uint16_t)(color[1]*63.0f + 0.5f);
- uint16_t b16 = (uint16_t)(color[2]*31.0f + 0.5f);
- // Pack the components into a 16-bit value
- uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g16 & 0x3F) << 5) | (b16 & 0x1F);
- uint16_t *cptr = (uint16_t *)colorPtr;
-#elif (SW_COLOR_BUFFER_BITS == 24)
- // Calculate 8:8:8 color components
- uint8_t r24 = (uint8_t)(color[0]*255.0f);
- uint8_t g24 = (uint8_t)(color[1]*255.0f);
- uint8_t b24 = (uint8_t)(color[2]*255.0f);
- uint8_t *cptr = (uint8_t *)colorPtr;
-#endif
-
-#if (SW_DEPTH_BUFFER_BITS == 8)
- // Calculate 8-bit depth
- uint8_t d8 = (uint8_t)(depth_value*UINT8_MAX);
- uint8_t *dptr = (uint8_t *)depthPtr;
-#elif (SW_DEPTH_BUFFER_BITS == 16)
- // Calculate 16-bit depth
- uint16_t d16 = (uint16_t)(depth_value*UINT16_MAX);
- uint16_t *dptr = (uint16_t *)depthPtr;
-#elif (SW_DEPTH_BUFFER_BITS == 24)
- // Calculate 24-bit depth and pre-calculate bytes
- uint32_t d32 = (uint32_t)(depth_value*UINT32_MAX);
- uint8_t dByte0 = (uint8_t)((d32 >> 16) & 0xFF);
- uint8_t dByte1 = (uint8_t)((d32 >> 8) & 0xFF);
- uint8_t dByte2 = (uint8_t)(d32 & 0xFF);
- uint8_t *dptr = (uint8_t *)depthPtr;
-#endif
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- int rowStartIdx = y*RLSW.framebuffer.width + RLSW.scMin[0];
-
- // Calculate starting pointers for the current row within the scissor rectangle
- #if (SW_COLOR_BUFFER_BITS == 8)
- uint8_t *curCPtr = cptr + rowStartIdx;
- #elif (SW_COLOR_BUFFER_BITS == 16)
- uint16_t *curCPtr = cptr + rowStartIdx;
- #elif (SW_COLOR_BUFFER_BITS == 24)
- uint8_t *curCPtr = cptr + 3*rowStartIdx;
- #endif
-
- #if (SW_DEPTH_BUFFER_BITS == 8)
- uint8_t *curDPtr = dptr + rowStartIdx;
- #elif (SW_DEPTH_BUFFER_BITS == 16)
- uint16_t *curDPtr = dptr + rowStartIdx;
- #elif (SW_DEPTH_BUFFER_BITS == 24)
- uint8_t *curDPtr = dptr + 3*rowStartIdx;
- #endif
-
- // Fill the current row within the scissor rectangle
- for (int xCount = 0; xCount < wScissor; xCount++)
- {
- // Write color
- #if (SW_COLOR_BUFFER_BITS == 8)
- *curCPtr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 16)
- *curCPtr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 24)
- *curCPtr++ = r24;
- *curCPtr++ = g24;
- *curCPtr++ = b24;
- #endif
-
- // Write depth
- #if (SW_DEPTH_BUFFER_BITS == 8)
- *curDPtr++ = d8;
- #elif (SW_DEPTH_BUFFER_BITS == 16)
- *curDPtr++ = d16;
- #elif (SW_DEPTH_BUFFER_BITS == 24)
- *curDPtr++ = dByte0;
- *curDPtr++ = dByte1;
- *curDPtr++ = dByte2;
- #endif
- }
- }
- return;
- }
-
- for (int i = 0; i < size; i++)
- {
- // Write color
- #if (SW_COLOR_BUFFER_BITS == 8)
- *cptr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 16)
- *cptr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 24)
- *cptr++ = r24;
- *cptr++ = g24;
- *cptr++ = b24;
+ #else // RGBA
+ for (int i = 0; i < size; i++) dst32[i] = *(uint32_t*)pixels[i].color;
#endif
-
- // Write depth
- #if (SW_DEPTH_BUFFER_BITS == 8)
- *dptr++ = d8;
- #elif (SW_DEPTH_BUFFER_BITS == 16)
- *dptr++ = d16;
- #elif (SW_DEPTH_BUFFER_BITS == 24)
- *dptr++ = dByte0;
- *dptr++ = dByte1;
- *dptr++ = dByte2;
- #endif
- }
+#endif
}
-#define DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(name, DST_PTR_T) \
-static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \
+#define DEFINE_FRAMEBUFFER_COPY_BEGIN(name, DST_PTR_T) \
+static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \
{ \
- const void *src = RLSW.framebuffer.color; \
+ const int stride = RLSW.framebuffer.width; \
+ const sw_pixel_t *src = RLSW.framebuffer.pixels + (y*stride + x); \
\
- for (int iy = y; iy < h; iy++) { \
- for (int ix = x; ix < w; ix++) { \
+ for (int iy = 0; iy < h; iy++) { \
+ const sw_pixel_t *line = src; \
+ for (int ix = 0; ix < w; ix++) { \
uint8_t color[4]; \
- sw_framebuffer_read_color8(color, src); \
-
-#define DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(name, DST_PTR_T) \
-static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \
-{ \
- const void *src = RLSW.framebuffer.color; \
- \
- for (int iy = y; iy < h; iy++) { \
- for (int ix = x; ix < w; ix++) { \
- float color[4]; \
- sw_framebuffer_read_color(color, src); \
+ sw_framebuffer_read_color8(color, line); \
#define DEFINE_FRAMEBUFFER_COPY_END() \
- sw_framebuffer_inc_const_color_addr(&src); \
+ ++line; \
} \
+ src += stride; \
} \
}
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYSCALE, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYSCALE, uint8_t)
{
// NTSC grayscale conversion: Y = 0.299R + 0.587G + 0.114B
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
@@ -1517,7 +1472,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYSCALE, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYALPHA, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYALPHA, uint8_t)
{
// Convert RGB to grayscale using NTSC formula
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
@@ -1529,7 +1484,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYALPHA, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G6B5, uint16_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G6B5, uint16_t)
{
// Convert 8-bit RGB to 5:6:5 format
uint8_t r5 = (color[0]*31 + 127)/255;
@@ -1546,7 +1501,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G6B5, uint16_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1562,7 +1517,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G5B5A1, uint16_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G5B5A1, uint16_t)
{
uint8_t r5 = (color[0]*31 + 127)/255;
uint8_t g5 = (color[1]*31 + 127)/255;
@@ -1579,7 +1534,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G5B5A1, uint16_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R4G4B4A4, uint16_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R4G4B4A4, uint16_t)
{
uint8_t r4 = (color[0]*15 + 127)/255;
uint8_t g4 = (color[1]*15 + 127)/255;
@@ -1596,7 +1551,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R4G4B4A4, uint16_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8A8, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8A8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1613,145 +1568,44 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8A8, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32, float)
-{
- dst[0] = color[0];
- dst++;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32G32B32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32G32B32A32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
- dst[3] = color[3];
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16, sw_half_t)
-{
- dst[0] = sw_f16_from_f32(color[0]);
- dst++;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16G16B16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16G16B16A16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
- dst[3] = sw_f16_from_f32(color[3]);
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-#define DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(name, DST_PTR_T) \
+#define DEFINE_FRAMEBUFFER_BLIT_BEGIN(name, DST_PTR_T) \
static inline void sw_framebuffer_blit_to_##name( \
int xDst, int yDst, int wDst, int hDst, \
int xSrc, int ySrc, int wSrc, int hSrc, \
DST_PTR_T *dst) \
{ \
- const uint8_t *srcBase = RLSW.framebuffer.color; \
- int fbWidth = RLSW.framebuffer.width; \
+ const sw_pixel_t *srcBase = RLSW.framebuffer.pixels; \
+ const int fbWidth = RLSW.framebuffer.width; \
\
- uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \
- uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \
+ const uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \
+ const uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \
\
for (int dy = 0; dy < hDst; dy++) { \
- uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \
+ uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \
int sy = yFix >> 16; \
+ const sw_pixel_t *srcLine = srcBase + sy*fbWidth + xSrc; \
\
+ const sw_pixel_t *srcPtr = srcLine; \
for (int dx = 0; dx < wDst; dx++) { \
- uint32_t xFix = dx*xScale; \
+ uint32_t xFix = dx*xScale; \
int sx = xFix >> 16; \
- const void *srcPtr = sw_framebuffer_get_color_addr(srcBase, sy*fbWidth + sx); \
+ const sw_pixel_t *pixel = srcPtr + sx; \
uint8_t color[4]; \
- sw_framebuffer_read_color8(color, srcPtr); \
-
-#define DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(name, DST_PTR_T) \
-static inline void sw_framebuffer_blit_to_##name( \
- int xDst, int yDst, int wDst, int hDst, \
- int xSrc, int ySrc, int wSrc, int hSrc, \
- DST_PTR_T *dst) \
-{ \
- const uint8_t *srcBase = RLSW.framebuffer.color; \
- int fbWidth = RLSW.framebuffer.width; \
- \
- uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \
- uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \
- \
- for (int dy = 0; dy < hDst; dy++) { \
- uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \
- int sy = yFix >> 16; \
- \
- for (int dx = 0; dx < wDst; dx++) { \
- uint32_t xFix = dx*xScale; \
- int sx = xFix >> 16; \
- const void *srcPtr = sw_framebuffer_get_color_addr(srcBase, sy*fbWidth + sx); \
- float color[4]; \
- sw_framebuffer_read_color(color, srcPtr); \
+ sw_framebuffer_read_color8(color, pixel);
#define DEFINE_FRAMEBUFFER_BLIT_END() \
} \
} \
}
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYSCALE, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYSCALE, uint8_t)
{
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
*dst++ = gray;
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYALPHA, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYALPHA, uint8_t)
{
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
@@ -1762,7 +1616,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYALPHA, uint8_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G6B5, uint16_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G6B5, uint16_t)
{
uint8_t r5 = (color[0]*31 + 127)/255;
uint8_t g6 = (color[1]*63 + 127)/255;
@@ -1778,7 +1632,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G6B5, uint16_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1794,7 +1648,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8, uint8_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G5B5A1, uint16_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G5B5A1, uint16_t)
{
uint8_t r5 = (color[0]*31 + 127)/255;
uint8_t g5 = (color[1]*31 + 127)/255;
@@ -1811,7 +1665,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G5B5A1, uint16_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R4G4B4A4, uint16_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R4G4B4A4, uint16_t)
{
uint8_t r4 = (color[0]*15 + 127)/255;
uint8_t g4 = (color[1]*15 + 127)/255;
@@ -1828,7 +1682,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R4G4B4A4, uint16_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8A8, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8A8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1844,89 +1698,10 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8A8, uint8_t)
dst += 4;
}
DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32, uint8_t)
-{
- dst[0] = color[0];
- dst++;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32G32B32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32G32B32A32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
- dst[3] = color[3];
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16, sw_half_t)
-{
- dst[0] = sw_f16_from_f32(color[0]);
- dst++;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16A16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
- dst[3] = sw_f16_from_f32(color[3]);
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
+//-------------------------------------------------------------------------------------------
// Pixel format management functions
-
+//-------------------------------------------------------------------------------------------
static inline int sw_get_pixel_format(SWformat format, SWtype type)
{
int channels = 0;
@@ -1979,210 +1754,179 @@ static inline int sw_get_pixel_format(SWformat format, SWtype type)
return SW_PIXELFORMAT_UNKNOWN;
}
-int sw_get_pixel_bytes(sw_pixelformat_t format)
+static inline void sw_get_pixel(uint8_t *color, const void *pixels, uint32_t offset, sw_pixelformat_t format)
{
- int bpp = 0;
-
switch (format)
{
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 1; break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
+ {
+ uint8_t gray = ((const uint8_t*)pixels)[offset];
+ color[0] = gray;
+ color[1] = gray;
+ color[2] = gray;
+ color[3] = 255;
+ break;
+ }
case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+ {
+ const uint8_t *src = &((const uint8_t*)pixels)[offset*2];
+ color[0] = src[0];
+ color[1] = src[0];
+ color[2] = src[0];
+ color[3] = src[1];
+ break;
+ }
case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+ {
+ uint16_t pixel = ((const uint16_t*)pixels)[offset];
+ color[0] = ((pixel >> 11) & 0x1F)*255/31; // R (5 bits)
+ color[1] = ((pixel >> 5) & 0x3F)*255/63; // G (6 bits)
+ color[2] = (pixel & 0x1F)*255/31; // B (5 bits)
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8:
+ {
+ const uint8_t *src = &((const uint8_t*)pixels)[offset*3];
+ color[0] = src[0];
+ color[1] = src[1];
+ color[2] = src[2];
+ color[3] = 255;
+ break;
+ }
case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 2; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 4; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 3; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 4; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 4*3; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 4*4; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: bpp = 2; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 2*3; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 2*4; break;
- default: break;
- }
-
- return bpp;
-}
-
-static inline void sw_get_pixel_grayscale(float *color, const void *pixels, uint32_t offset)
-{
- float gray = (float)((uint8_t *)pixels)[offset]*(1.0f/255);
-
- color[0] = gray;
- color[1] = gray;
- color[2] = gray;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_red_16(float *color, const void *pixels, uint32_t offset)
-{
- float value = sw_f16_to_f32(((sw_half_t *)pixels)[offset]);
-
- color[0] = value;
- color[1] = value;
- color[2] = value;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_red_32(float *color, const void *pixels, uint32_t offset)
-{
- float value = ((float *)pixels)[offset];
-
- color[0] = value;
- color[1] = value;
- color[2] = value;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_grayscale_alpha(float *color, const void *pixels, uint32_t offset)
-{
- const uint8_t *pixelData = (const uint8_t *)pixels + 2*offset;
-
- color[0] = color[1] = color[2] = (float)pixelData[0]*(1.0f/255);
- color[3] = (float)pixelData[1]*(1.0f/255);
-}
-
-static inline void sw_get_pixel_rgb_565(float *color, const void *pixels, uint32_t offset)
-{
- uint16_t pixel = ((uint16_t *)pixels)[offset];
-
- color[0] = (float)((pixel & 0xF800) >> 11)/31;
- color[1] = (float)((pixel & 0x7E0) >> 5)/63;
- color[2] = (float)(pixel & 0x1F)/31;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgb_888(float *color, const void *pixels, uint32_t offset)
-{
- const uint8_t *pixel = (const uint8_t *)pixels + 3*offset;
-
- color[0] = (float)pixel[0]*(1.0f/255);
- color[1] = (float)pixel[1]*(1.0f/255);
- color[2] = (float)pixel[2]*(1.0f/255);
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgb_161616(float *color, const void *pixels, uint32_t offset)
-{
- const sw_half_t *pixel = (sw_half_t *)pixels + 3*offset;
-
- color[0] = sw_f16_to_f32(pixel[0]);
- color[1] = sw_f16_to_f32(pixel[1]);
- color[2] = sw_f16_to_f32(pixel[2]);
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgb_323232(float *color, const void *pixels, uint32_t offset)
-{
- const float *pixel = (float *)pixels + 3*offset;
-
- color[0] = pixel[0];
- color[1] = pixel[1];
- color[2] = pixel[2];
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgba_5551(float *color, const void *pixels, uint32_t offset)
-{
- uint16_t pixel = ((uint16_t *)pixels)[offset];
-
- color[0] = (float)((pixel & 0xF800) >> 11)/31;
- color[1] = (float)((pixel & 0x7C0) >> 6)/31;
- color[2] = (float)((pixel & 0x3E) >> 1)/31;
- color[3] = (float)(pixel & 0x1);
-}
-
-static inline void sw_get_pixel_rgba_4444(float *color, const void *pixels, uint32_t offset)
-{
- uint16_t pixel = ((uint16_t *)pixels)[offset];
-
- color[0] = (float)((pixel & 0xF000) >> 12)/15;
- color[1] = (float)((pixel & 0xF00) >> 8)/15;
- color[2] = (float)((pixel & 0xF0) >> 4)/15;
- color[3] = (float)(pixel & 0xF)/15;
-}
-
-static inline void sw_get_pixel_rgba_8888(float *color, const void *pixels, uint32_t offset)
-{
- const uint8_t *pixel = (uint8_t *)pixels + 4*offset;
-
- color[0] = (float)pixel[0]*(1.0f/255);
- color[1] = (float)pixel[1]*(1.0f/255);
- color[2] = (float)pixel[2]*(1.0f/255);
- color[3] = (float)pixel[3]*(1.0f/255);
-}
-
-static inline void sw_get_pixel_rgba_16161616(float *color, const void *pixels, uint32_t offset)
-{
- const sw_half_t *pixel = (sw_half_t *)pixels + 4*offset;
-
- color[0] = sw_f16_to_f32(pixel[0]);
- color[1] = sw_f16_to_f32(pixel[1]);
- color[2] = sw_f16_to_f32(pixel[2]);
- color[3] = sw_f16_to_f32(pixel[3]);
-}
-
-static inline void sw_get_pixel_rgba_32323232(float *color, const void *pixels, uint32_t offset)
-{
- const float *pixel = (float *)pixels + 4*offset;
-
- color[0] = pixel[0];
- color[1] = pixel[1];
- color[2] = pixel[2];
- color[3] = pixel[3];
-}
-
-static inline void sw_get_pixel(float *color, const void *pixels, uint32_t offset, sw_pixelformat_t format)
-{
- switch (format)
- {
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_get_pixel_grayscale(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_get_pixel_grayscale_alpha(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_get_pixel_rgb_565(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_get_pixel_rgb_888(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_get_pixel_rgba_5551(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_get_pixel_rgba_4444(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_get_pixel_rgba_8888(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_get_pixel_red_32(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_get_pixel_rgb_323232(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_get_pixel_rgba_32323232(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_get_pixel_red_16(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_get_pixel_rgb_161616(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_get_pixel_rgba_16161616(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNKNOWN: break;
- default: break;
+ {
+ uint16_t pixel = ((const uint16_t*)pixels)[offset];
+ color[0] = ((pixel >> 11) & 0x1F)*255/31; // R (5 bits)
+ color[1] = ((pixel >> 6) & 0x1F)*255/31; // G (5 bits)
+ color[2] = ((pixel >> 1) & 0x1F)*255/31; // B (5 bits)
+ color[3] = (pixel & 0x01)*255; // A (1 bit)
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+ {
+ uint16_t pixel = ((const uint16_t*)pixels)[offset];
+ color[0] = ((pixel >> 12) & 0x0F)*255/15; // R (4 bits)
+ color[1] = ((pixel >> 8) & 0x0F)*255/15; // G (4 bits)
+ color[2] = ((pixel >> 4) & 0x0F)*255/15; // B (4 bits)
+ color[3] = (pixel & 0x0F)*255/15; // A (4 bits)
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+ {
+ const uint8_t *src = &((const uint8_t*)pixels)[offset*4];
+ color[0] = src[0];
+ color[1] = src[1];
+ color[2] = src[2];
+ color[3] = src[3];
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32:
+ {
+ float val = ((const float*)pixels)[offset];
+ uint8_t gray = (uint8_t)(val*255.0f);
+ color[0] = gray;
+ color[1] = gray;
+ color[2] = gray;
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+ {
+ const float *src = &((const float*)pixels)[offset*3];
+ color[0] = (uint8_t)(src[0]*255.0f);
+ color[1] = (uint8_t)(src[1]*255.0f);
+ color[2] = (uint8_t)(src[2]*255.0f);
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+ {
+ const float *src = &((const float*)pixels)[offset*4];
+ color[0] = (uint8_t)(src[0]*255.0f);
+ color[1] = (uint8_t)(src[1]*255.0f);
+ color[2] = (uint8_t)(src[2]*255.0f);
+ color[3] = (uint8_t)(src[3]*255.0f);
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16:
+ {
+ uint16_t val = ((const uint16_t*)pixels)[offset];
+ uint8_t gray = sw_half_to_float(val)*SW_INV_255;
+ color[0] = gray;
+ color[1] = gray;
+ color[2] = gray;
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+ {
+ const uint16_t *src = &((const uint16_t*)pixels)[offset*3];
+ color[0] = sw_half_to_float(src[0])*SW_INV_255;
+ color[1] = sw_half_to_float(src[1])*SW_INV_255;
+ color[2] = sw_half_to_float(src[2])*SW_INV_255;
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+ {
+ const uint16_t *src = &((const uint16_t*)pixels)[offset*4];
+ color[0] = sw_half_to_float(src[0])*SW_INV_255;
+ color[1] = sw_half_to_float(src[1])*SW_INV_255;
+ color[2] = sw_half_to_float(src[2])*SW_INV_255;
+ color[3] = sw_half_to_float(src[3])*SW_INV_255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNKNOWN:
+ default:
+ {
+ color[0] = 0;
+ color[1] = 0;
+ color[2] = 0;
+ color[3] = 0;
+ break;
+ }
}
}
+//-------------------------------------------------------------------------------------------
// Texture sampling functionality
+//-------------------------------------------------------------------------------------------
+static inline void sw_texture_fetch(float* color, const sw_texture_t* tex, int x, int y)
+{
+ sw_float_from_unorm8_simd(color, &tex->pixels[4*(y*tex->width + x)]);
+}
static inline void sw_texture_sample_nearest(float *color, const sw_texture_t *tex, float u, float v)
{
u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u);
v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v);
- int x = u*tex->width, y = v*tex->height;
+ int x = u*tex->width;
+ int y = v*tex->height;
- sw_get_pixel(color, tex->pixels.cptr, y*tex->width + x, tex->format);
+ sw_texture_fetch(color, tex, x, y);
}
static inline void sw_texture_sample_linear(float *color, const sw_texture_t *tex, float u, float v)
{
- // TODO: REVIEW: With a bit more cleverness we could clearly reduce the
+ // TODO: With a bit more cleverness we could clearly reduce the
// number of operations here, but for now it works fine.
- float xf = u*tex->width - 0.5f;
- float yf = v*tex->height - 0.5f;
+ float xf = (u*tex->width) - 0.5f;
+ float yf = (v*tex->height) - 0.5f;
- int x0 = (int)floorf(xf);
- int y0 = (int)floorf(yf);
+ float fx = sw_fract(xf);
+ float fy = sw_fract(yf);
- float fx = xf - x0;
- float fy = yf - y0;
+ int x0 = (int)xf;
+ int y0 = (int)yf;
int x1 = x0 + 1;
int y1 = y0 + 1;
+ // NOTE: If the textures are POT we could avoid the division for SW_REPEAT
+
if (tex->sWrap == SW_CLAMP)
{
x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0;
@@ -2206,10 +1950,10 @@ static inline void sw_texture_sample_linear(float *color, const sw_texture_t *te
}
float c00[4], c10[4], c01[4], c11[4];
- sw_get_pixel(c00, tex->pixels.cptr, y0*tex->width + x0, tex->format);
- sw_get_pixel(c10, tex->pixels.cptr, y0*tex->width + x1, tex->format);
- sw_get_pixel(c01, tex->pixels.cptr, y1*tex->width + x0, tex->format);
- sw_get_pixel(c11, tex->pixels.cptr, y1*tex->width + x1, tex->format);
+ sw_texture_fetch(c00, tex, x0, y0);
+ sw_texture_fetch(c10, tex, x1, y0);
+ sw_texture_fetch(c01, tex, x0, y1);
+ sw_texture_fetch(c11, tex, x1, y1);
for (int i = 0; i < 4; i++)
{
@@ -2219,18 +1963,18 @@ static inline void sw_texture_sample_linear(float *color, const sw_texture_t *te
}
}
-static inline void sw_texture_sample(float *color, const sw_texture_t *tex, float u, float v, float duDx, float duDy, float dvDx, float dvDy)
+static inline void sw_texture_sample(float *color, const sw_texture_t *tex, float u, float v, float dUdx, float dUdy, float dVdx, float dVdy)
{
// Previous method: There is no need to compute the square root
// because using the squared value, the comparison remains `L2 > 1.0f*1.0f`
- //float du = sqrtf(duDx*duDx + duDy*duDy);
- //float dv = sqrtf(dvDx*dvDx + dvDy*dvDy);
+ //float du = sqrtf(dUdx*dUdx + dUdy*dUdy);
+ //float dv = sqrtf(dVdx*dVdx + dVdy*dVdy);
//float L = (du > dv)? du : dv;
// Calculate the derivatives for each axis
- float du2 = duDx*duDx + duDy*duDy;
- float dv2 = dvDx*dvDx + dvDy*dvDy;
- float L2 = (du2 > dv2)? du2 : dv2;
+ float dU2 = dUdx*dUdx + dUdy*dUdy;
+ float dV2 = dVdx*dVdx + dVdy*dVdy;
+ float L2 = (dU2 > dV2)? dU2 : dV2;
SWfilter filter = (L2 > 1.0f)? tex->minFilter : tex->magFilter;
@@ -2241,9 +1985,10 @@ static inline void sw_texture_sample(float *color, const sw_texture_t *tex, floa
default: break;
}
}
+//-------------------------------------------------------------------------------------------
-// Color Blending functionality
-
+// Color blending functionality
+//-------------------------------------------------------------------------------------------
static inline void sw_factor_zero(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
{
factor[0] = factor[1] = factor[2] = factor[3] = 0.0f;
@@ -2316,17 +2061,19 @@ static inline void sw_blend_colors(float *SW_RESTRICT dst/*[4]*/, const float *S
dst[2] = srcFactor[2]*src[2] + dstFactor[2]*dst[2];
dst[3] = srcFactor[3]*src[3] + dstFactor[3]*dst[3];
}
+//-------------------------------------------------------------------------------------------
// Projection helper functions
-
+//-------------------------------------------------------------------------------------------
static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4])
{
- screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalfSize[0];
- screen[1] = RLSW.vpCenter[1] - ndc[1]*RLSW.vpHalfSize[1];
+ screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalf[0] + 0.5f;
+ screen[1] = RLSW.vpCenter[1] - ndc[1]*RLSW.vpHalf[1] + 0.5f;
}
+//-------------------------------------------------------------------------------------------
-// Polygon Clipping management
-
+// Polygon clipping management
+//-------------------------------------------------------------------------------------------
#define DEFINE_CLIP_FUNC(name, FUNC_IS_INSIDE, FUNC_COMPUTE_T) \
static inline int sw_clip_##name( \
sw_vertex_t output[SW_MAX_CLIPPED_POLYGON_VERTICES], \
@@ -2358,9 +2105,10 @@ static inline int sw_clip_##name(
\
return outputCount; \
}
+//-------------------------------------------------------------------------------------------
// Frustum cliping functions
-
+//-------------------------------------------------------------------------------------------
#define IS_INSIDE_PLANE_W(h) ((h)[3] >= SW_CLIP_EPSILON)
#define IS_INSIDE_PLANE_X_POS(h) ((h)[0] <= (h)[3])
#define IS_INSIDE_PLANE_X_NEG(h) (-(h)[0] <= (h)[3])
@@ -2384,9 +2132,10 @@ DEFINE_CLIP_FUNC(y_pos, IS_INSIDE_PLANE_Y_POS, COMPUTE_T_PLANE_Y_POS)
DEFINE_CLIP_FUNC(y_neg, IS_INSIDE_PLANE_Y_NEG, COMPUTE_T_PLANE_Y_NEG)
DEFINE_CLIP_FUNC(z_pos, IS_INSIDE_PLANE_Z_POS, COMPUTE_T_PLANE_Z_POS)
DEFINE_CLIP_FUNC(z_neg, IS_INSIDE_PLANE_Z_NEG, COMPUTE_T_PLANE_Z_NEG)
+//-------------------------------------------------------------------------------------------
// Scissor clip functions
-
+//-------------------------------------------------------------------------------------------
#define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMin[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0])*(hPrev)[3])))
#define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMax[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0])*(hPrev)[3])))
#define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMin[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1])*(hPrev)[3])))
@@ -2401,9 +2150,9 @@ DEFINE_CLIP_FUNC(scissor_x_min, IS_INSIDE_SCISSOR_X_MIN, COMPUTE_T_SCISSOR_X_MIN
DEFINE_CLIP_FUNC(scissor_x_max, IS_INSIDE_SCISSOR_X_MAX, COMPUTE_T_SCISSOR_X_MAX)
DEFINE_CLIP_FUNC(scissor_y_min, IS_INSIDE_SCISSOR_Y_MIN, COMPUTE_T_SCISSOR_Y_MIN)
DEFINE_CLIP_FUNC(scissor_y_max, IS_INSIDE_SCISSOR_Y_MAX, COMPUTE_T_SCISSOR_Y_MAX)
+//-------------------------------------------------------------------------------------------
-// Main clip function
-
+// Main polygon clip function
static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int *vertexCounter)
{
static sw_vertex_t tmp[SW_MAX_CLIPPED_POLYGON_VERTICES];
@@ -2443,7 +2192,7 @@ static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VE
}
// Triangle rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_triangle_face_culling(void)
{
// NOTE: Face culling is done before clipping to avoid unnecessary computations.
@@ -2506,23 +2255,23 @@ static inline void sw_triangle_clip_and_project(void)
// Calculation of the reciprocal of W for normalization
// as well as perspective-correct attributes
- const float invW = 1.0f/v->homogeneous[3];
- v->homogeneous[3] = invW;
+ const float wRcp = 1.0f/v->homogeneous[3];
+ v->homogeneous[3] = wRcp;
// Division of XYZ coordinates by weight
- v->homogeneous[0] *= invW;
- v->homogeneous[1] *= invW;
- v->homogeneous[2] *= invW;
+ v->homogeneous[0] *= wRcp;
+ v->homogeneous[1] *= wRcp;
+ v->homogeneous[2] *= wRcp;
// Division of texture coordinates (perspective-correct)
- v->texcoord[0] *= invW;
- v->texcoord[1] *= invW;
+ v->texcoord[0] *= wRcp;
+ v->texcoord[1] *= wRcp;
// Division of colors (perspective-correct)
- v->color[0] *= invW;
- v->color[1] *= invW;
- v->color[2] *= invW;
- v->color[3] *= invW;
+ v->color[0] *= wRcp;
+ v->color[1] *= wRcp;
+ v->color[2] *= wRcp;
+ v->color[3] *= wRcp;
// Transformation to screen space
sw_project_ndc_to_screen(v->screen, v->homogeneous);
@@ -2532,68 +2281,64 @@ static inline void sw_triangle_clip_and_project(void)
#define DEFINE_TRIANGLE_RASTER_SCANLINE(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \
static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start, \
- const sw_vertex_t *end, float duDy, float dvDy) \
+ const sw_vertex_t *end, float dUdy, float dVdy) \
{ \
- /* Convert and center the screen coordinates */ \
- int xStart = (int)(start->screen[0] + 0.5f); \
- int xEnd = (int)(end->screen[0] + 0.5f); \
- int y = (int)start->screen[1]; \
+ /* Gets the start and end coordinates */ \
+ int xStart = (int)start->screen[0]; \
+ int xEnd = (int)end->screen[0]; \
+ \
+ /* Avoid empty lines */ \
+ if (xStart == xEnd) return; \
+ \
+ /* Compute the subpixel distance to traverse before the first pixel */ \
+ float xSubstep = 1.0f - sw_fract(start->screen[0]); \
\
/* Compute the inverse horizontal distance along the X axis */ \
- float dx = end->screen[0] - start->screen[0]; \
- if (fabsf(dx) < 1e-6f) return; \
- float dxRcp = 1.0f/dx; \
+ float dxRcp = 1.0f/(end->screen[0] - start->screen[0]); \
\
/* Compute the interpolation steps along the X axis */ \
- float dzDx = (end->homogeneous[2] - start->homogeneous[2])*dxRcp; \
- float dwDx = (end->homogeneous[3] - start->homogeneous[3])*dxRcp; \
+ float dZdx = (end->homogeneous[2] - start->homogeneous[2])*dxRcp; \
+ float dWdx = (end->homogeneous[3] - start->homogeneous[3])*dxRcp; \
\
- float dcDx[4] = { 0 }; \
- dcDx[0] = (end->color[0] - start->color[0])*dxRcp; \
- dcDx[1] = (end->color[1] - start->color[1])*dxRcp; \
- dcDx[2] = (end->color[2] - start->color[2])*dxRcp; \
- dcDx[3] = (end->color[3] - start->color[3])*dxRcp; \
+ float dCdx[4] = { \
+ (end->color[0] - start->color[0])*dxRcp, \
+ (end->color[1] - start->color[1])*dxRcp, \
+ (end->color[2] - start->color[2])*dxRcp, \
+ (end->color[3] - start->color[3])*dxRcp \
+ }; \
\
- float duDx = 0.0f, dvDx = 0.0f; \
+ float dUdx = 0.0f; \
+ float dVdx = 0.0f; \
if (ENABLE_TEXTURE) { \
- duDx = (end->texcoord[0] - start->texcoord[0])*dxRcp; \
- dvDx = (end->texcoord[1] - start->texcoord[1])*dxRcp; \
+ dUdx = (end->texcoord[0] - start->texcoord[0])*dxRcp; \
+ dVdx = (end->texcoord[1] - start->texcoord[1])*dxRcp; \
} \
\
/* Initializing the interpolation starting values */ \
- float z = start->homogeneous[2]; \
- float w = start->homogeneous[3]; \
+ float z = start->homogeneous[2] + dZdx*xSubstep; \
+ float w = start->homogeneous[3] + dWdx*xSubstep; \
\
- float color[4] = { 0 }; \
- color[0] = start->color[0]; \
- color[1] = start->color[1]; \
- color[2] = start->color[2]; \
- color[3] = start->color[3]; \
+ float color[4] = { \
+ start->color[0] + dCdx[0]*xSubstep, \
+ start->color[1] + dCdx[1]*xSubstep, \
+ start->color[2] + dCdx[2]*xSubstep, \
+ start->color[3] + dCdx[3]*xSubstep \
+ }; \
\
- float u = 0.0f, v = 0.0f; \
+ float u = 0.0f; \
+ float v = 0.0f; \
if (ENABLE_TEXTURE) { \
- u = start->texcoord[0]; \
- v = start->texcoord[1]; \
+ u = start->texcoord[0] + dUdx*xSubstep; \
+ v = start->texcoord[1] + dVdx*xSubstep; \
} \
\
/* Pre-calculate the starting pointers for the framebuffer row */ \
- void *cptr = sw_framebuffer_get_color_addr(RLSW.framebuffer.color, y*RLSW.framebuffer.width + xStart); \
- void *dptr = sw_framebuffer_get_depth_addr(RLSW.framebuffer.depth, y*RLSW.framebuffer.width + xStart); \
+ int y = (int)start->screen[1]; \
+ sw_pixel_t *ptr = RLSW.framebuffer.pixels + y*RLSW.framebuffer.width + xStart; \
\
/* Scanline rasterization */ \
for (int x = xStart; x < xEnd; x++) \
{ \
- /* Test and write depth */ \
- if (ENABLE_DEPTH_TEST) \
- { \
- /* TODO: Implement different depth funcs? */ \
- float depth = sw_framebuffer_read_depth(dptr); \
- if (z > depth) goto discard; \
- } \
- \
- sw_framebuffer_write_depth(dptr, z); \
- \
- /* Pixel color computation */ \
float wRcp = 1.0f/w; \
float srcColor[4] = { \
color[0]*wRcp, \
@@ -2602,12 +2347,22 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start,
color[3]*wRcp \
}; \
\
+ if (ENABLE_DEPTH_TEST) \
+ { \
+ /* TODO: Implement different depth funcs? */ \
+ float depth = sw_framebuffer_read_depth(ptr); \
+ if (z > depth) goto discard; \
+ } \
+ \
+ /* TODO: Implement depth mask */ \
+ sw_framebuffer_write_depth(ptr, z); \
+ \
if (ENABLE_TEXTURE) \
{ \
float texColor[4]; \
float s = u*wRcp; \
float t = v*wRcp; \
- sw_texture_sample(texColor, tex, s, t, duDx, duDy, dvDx, dvDy); \
+ sw_texture_sample(texColor, tex, s, t, dUdx, dUdy, dVdx, dVdy); \
srcColor[0] *= texColor[0]; \
srcColor[1] *= texColor[1]; \
srcColor[2] *= texColor[2]; \
@@ -2617,36 +2372,29 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start,
if (ENABLE_COLOR_BLEND) \
{ \
float dstColor[4]; \
- sw_framebuffer_read_color(dstColor, cptr); \
- \
+ sw_framebuffer_read_color(dstColor, ptr); \
sw_blend_colors(dstColor, srcColor); \
- dstColor[0] = sw_saturate(dstColor[0]); \
- dstColor[1] = sw_saturate(dstColor[1]); \
- dstColor[2] = sw_saturate(dstColor[2]); \
- \
- sw_framebuffer_write_color(cptr, dstColor); \
+ sw_framebuffer_write_color(ptr, dstColor); \
} \
else \
{ \
- sw_framebuffer_write_color(cptr, srcColor); \
+ sw_framebuffer_write_color(ptr, srcColor); \
} \
\
/* Increment the interpolation parameter, UVs, and pointers */ \
discard: \
- z += dzDx; \
- w += dwDx; \
- color[0] += dcDx[0]; \
- color[1] += dcDx[1]; \
- color[2] += dcDx[2]; \
- color[3] += dcDx[3]; \
+ z += dZdx; \
+ w += dWdx; \
+ color[0] += dCdx[0]; \
+ color[1] += dCdx[1]; \
+ color[2] += dCdx[2]; \
+ color[3] += dCdx[3]; \
if (ENABLE_TEXTURE) \
{ \
- u += duDx; \
- v += dvDx; \
+ u += dUdx; \
+ v += dVdx; \
} \
- \
- sw_framebuffer_inc_color_addr(&cptr); \
- sw_framebuffer_inc_depth_addr(&dptr); \
+ ++ptr; \
} \
}
@@ -2672,60 +2420,71 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1,
if (h02 < 1e-6f) return; \
\
/* Precompute the inverse values without additional checks */ \
- float invH02 = 1.0f/h02; \
- float invH01 = (h01 > 1e-6f)? 1.0f/h01 : 0.0f; \
- float invH12 = (h12 > 1e-6f)? 1.0f/h12 : 0.0f; \
+ float h02Rcp = 1.0f/h02; \
+ float h01Rcp = (h01 > 1e-6f)? 1.0f/h01 : 0.0f; \
+ float h12Rcp = (h12 > 1e-6f)? 1.0f/h12 : 0.0f; \
\
/* Pre-calculation of slopes */ \
- float dx02 = (x2 - x0)*invH02; \
- float dx01 = (x1 - x0)*invH01; \
- float dx12 = (x2 - x1)*invH12; \
+ float dXdy02 = (x2 - x0)*h02Rcp; \
+ float dXdy01 = (x1 - x0)*h01Rcp; \
+ float dXdy12 = (x2 - x1)*h12Rcp; \
+ \
+ /* Y subpixel correction */ \
+ float y0Substep = 1.0f - sw_fract(y0); \
+ float y1Substep = 1.0f - sw_fract(y1); \
\
/* Y bounds (vertical clipping) */ \
- int yTop = (int)(y0 + 0.5f); \
- int yMiddle = (int)(y1 + 0.5f); \
- int yBottom = (int)(y2 + 0.5f); \
+ int yTop = (int)y0; \
+ int yMid = (int)y1; \
+ int yBot = (int)y2; \
\
/* Compute gradients for each side of the triangle */ \
- sw_vertex_t vDy02, vDy01, vDy12; \
- sw_get_vertex_grad_PTCH(&vDy02, v0, v2, invH02); \
- sw_get_vertex_grad_PTCH(&vDy01, v0, v1, invH01); \
- sw_get_vertex_grad_PTCH(&vDy12, v1, v2, invH12); \
+ sw_vertex_t dVXdy02, dVXdy01, dVXdy12; \
+ sw_get_vertex_grad_PTCH(&dVXdy02, v0, v2, h02Rcp); \
+ sw_get_vertex_grad_PTCH(&dVXdy01, v0, v1, h01Rcp); \
+ sw_get_vertex_grad_PTCH(&dVXdy12, v1, v2, h12Rcp); \
\
- /* Initializing scanline variables */ \
- sw_vertex_t vLeft = *v0; \
- vLeft.screen[0] = x0; \
- sw_vertex_t vRight = *v0; \
- vRight.screen[0] = x0; \
+ /* Get a copy of vertices for interpolation and apply substep correction */ \
+ sw_vertex_t vLeft = *v0, vRight = *v0; \
+ sw_add_vertex_grad_scaled_PTCH(&vLeft, &dVXdy02, y0Substep); \
+ sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy01, y0Substep); \
+ \
+ vLeft.screen[0] += dXdy02*y0Substep; \
+ vRight.screen[0] += dXdy01*y0Substep; \
\
/* Scanline for the upper part of the triangle */ \
- for (int y = yTop; y < yMiddle; y++) \
+ for (int y = yTop; y < yMid; y++) \
{ \
vLeft.screen[1] = vRight.screen[1] = y; \
\
- if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, vDy02.texcoord[0], vDy02.texcoord[1]); \
- else FUNC_SCANLINE(tex, &vRight, &vLeft, vDy02.texcoord[0], vDy02.texcoord[1]); \
+ if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
+ else FUNC_SCANLINE(tex, &vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
\
- sw_add_vertex_grad_PTCH(&vLeft, &vDy02); \
- vLeft.screen[0] += dx02; \
- sw_add_vertex_grad_PTCH(&vRight, &vDy01); \
- vRight.screen[0] += dx01; \
+ sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); \
+ vLeft.screen[0] += dXdy02; \
+ \
+ sw_add_vertex_grad_PTCH(&vRight, &dVXdy01); \
+ vRight.screen[0] += dXdy01; \
} \
\
- /* Scanline for the lower part of the triangle */ \
- vRight = *v1, vRight.screen[0] = x1; \
+ /* Get a copy of next right for interpolation and apply substep correction */ \
+ vRight = *v1; \
+ sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy12, y1Substep); \
+ vRight.screen[0] += dXdy12*y1Substep; \
\
- for (int y = yMiddle; y < yBottom; y++) \
+ /* Scanline for the lower part of the triangle */ \
+ for (int y = yMid; y < yBot; y++) \
{ \
vLeft.screen[1] = vRight.screen[1] = y; \
\
- if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, vDy02.texcoord[0], vDy02.texcoord[1]); \
- else FUNC_SCANLINE(tex, &vRight, &vLeft, vDy02.texcoord[0], vDy02.texcoord[1]); \
+ if (vLeft.screen[0] < vRight.screen[0]) FUNC_SCANLINE(tex, &vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
+ else FUNC_SCANLINE(tex, &vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); \
\
- sw_add_vertex_grad_PTCH(&vLeft, &vDy02); \
- vLeft.screen[0] += dx02; \
- sw_add_vertex_grad_PTCH(&vRight, &vDy12); \
- vRight.screen[0] += dx12; \
+ sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); \
+ vLeft.screen[0] += dXdy02; \
+ \
+ sw_add_vertex_grad_PTCH(&vRight, &dVXdy12); \
+ vRight.screen[0] += dXdy12; \
} \
}
@@ -2771,20 +2530,25 @@ static inline void sw_triangle_render(void)
} \
}
- if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
+ uint32_t state = RLSW.stateFlags;
+ if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D;
+ if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND;
+
+ if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
else TRIANGLE_RASTER(sw_triangle_raster)
#undef TRIANGLE_RASTER
}
+//-------------------------------------------------------------------------------------------
// Quad rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_quad_face_culling(void)
{
// NOTE: Face culling is done before clipping to avoid unnecessary computations.
@@ -2853,23 +2617,23 @@ static inline void sw_quad_clip_and_project(void)
// Calculation of the reciprocal of W for normalization
// as well as perspective-correct attributes
- const float invW = 1.0f/v->homogeneous[3];
- v->homogeneous[3] = invW;
+ const float wRcp = 1.0f/v->homogeneous[3];
+ v->homogeneous[3] = wRcp;
// Division of XYZ coordinates by weight
- v->homogeneous[0] *= invW;
- v->homogeneous[1] *= invW;
- v->homogeneous[2] *= invW;
+ v->homogeneous[0] *= wRcp;
+ v->homogeneous[1] *= wRcp;
+ v->homogeneous[2] *= wRcp;
// Division of texture coordinates (perspective-correct)
- v->texcoord[0] *= invW;
- v->texcoord[1] *= invW;
+ v->texcoord[0] *= wRcp;
+ v->texcoord[1] *= wRcp;
// Division of colors (perspective-correct)
- v->color[0] *= invW;
- v->color[1] *= invW;
- v->color[2] *= invW;
- v->color[3] *= invW;
+ v->color[0] *= wRcp;
+ v->color[1] *= wRcp;
+ v->color[2] *= wRcp;
+ v->color[3] *= wRcp;
// Transformation to screen space
sw_project_ndc_to_screen(v->screen, v->homogeneous);
@@ -2879,99 +2643,76 @@ static inline void sw_quad_clip_and_project(void)
static inline bool sw_quad_is_axis_aligned(void)
{
- int horizontal = 0;
- int vertical = 0;
-
+ // Reject quads with perspective projection
+ // The fast path assumes affine (non-perspective) quads,
+ // so we require all vertices to have homogeneous w = 1.0
for (int i = 0; i < 4; i++)
{
if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) return false;
-
- const float *v0 = RLSW.vertexBuffer[i].position;
- const float *v1 = RLSW.vertexBuffer[(i + 1)%4].position;
-
- float dx = v1[0] - v0[0];
- float dy = v1[1] - v0[1];
-
- if (fabsf(dx) > 1e-6f && fabsf(dy) < 1e-6f) horizontal++;
- else if (fabsf(dy) > 1e-6f && fabsf(dx) < 1e-6f) vertical++;
- else return false; // Diagonal edge -> not axis-aligned
}
- return ((horizontal == 2) && (vertical == 2));
+ // Epsilon tolerance in screen space (pixels)
+ const float epsilon = 0.5f;
+
+ // Fetch screen-space positions for the four quad vertices
+ const float *p0 = RLSW.vertexBuffer[0].screen;
+ const float *p1 = RLSW.vertexBuffer[1].screen;
+ const float *p2 = RLSW.vertexBuffer[2].screen;
+ const float *p3 = RLSW.vertexBuffer[3].screen;
+
+ // Compute edge vectors between consecutive vertices
+ // These define the four sides of the quad in screen space
+ float dx01 = p1[0] - p0[0], dy01 = p1[1] - p0[1];
+ float dx12 = p2[0] - p1[0], dy12 = p2[1] - p1[1];
+ float dx23 = p3[0] - p2[0], dy23 = p3[1] - p2[1];
+ float dx30 = p0[0] - p3[0], dy30 = p0[1] - p3[1];
+
+ // Each edge must be either horizontal or vertical within epsilon tolerance
+ // If any edge deviates significantly from either axis, the quad is not axis-aligned
+ if (!((fabsf(dy01) < epsilon) || (fabsf(dx01) < epsilon))) return false;
+ if (!((fabsf(dy12) < epsilon) || (fabsf(dx12) < epsilon))) return false;
+ if (!((fabsf(dy23) < epsilon) || (fabsf(dx23) < epsilon))) return false;
+ if (!((fabsf(dy30) < epsilon) || (fabsf(dx30) < epsilon))) return false;
+
+ return true;
}
static inline void sw_quad_sort_cw(const sw_vertex_t* *output)
{
- // Sort 4 quad vertices into clockwise order with fixed layout:
- //
- // v0 -- v1
- // | |
- // v3 -- v2
- //
- // The goal is:
- // - v0: top-left (minimum Y, then minimum X)
- // - v1: top-right (minimum Y row, maximum X)
- // - v2: bottom-right (maximum Y, maximum X)
- // - v3: bottom-left (maximum Y, minimum X)
const sw_vertex_t *input = RLSW.vertexBuffer;
- // Separate vertices into top and bottom based on Y-coordinate
- const sw_vertex_t *top[2] = {NULL, NULL};
- const sw_vertex_t *bottom[2] = {NULL, NULL};
- int topCount = 0, bottomCount = 0;
+ // Calculate the centroid of the quad
+ float cx = (input[0].screen[0] + input[1].screen[0] +
+ input[2].screen[0] + input[3].screen[0])*0.25f;
+ float cy = (input[0].screen[1] + input[1].screen[1] +
+ input[2].screen[1] + input[3].screen[1])*0.25f;
- // Find minimum and maximum Y
- float minY = input[0].screen[1];
- float maxY = input[0].screen[1];
+ // Calculate the angle of each vertex relative to the center
+ // and assign them directly to their correct position
+ const sw_vertex_t *corners[4] = { 0 };
- for (int i = 1; i < 4; i++)
- {
- if (input[i].screen[1] < minY) minY = input[i].screen[1];
- if (input[i].screen[1] > maxY) maxY = input[i].screen[1];
- }
-
- // Separate vertices based on Y-coordinate
for (int i = 0; i < 4; i++)
{
- if (input[i].screen[1] == minY && topCount < 2) top[topCount++] = &input[i];
- else if (input[i].screen[1] == maxY && bottomCount < 2) bottom[bottomCount++] = &input[i];
+ float dx = input[i].screen[0] - cx;
+ float dy = input[i].screen[1] - cy;
+
+ // Determine the quadrant (clockwise from top-left)
+ // top-left: dx < 0, dy < 0
+ // top-right: dx >= 0, dy < 0
+ // bottom-right: dx >= 0, dy >= 0
+ // bottom-left: dx < 0, dy >= 0
+
+ int idx;
+ if (dy < 0) idx = (dx < 0)? 0 : 1; // Top row
+ else idx = (dx < 0)? 3 : 2; // Bottom row
+
+ corners[idx] = &input[i];
}
- // If we don't have enough top/bottom vertices (e.g., Y values are all different),
- // classify vertices as top or bottom based on whether they're closer to minY or maxY
- for (int i = 0; i < 4; i++)
- {
- if ((topCount < 2) && (&input[i] != top[0]) && (&input[i] != bottom[0]) && (&input[i] != bottom[1]))
- {
- if (fabsf(input[i].screen[1] - minY) <= fabsf(input[i].screen[1] - maxY)) top[topCount++] = &input[i];
- }
- if ((bottomCount < 2) && (&input[i] != top[0]) && (&input[i] != top[1]) && (&input[i] != bottom[0]))
- {
- if (fabsf(input[i].screen[1] - maxY) < fabsf(input[i].screen[1] - minY)) bottom[bottomCount++] = &input[i];
- }
- }
-
- // Sort top vertices by X (left to right)
- if ((topCount == 2) && (top[0]->screen[0] > top[1]->screen[0]))
- {
- const sw_vertex_t *temp = top[0];
- top[0] = top[1];
- top[1] = temp;
- }
-
- // Sort bottom vertices by X (left to right)
- if (bottomCount == 2 && bottom[0]->screen[0] > bottom[1]->screen[0])
- {
- const sw_vertex_t *temp = bottom[0];
- bottom[0] = bottom[1];
- bottom[1] = temp;
- }
-
- // Assign vertices in clockwise order as per the required layout
- output[0] = top[0]; // v0: top-left
- output[1] = top[topCount-1]; // v1: top-right
- output[2] = bottom[bottomCount-1]; // v2: bottom-right
- output[3] = bottom[0]; // v3: bottom-left
+ output[0] = corners[0]; // top-left
+ output[1] = corners[1]; // top-right
+ output[2] = corners[2]; // bottom-right
+ output[3] = corners[3]; // bottom-left
}
// TODO: REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth,
@@ -2989,65 +2730,68 @@ static inline void FUNC_NAME(void)
const sw_vertex_t *v3 = sortedVerts[3]; \
\
/* Screen bounds (axis-aligned) */ \
- int xMin = (int)(v0->screen[0] + 0.5f); \
- int yMin = (int)(v0->screen[1] + 0.5f); \
- int xMax = (int)(v2->screen[0] + 0.5f); \
- int yMax = (int)(v2->screen[1] + 0.5f); \
+ int xMin = (int)v0->screen[0]; \
+ int yMin = (int)v0->screen[1]; \
+ int xMax = (int)v2->screen[0]; \
+ int yMax = (int)v2->screen[1]; \
\
- int width = xMax - xMin; \
- int height = yMax - yMin; \
+ float w = v2->screen[0] - v0->screen[0]; \
+ float h = v2->screen[1] - v0->screen[1]; \
\
- if (width == 0 || height == 0) return; \
+ if ((w == 0) || (h == 0)) return; \
\
- float wRcp = (width > 0.0f)? 1.0f/width : 0.0f; \
- float hRcp = (height > 0.0f)? 1.0f/height : 0.0f; \
+ float wRcp = (w > 0.0f)? 1.0f/w : 0.0f; \
+ float hRcp = (h > 0.0f)? 1.0f/h : 0.0f; \
+ \
+ /* Subpixel corrections */ \
+ float xSubstep = 1.0f - sw_fract(v0->screen[0]); \
+ float ySubstep = 1.0f - sw_fract(v0->screen[1]); \
\
/* Calculation of vertex gradients in X and Y */ \
- float tcDx[2], tcDy[2]; \
+ float dUdx = 0.0f, dVdx = 0.0f; \
+ float dUdy = 0.0f, dVdy = 0.0f; \
if (ENABLE_TEXTURE) { \
- tcDx[0] = (v1->texcoord[0] - v0->texcoord[0])*wRcp; \
- tcDx[1] = (v1->texcoord[1] - v0->texcoord[1])*wRcp; \
- tcDy[0] = (v3->texcoord[0] - v0->texcoord[0])*hRcp; \
- tcDy[1] = (v3->texcoord[1] - v0->texcoord[1])*hRcp; \
+ dUdx = (v1->texcoord[0] - v0->texcoord[0])*wRcp; \
+ dVdx = (v1->texcoord[1] - v0->texcoord[1])*wRcp; \
+ dUdy = (v3->texcoord[0] - v0->texcoord[0])*hRcp; \
+ dVdy = (v3->texcoord[1] - v0->texcoord[1])*hRcp; \
} \
\
- float cDx[4], cDy[4]; \
- cDx[0] = (v1->color[0] - v0->color[0])*wRcp; \
- cDx[1] = (v1->color[1] - v0->color[1])*wRcp; \
- cDx[2] = (v1->color[2] - v0->color[2])*wRcp; \
- cDx[3] = (v1->color[3] - v0->color[3])*wRcp; \
- cDy[0] = (v3->color[0] - v0->color[0])*hRcp; \
- cDy[1] = (v3->color[1] - v0->color[1])*hRcp; \
- cDy[2] = (v3->color[2] - v0->color[2])*hRcp; \
- cDy[3] = (v3->color[3] - v0->color[3])*hRcp; \
+ float dCdx[4], dCdy[4]; \
+ dCdx[0] = (v1->color[0] - v0->color[0])*wRcp; \
+ dCdx[1] = (v1->color[1] - v0->color[1])*wRcp; \
+ dCdx[2] = (v1->color[2] - v0->color[2])*wRcp; \
+ dCdx[3] = (v1->color[3] - v0->color[3])*wRcp; \
+ dCdy[0] = (v3->color[0] - v0->color[0])*hRcp; \
+ dCdy[1] = (v3->color[1] - v0->color[1])*hRcp; \
+ dCdy[2] = (v3->color[2] - v0->color[2])*hRcp; \
+ dCdy[3] = (v3->color[3] - v0->color[3])*hRcp; \
\
- float zDx, zDy; \
- zDx = (v1->homogeneous[2] - v0->homogeneous[2])*wRcp; \
- zDy = (v3->homogeneous[2] - v0->homogeneous[2])*hRcp; \
+ float dZdx, dZdy; \
+ dZdx = (v1->homogeneous[2] - v0->homogeneous[2])*wRcp; \
+ dZdy = (v3->homogeneous[2] - v0->homogeneous[2])*hRcp; \
\
/* Start of quad rasterization */ \
const sw_texture_t *tex; \
if (ENABLE_TEXTURE) tex = &RLSW.loadedTextures[RLSW.currentTexture]; \
\
- void *cDstBase = RLSW.framebuffer.color; \
- void *dDstBase = RLSW.framebuffer.depth; \
+ sw_pixel_t *pixels = RLSW.framebuffer.pixels; \
int wDst = RLSW.framebuffer.width; \
\
- float zScanline = v0->homogeneous[2]; \
- float uScanline = v0->texcoord[0]; \
- float vScanline = v0->texcoord[1]; \
+ float zScanline = v0->homogeneous[2] + dZdx*xSubstep + dZdy*ySubstep; \
+ float uScanline = v0->texcoord[0] + dUdx*xSubstep + dUdy*ySubstep; \
+ float vScanline = v0->texcoord[1] + dVdx*xSubstep + dVdy*ySubstep; \
\
float colorScanline[4] = { \
- v0->color[0], \
- v0->color[1], \
- v0->color[2], \
- v0->color[3] \
+ v0->color[0] + dCdx[0]*xSubstep + dCdy[0]*ySubstep, \
+ v0->color[1] + dCdx[1]*xSubstep + dCdy[1]*ySubstep, \
+ v0->color[2] + dCdx[2]*xSubstep + dCdy[2]*ySubstep, \
+ v0->color[3] + dCdx[3]*xSubstep + dCdy[3]*ySubstep \
}; \
\
for (int y = yMin; y < yMax; y++) \
{ \
- void *cptr = sw_framebuffer_get_color_addr(cDstBase, y*wDst + xMin); \
- void *dptr = sw_framebuffer_get_depth_addr(dDstBase, y*wDst + xMin); \
+ sw_pixel_t *ptr = pixels + y*wDst + xMin; \
\
float z = zScanline; \
float u = uScanline; \
@@ -3063,16 +2807,6 @@ static inline void FUNC_NAME(void)
/* Scanline rasterization */ \
for (int x = xMin; x < xMax; x++) \
{ \
- /* Test and write depth */ \
- if (ENABLE_DEPTH_TEST) \
- { \
- /* TODO: Implement different depth funcs? */ \
- float depth = sw_framebuffer_read_depth(dptr); \
- if (z > depth) goto discard; \
- } \
- \
- sw_framebuffer_write_depth(dptr, z); \
- \
/* Pixel color computation */ \
float srcColor[4] = { \
color[0], \
@@ -3081,10 +2815,21 @@ static inline void FUNC_NAME(void)
color[3] \
}; \
\
+ /* Test and write depth */ \
+ if (ENABLE_DEPTH_TEST) \
+ { \
+ /* TODO: Implement different depth funcs? */ \
+ float depth = sw_framebuffer_read_depth(ptr); \
+ if (z > depth) goto discard; \
+ } \
+ \
+ /* TODO: Implement depth mask */ \
+ sw_framebuffer_write_depth(ptr, z); \
+ \
if (ENABLE_TEXTURE) \
{ \
float texColor[4]; \
- sw_texture_sample(texColor, tex, u, v, tcDx[0], tcDy[0], tcDx[1], tcDy[1]); \
+ sw_texture_sample(texColor, tex, u, v, dUdx, dUdy, dVdx, dVdy); \
srcColor[0] *= texColor[0]; \
srcColor[1] *= texColor[1]; \
srcColor[2] *= texColor[2]; \
@@ -3094,45 +2839,36 @@ static inline void FUNC_NAME(void)
if (ENABLE_COLOR_BLEND) \
{ \
float dstColor[4]; \
- sw_framebuffer_read_color(dstColor, cptr); \
- \
+ sw_framebuffer_read_color(dstColor, ptr); \
sw_blend_colors(dstColor, srcColor); \
- dstColor[0] = sw_saturate(dstColor[0]); \
- dstColor[1] = sw_saturate(dstColor[1]); \
- dstColor[2] = sw_saturate(dstColor[2]); \
- dstColor[3] = sw_saturate(dstColor[3]); \
- \
- sw_framebuffer_write_color(cptr, dstColor); \
+ sw_framebuffer_write_color(ptr, dstColor); \
} \
- else sw_framebuffer_write_color(cptr, srcColor); \
+ else sw_framebuffer_write_color(ptr, srcColor); \
\
discard: \
- z += zDx; \
- color[0] += cDx[0]; \
- color[1] += cDx[1]; \
- color[2] += cDx[2]; \
- color[3] += cDx[3]; \
- \
+ z += dZdx; \
+ color[0] += dCdx[0]; \
+ color[1] += dCdx[1]; \
+ color[2] += dCdx[2]; \
+ color[3] += dCdx[3]; \
if (ENABLE_TEXTURE) \
{ \
- u += tcDx[0]; \
- v += tcDx[1]; \
+ u += dUdx; \
+ v += dVdx; \
} \
- \
- sw_framebuffer_inc_color_addr(&cptr); \
- sw_framebuffer_inc_depth_addr(&dptr); \
+ ++ptr; \
} \
\
- zScanline += zDy; \
- colorScanline[0] += cDy[0]; \
- colorScanline[1] += cDy[1]; \
- colorScanline[2] += cDy[2]; \
- colorScanline[3] += cDy[3]; \
+ zScanline += dZdy; \
+ colorScanline[0] += dCdy[0]; \
+ colorScanline[1] += dCdy[1]; \
+ colorScanline[2] += dCdy[2]; \
+ colorScanline[3] += dCdy[3]; \
\
if (ENABLE_TEXTURE) \
{ \
- uScanline += tcDy[0]; \
- vScanline += tcDy[1]; \
+ uScanline += dUdy; \
+ vScanline += dVdy; \
} \
} \
}
@@ -3157,15 +2893,19 @@ static inline void sw_quad_render(void)
if (RLSW.vertexCounter < 3) return;
- if (RLSW.vertexCounter == 4 && sw_quad_is_axis_aligned())
+ uint32_t state = RLSW.stateFlags;
+ if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D;
+ if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND;
+
+ if ((RLSW.vertexCounter == 4) && sw_quad_is_axis_aligned())
{
- if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_DEPTH_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH();
- else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH();
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX();
+ if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_DEPTH_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX();
else sw_quad_raster_axis_aligned();
return;
}
@@ -3183,20 +2923,21 @@ static inline void sw_quad_render(void)
} \
}
- if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
+ if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
else TRIANGLE_RASTER(sw_triangle_raster)
#undef TRIANGLE_RASTER
}
+//-------------------------------------------------------------------------------------------
// Line rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_line_clip_coord(float q, float p, float *t0, float *t1)
{
if (fabsf(p) < SW_CLIP_EPSILON)
@@ -3295,137 +3036,84 @@ static inline bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1)
#define DEFINE_LINE_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST, ENABLE_COLOR_BLEND) \
static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \
{ \
- int x1 = (int)(v0->screen[0] + 0.5f); \
- int y1 = (int)(v0->screen[1] + 0.5f); \
- int x2 = (int)(v1->screen[0] + 0.5f); \
- int y2 = (int)(v1->screen[1] + 0.5f); \
+ float x0 = v0->screen[0]; \
+ float y0 = v0->screen[1]; \
+ float x1 = v1->screen[0]; \
+ float y1 = v1->screen[1]; \
\
- int dx = x2 - x1; \
- int dy = y2 - y1; \
+ float dx = x1 - x0; \
+ float dy = y1 - y0; \
\
- /* Handling of lines that are more horizontal or vertical */ \
- if (dx == 0 && dy == 0) \
+ /* Compute dominant axis and subpixel offset */ \
+ float steps, substep; \
+ if (fabsf(dx) > fabsf(dy)) \
{ \
- /* TODO: A point should be rendered here */ \
- return; \
- } \
- \
- bool yLonger = (abs(dy) > abs(dx)); \
- int longLen, shortLen; \
- \
- if (yLonger) \
- { \
- longLen = dy; \
- shortLen = dx; \
+ steps = fabsf(dx); \
+ if (steps < 1.0f) return; \
+ substep = (dx >= 0.0f)? (1.0f - sw_fract(x0)) : sw_fract(x0); \
} \
else \
{ \
- longLen = dx; \
- shortLen = dy; \
+ steps = fabsf(dy); \
+ if (steps < 1.0f) return; \
+ substep = (dy >= 0.0f)? (1.0f - sw_fract(y0)) : sw_fract(y0); \
} \
\
- /* Handling of traversal direction */ \
- int sgnInc = (longLen < 0)? -1 : 1; \
- int abslongLen = abs(longLen); \
+ /* Compute per pixel increments */ \
+ float xInc = dx/steps; \
+ float yInc = dy/steps; \
+ float stepRcp = 1.0f/steps; \
\
- /* Calculation of the increment step for the shorter coordinate */ \
- int decInc = 0; \
- if (abslongLen != 0) decInc = (shortLen << 16)/abslongLen; \
+ float zInc = (v1->homogeneous[2] - v0->homogeneous[2])*stepRcp; \
+ float rInc = (v1->color[0] - v0->color[0])*stepRcp; \
+ float gInc = (v1->color[1] - v0->color[1])*stepRcp; \
+ float bInc = (v1->color[2] - v0->color[2])*stepRcp; \
+ float aInc = (v1->color[3] - v0->color[3])*stepRcp; \
\
- float longLenRcp = (abslongLen != 0)? (1.0f/abslongLen) : 0.0f; \
- \
- /* Calculation of interpolation steps */ \
- const float zStep = (v1->homogeneous[2] - v0->homogeneous[2])*longLenRcp; \
- const float rStep = (v1->color[0] - v0->color[0])*longLenRcp; \
- const float gStep = (v1->color[1] - v0->color[1])*longLenRcp; \
- const float bStep = (v1->color[2] - v0->color[2])*longLenRcp; \
- const float aStep = (v1->color[3] - v0->color[3])*longLenRcp; \
- \
- float z = v0->homogeneous[2]; \
- \
- float color[4] = { \
- v0->color[0], \
- v0->color[1], \
- v0->color[2], \
- v0->color[3] \
- }; \
+ /* Initializing the interpolation starting values */ \
+ float x = x0 + xInc*substep; \
+ float y = y0 + yInc*substep; \
+ float z = v0->homogeneous[2] + zInc*substep; \
+ float r = v0->color[0] + rInc*substep; \
+ float g = v0->color[1] + gInc*substep; \
+ float b = v0->color[2] + bInc*substep; \
+ float a = v0->color[3] + aInc*substep; \
\
const int fbWidth = RLSW.framebuffer.width; \
- void *cBuffer = RLSW.framebuffer.color; \
- void *dBuffer = RLSW.framebuffer.depth; \
+ sw_pixel_t *pixels = RLSW.framebuffer.pixels; \
\
- int j = 0; \
- if (yLonger) \
+ int numPixels = (int)(steps - substep) + 1; \
+ \
+ for (int i = 0; i < numPixels; i++) \
{ \
- for (int i = 0; i != longLen; i += sgnInc) \
+ /* REVIEW: May require reviewing projection details */ \
+ int px = (int)(x - 0.5f); \
+ int py = (int)(y - 0.5f); \
+ \
+ sw_pixel_t *ptr = pixels + py*fbWidth + px; \
+ \
+ if (ENABLE_DEPTH_TEST) \
{ \
- int offset = (y1 + i)*fbWidth + (x1 + (j >> 16)); \
- void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \
- \
- if (ENABLE_DEPTH_TEST) \
- { \
- float depth = sw_framebuffer_read_depth(dptr); \
- if (z > depth) goto discardA; \
- } \
- \
- sw_framebuffer_write_depth(dptr, z); \
- \
- void *cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \
- \
- if (ENABLE_COLOR_BLEND) \
- { \
- float dstColor[4]; \
- sw_framebuffer_read_color(dstColor, cptr); \
- \
- sw_blend_colors(dstColor, color); \
- sw_framebuffer_write_color(cptr, dstColor); \
- } \
- else sw_framebuffer_write_color(cptr, color); \
- \
- discardA: \
- j += decInc; \
- z += zStep; \
- color[0] += rStep; \
- color[1] += gStep; \
- color[2] += bStep; \
- color[3] += aStep; \
+ float depth = sw_framebuffer_read_depth(ptr); \
+ if (z > depth) goto discard; \
} \
- } \
- else \
- { \
- for (int i = 0; i != longLen; i += sgnInc) \
+ \
+ sw_framebuffer_write_depth(ptr, z); \
+ \
+ float color[4] = {r, g, b, a}; \
+ \
+ if (ENABLE_COLOR_BLEND) \
{ \
- int offset = (y1 + (j >> 16))*fbWidth + (x1 + i); \
- void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \
- \
- if (ENABLE_DEPTH_TEST) \
- { \
- float depth = sw_framebuffer_read_depth(dptr); \
- if (z > depth) goto discardB; \
- } \
- \
- sw_framebuffer_write_depth(dptr, z); \
- \
- void *cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \
- \
- if (ENABLE_COLOR_BLEND) \
- { \
- float dstColor[4]; \
- sw_framebuffer_read_color(dstColor, cptr); \
- \
- sw_blend_colors(dstColor, color); \
- sw_framebuffer_write_color(cptr, dstColor); \
- } \
- else sw_framebuffer_write_color(cptr, color); \
- \
- discardB: \
- j += decInc; \
- z += zStep; \
- color[0] += rStep; \
- color[1] += gStep; \
- color[2] += bStep; \
- color[3] += aStep; \
+ float dstColor[4]; \
+ sw_framebuffer_read_color(dstColor, ptr); \
+ sw_blend_colors(dstColor, color); \
+ sw_framebuffer_write_color(ptr, dstColor); \
} \
+ else sw_framebuffer_write_color(ptr, color); \
+ \
+ discard: \
+ x += xInc; y += yInc; z += zInc; \
+ r += rInc; g += gInc; b += bInc; a += aInc; \
} \
}
@@ -3444,7 +3132,7 @@ void FUNC_NAME(const sw_vertex_t *v1, const sw_vertex_t *v2) \
\
RASTER_FUNC(v1, v2); \
\
- if (dx != 0 && abs(dy/dx) < 1) \
+ if ((dx != 0) && (abs(dy/dx) < 1)) \
{ \
int wy = (int)((RLSW.lineWidth - 1.0f)*abs(dx)/sqrtf(dx*dx + dy*dy)); \
wy >>= 1; \
@@ -3507,9 +3195,10 @@ static inline void sw_line_render(sw_vertex_t *vertices)
else sw_line_raster(&vertices[0], &vertices[1]);
}
}
+//-------------------------------------------------------------------------------------------
// Point rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_point_clip_and_project(sw_vertex_t *v)
{
if (v->homogeneous[3] != 1.0f)
@@ -3551,38 +3240,34 @@ static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \
{ \
if (CHECK_BOUNDS == 1) \
{ \
- if (x < RLSW.vpMin[0] || x >= RLSW.vpMax[0]) return; \
- if (y < RLSW.vpMin[1] || y >= RLSW.vpMax[1]) return; \
+ if ((x < RLSW.vpMin[0]) || (x >= RLSW.vpMax[0])) return; \
+ if ((y < RLSW.vpMin[1]) || (y >= RLSW.vpMax[1])) return; \
} \
else if (CHECK_BOUNDS == SW_SCISSOR_TEST) \
{ \
- if (x < RLSW.scMin[0] || x >= RLSW.scMax[0]) return; \
- if (y < RLSW.scMin[1] || y >= RLSW.scMax[1]) return; \
+ if ((x < RLSW.scMin[0]) || (x >= RLSW.scMax[0])) return; \
+ if ((y < RLSW.scMin[1]) || (y >= RLSW.scMax[1])) return; \
} \
\
int offset = y*RLSW.framebuffer.width + x; \
- \
- void *dptr = sw_framebuffer_get_depth_addr(RLSW.framebuffer.depth, offset); \
+ sw_pixel_t *ptr = RLSW.framebuffer.pixels + offset; \
\
if (ENABLE_DEPTH_TEST) \
{ \
- float depth = sw_framebuffer_read_depth(dptr); \
+ float depth = sw_framebuffer_read_depth(ptr); \
if (z > depth) return; \
} \
\
- sw_framebuffer_write_depth(dptr, z); \
- \
- void *cptr = sw_framebuffer_get_color_addr(RLSW.framebuffer.color, offset); \
+ sw_framebuffer_write_depth(ptr, z); \
\
if (ENABLE_COLOR_BLEND) \
{ \
float dstColor[4]; \
- sw_framebuffer_read_color(dstColor, cptr); \
- \
+ sw_framebuffer_read_color(dstColor, ptr); \
sw_blend_colors(dstColor, color); \
- sw_framebuffer_write_color(cptr, dstColor); \
+ sw_framebuffer_write_color(ptr, dstColor); \
} \
- else sw_framebuffer_write_color(cptr, color); \
+ else sw_framebuffer_write_color(ptr, color); \
}
#define DEFINE_POINT_THICK_RASTER(FUNC_NAME, RASTER_FUNC) \
@@ -3674,9 +3359,10 @@ static inline void sw_point_render(sw_vertex_t *v)
else sw_point_raster(v->screen[0], v->screen[1], v->homogeneous[2], v->color);
}
}
+//-------------------------------------------------------------------------------------------
-// Polygon modes mendering logic
-
+// Polygon modes rendering logic
+//-------------------------------------------------------------------------------------------
static inline void sw_poly_point_render(void)
{
for (int i = 0; i < RLSW.vertexCounter; i++) sw_point_render(&RLSW.vertexBuffer[i]);
@@ -3687,9 +3373,14 @@ static inline void sw_poly_line_render(void)
const sw_vertex_t *vertices = RLSW.vertexBuffer;
int cm1 = RLSW.vertexCounter - 1;
- for (int i = 0; i < cm1; i++) sw_line_render((sw_vertex_t[2]){ vertices[i], vertices[i + 1] });
+ for (int i = 0; i < cm1; i++)
+ {
+ sw_vertex_t verts[2] = { vertices[i], vertices[i + 1] };
+ sw_line_render(verts);
+ }
- sw_line_render((sw_vertex_t[2]){ vertices[cm1], vertices[0] });
+ sw_vertex_t verts[2] = { vertices[cm1], vertices[0] };
+ sw_line_render(verts);
}
static inline void sw_poly_fill_render(void)
@@ -3702,28 +3393,66 @@ static inline void sw_poly_fill_render(void)
case SW_QUADS: sw_quad_render(); break;
}
}
+//-------------------------------------------------------------------------------------------
+
+// Immediate rendering logic
+//-------------------------------------------------------------------------------------------
+void sw_immediate_push_vertex(const float position[4], const float color[4], const float texcoord[2])
+{
+ // Copy the attributes in the current vertex
+ sw_vertex_t *vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++];
+ for (int i = 0; i < 4; i++)
+ {
+ vertex->position[i] = position[i];
+ if (i < 2) vertex->texcoord[i] = texcoord[i];
+ vertex->color[i] = color[i];
+ }
+
+ // Calculate homogeneous coordinates
+ const float *m = RLSW.matMVP, *v = vertex->position;
+ vertex->homogeneous[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3];
+ vertex->homogeneous[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3];
+ vertex->homogeneous[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3];
+ vertex->homogeneous[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3];
+
+ // Immediate rendering of the primitive if the required number is reached
+ if (RLSW.vertexCounter == RLSW.reqVertices)
+ {
+ switch (RLSW.polyMode)
+ {
+ case SW_FILL: sw_poly_fill_render(); break;
+ case SW_LINE: sw_poly_line_render(); break;
+ case SW_POINT: sw_poly_point_render(); break;
+ default: break;
+ }
+
+ RLSW.vertexCounter = 0;
+ }
+}
+
+//-------------------------------------------------------------------------------------------
// Validity check helper functions
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_is_texture_valid(uint32_t id)
{
bool valid = true;
if (id == 0) valid = false;
else if (id >= SW_MAX_TEXTURES) valid = false;
- else if (RLSW.loadedTextures[id].pixels.cptr == 0) valid = false;
+ else if (RLSW.loadedTextures[id].pixels == NULL) valid = false;
return true;
}
static inline bool sw_is_texture_filter_valid(int filter)
{
- return (filter == SW_NEAREST || filter == SW_LINEAR);
+ return ((filter == SW_NEAREST) || (filter == SW_LINEAR));
}
static inline bool sw_is_texture_wrap_valid(int wrap)
{
- return (wrap == SW_REPEAT || wrap == SW_CLAMP);
+ return ((wrap == SW_REPEAT) || (wrap == SW_CLAMP));
}
static inline bool sw_is_draw_mode_valid(int mode)
@@ -3806,6 +3535,7 @@ static inline bool sw_is_blend_dst_factor_valid(int blend)
return result;
}
+//-------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
// Module Functions Definition
@@ -3817,17 +3547,15 @@ bool swInit(int w, int h)
swViewport(0, 0, w, h);
swScissor(0, 0, w, h);
- RLSW.loadedTextures = SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t));
+ RLSW.loadedTextures = (sw_texture_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t));
if (RLSW.loadedTextures == NULL) { swClose(); return false; }
- RLSW.freeTextureIds = SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t));
+ RLSW.freeTextureIds = (uint32_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t));
if (RLSW.loadedTextures == NULL) { swClose(); return false; }
- RLSW.clearColor[0] = 0.0f;
- RLSW.clearColor[1] = 0.0f;
- RLSW.clearColor[2] = 0.0f;
- RLSW.clearColor[3] = 1.0f;
- RLSW.clearDepth = 1.0f;
+ const float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
+ sw_framebuffer_write_color(&RLSW.clearValue, clearColor);
+ sw_framebuffer_write_depth(&RLSW.clearValue, 1.0f);
RLSW.currentMatrixMode = SW_MODELVIEW;
RLSW.currentMatrix = &RLSW.stackModelview[0];
@@ -3859,46 +3587,63 @@ bool swInit(int w, int h)
RLSW.polyMode = SW_FILL;
RLSW.cullFace = SW_BACK;
- static const float defTex[3*2*2] = {
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f,
+ static uint32_t defaultTex[3*2*2] = {
+ 0xFFFFFFFF,
+ 0xFFFFFFFF,
+ 0xFFFFFFFF,
+ 0xFFFFFFFF
};
- RLSW.loadedTextures[0].pixels.cptr = defTex;
+ RLSW.loadedTextures[0].pixels = (uint8_t*)defaultTex;
RLSW.loadedTextures[0].width = 2;
RLSW.loadedTextures[0].height = 2;
RLSW.loadedTextures[0].wMinus1 = 1;
RLSW.loadedTextures[0].hMinus1 = 1;
- RLSW.loadedTextures[0].format = SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32;
RLSW.loadedTextures[0].minFilter = SW_NEAREST;
RLSW.loadedTextures[0].magFilter = SW_NEAREST;
RLSW.loadedTextures[0].sWrap = SW_REPEAT;
RLSW.loadedTextures[0].tWrap = SW_REPEAT;
RLSW.loadedTextures[0].tx = 0.5f;
RLSW.loadedTextures[0].ty = 0.5f;
- RLSW.loadedTextures[0].copy = false;
RLSW.loadedTextureCount = 1;
+
+ SW_LOG("INFO: RLSW: Software renderer initialized successfully\n");
+#if defined(SW_HAS_FMA_AVX) && defined(SW_HAS_FMA_AVX2)
+ SW_LOG("INFO: RLSW: Using SIMD instructions: FMA AVX\n");
+#endif
+#if defined(SW_HAS_AVX) || defined(SW_HAS_AVX2)
+ SW_LOG("INFO: RLSW: Using SIMD instructions: AVX\n");
+#endif
+#if defined(SW_HAS_SSE) || defined(SW_HAS_SSE2) || defined(SW_HAS_SSE3) || defined(SW_HAS_SSSE3) || defined(SW_HAS_SSE41) || defined(SW_HAS_SSE42)
+ SW_LOG("INFO: RLSW: Using SIMD instructions: SSE\n");
+#endif
+#if defined(SW_HAS_NEON_FMA) || defined(SW_HAS_NEON)
+ SW_LOG("INFO: RLSW: Using SIMD instructions: NEON\n");
+#endif
+#if defined(SW_HAS_RVV)
+ SW_LOG("INFO: RLSW: Using SIMD instructions: RVV\n");
+#endif
return true;
}
void swClose(void)
{
+ // NOTE: Starts at texture 1, texture 0 does not have to be freed
for (int i = 1; i < RLSW.loadedTextureCount; i++)
{
- sw_texture_t *texture = &RLSW.loadedTextures[i];
- if (sw_is_texture_valid(i) && texture->copy) SW_FREE(texture->pixels.ptr);
+ if (sw_is_texture_valid(i))
+ {
+ SW_FREE(RLSW.loadedTextures[i].pixels);
+ }
}
- SW_FREE(RLSW.framebuffer.color);
- SW_FREE(RLSW.framebuffer.depth);
+ SW_FREE(RLSW.framebuffer.pixels);
SW_FREE(RLSW.loadedTextures);
SW_FREE(RLSW.freeTextureIds);
- RLSW = (sw_context_t) { 0 };
+ RLSW = SW_CURLY_INIT(sw_context_t) { 0 };
}
bool swResizeFramebuffer(int w, int h)
@@ -3908,19 +3653,10 @@ bool swResizeFramebuffer(int w, int h)
void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels)
{
- sw_pixelformat_t pFormat = sw_get_pixel_format(format, type);
+ sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type);
- if (w <= 0)
- {
- RLSW.errCode = SW_INVALID_VALUE;
- return;
- }
-
- if (h <= 0)
- {
- RLSW.errCode = SW_INVALID_VALUE;
- return;
- }
+ if (w <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
+ if (h <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
if (w > RLSW.framebuffer.width) w = RLSW.framebuffer.width;
if (h > RLSW.framebuffer.height) h = RLSW.framebuffer.height;
@@ -3928,40 +3664,53 @@ void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type,
x = sw_clampi(x, 0, w);
y = sw_clampi(y, 0, h);
+ if (x >= w || y >= h) return;
+
+ if (x == 0 && y == 0 && w == RLSW.framebuffer.width && h == RLSW.framebuffer.height)
+ {
+ #if SW_COLOR_BUFFER_BITS == 32
+ if (pFormat == SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
+ {
+ sw_framebuffer_copy_fast(pixels);
+ return;
+ }
+ #elif SW_COLOR_BUFFER_BITS == 16
+ if (pFormat == SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5)
+ {
+ sw_framebuffer_copy_fast(pixels);
+ return;
+ }
+ #endif
+ }
+
switch (pFormat)
{
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_copy_to_R32(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_copy_to_R32G32B32(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_copy_to_R32G32B32A32(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_copy_to_R16(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_copy_to_R16G16B16(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_copy_to_R16G16B16A16(x, y, w, h, pixels); break;
- default: RLSW.errCode = SW_INVALID_ENUM; break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, (uint8_t *)pixels); break;
+ // Below: not implemented
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+ default:
+ RLSW.errCode = SW_INVALID_ENUM;
+ break;
}
}
void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels)
{
- sw_pixelformat_t pFormat = sw_get_pixel_format(format, type);
+ sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type);
- if (wSrc <= 0)
- {
- RLSW.errCode = SW_INVALID_VALUE;
- return;
- }
-
- if (hSrc <= 0)
- {
- RLSW.errCode = SW_INVALID_VALUE;
- return;
- }
+ if (wSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
+ if (hSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; }
if (wSrc > RLSW.framebuffer.width) wSrc = RLSW.framebuffer.width;
if (hSrc > RLSW.framebuffer.height) hSrc = RLSW.framebuffer.height;
@@ -3969,33 +3718,35 @@ void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySr
xSrc = sw_clampi(xSrc, 0, wSrc);
ySrc = sw_clampi(ySrc, 0, hSrc);
+ // Check if the sizes are identical after clamping the source to avoid unexpected issues
+ // REVIEW: This repeats the operations if true, so we could make a copy function without these checks
+ if (xDst == xSrc && yDst == ySrc && wDst == wSrc && hDst == hSrc)
+ {
+ swCopyFramebuffer(xSrc, ySrc, wSrc, hSrc, format, type, pixels);
+ }
+
switch (pFormat)
{
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_blit_to_R32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_blit_to_R32G32B32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_blit_to_R32G32B32A32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_blit_to_R16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_blit_to_R16G16B16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_blit_to_R16G16B16A16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- default: RLSW.errCode = SW_INVALID_ENUM; break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ // Below: not implemented
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+ default:
+ RLSW.errCode = SW_INVALID_ENUM;
+ break;
}
}
-void *swGetColorBuffer(int *w, int *h)
-{
- if (w) *w = RLSW.framebuffer.width;
- if (h) *h = RLSW.framebuffer.height;
-
- return RLSW.framebuffer.color;
-}
-
void swEnable(SWstate state)
{
switch (state)
@@ -4039,10 +3790,11 @@ void swGetFloatv(SWget name, float *v)
{
case SW_COLOR_CLEAR_VALUE:
{
- v[0] = RLSW.clearColor[0];
- v[1] = RLSW.clearColor[1];
- v[2] = RLSW.clearColor[2];
- v[3] = RLSW.clearColor[3];
+ sw_framebuffer_read_color(v, &RLSW.clearValue);
+ } break;
+ case SW_DEPTH_CLEAR_VALUE:
+ {
+ v[0] = sw_framebuffer_read_depth(&RLSW.clearValue);
} break;
case SW_CURRENT_COLOR:
{
@@ -4117,11 +3869,11 @@ void swViewport(int x, int y, int width, int height)
RLSW.vpSize[0] = width;
RLSW.vpSize[1] = height;
- RLSW.vpHalfSize[0] = (int)(width/2.0f + 0.5f);
- RLSW.vpHalfSize[1] = (int)(height/2.0f + 0.5f);
+ RLSW.vpHalf[0] = width/2.0f;
+ RLSW.vpHalf[1] = height/2.0f;
- RLSW.vpCenter[0] = x + RLSW.vpHalfSize[0];
- RLSW.vpCenter[1] = y + RLSW.vpHalfSize[1];
+ RLSW.vpCenter[0] = (float)x + RLSW.vpHalf[0];
+ RLSW.vpCenter[1] = (float)y + RLSW.vpHalf[1];
RLSW.vpMin[0] = sw_clampi(x, 0, RLSW.framebuffer.width - 1);
RLSW.vpMin[1] = sw_clampi(y, 0, RLSW.framebuffer.height - 1);
@@ -4150,10 +3902,13 @@ void swScissor(int x, int y, int width, int height)
void swClearColor(float r, float g, float b, float a)
{
- RLSW.clearColor[0] = r;
- RLSW.clearColor[1] = g;
- RLSW.clearColor[2] = b;
- RLSW.clearColor[3] = a;
+ float v[4] = { r, g, b, a };
+ sw_framebuffer_write_color(&RLSW.clearValue, v);
+}
+
+void swClearDepth(float depth)
+{
+ sw_framebuffer_write_depth(&RLSW.clearValue, depth);
}
void swClear(uint32_t bitmask)
@@ -4162,15 +3917,15 @@ void swClear(uint32_t bitmask)
if ((bitmask & (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT)) == (SW_COLOR_BUFFER_BIT | SW_DEPTH_BUFFER_BIT))
{
- sw_framebuffer_fill(RLSW.framebuffer.color, RLSW.framebuffer.depth,size, RLSW.clearColor, RLSW.clearDepth);
+ sw_framebuffer_fill(RLSW.framebuffer.pixels, size, RLSW.clearValue);
}
else if (bitmask & (SW_COLOR_BUFFER_BIT))
{
- sw_framebuffer_fill_color(RLSW.framebuffer.color, size, RLSW.clearColor);
+ sw_framebuffer_fill_color(RLSW.framebuffer.pixels, size, RLSW.clearValue.color);
}
else if (bitmask & SW_DEPTH_BUFFER_BIT)
{
- sw_framebuffer_fill_depth(RLSW.framebuffer.depth, size, RLSW.clearDepth);
+ sw_framebuffer_fill_depth(RLSW.framebuffer.pixels, size, RLSW.clearValue.depth);
}
}
@@ -4392,7 +4147,7 @@ void swRotatef(float angle, float x, float y, float z)
float lengthSq = x*x + y*y + z*z;
- if (lengthSq != 1.0f && lengthSq != 0.0f)
+ if ((lengthSq != 1.0f) && (lengthSq != 0.0f))
{
float invLength = 1.0f/sqrtf(lengthSq);
x *= invLength;
@@ -4553,95 +4308,68 @@ void swBegin(SWdraw mode)
void swEnd(void)
{
- RLSW.drawMode = 0;
+ RLSW.drawMode = (SWdraw)0;
}
void swVertex2i(int x, int y)
{
const float v[4] = { (float)x, (float)y, 0.0f, 1.0f };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex2f(float x, float y)
{
const float v[4] = { x, y, 0.0f, 1.0f };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex2fv(const float *v)
{
const float v4[4] = { v[0], v[1], 0.0f, 1.0f };
- swVertex4fv(v4);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex3i(int x, int y, int z)
{
const float v[4] = { (float)x, (float)y, (float)z, 1.0f };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex3f(float x, float y, float z)
{
const float v[4] = { x, y, z, 1.0f };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex3fv(const float *v)
{
const float v4[4] = { v[0], v[1], v[2], 1.0f };
- swVertex4fv(v4);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex4i(int x, int y, int z, int w)
{
const float v[4] = { (float)x, (float)y, (float)z, (float)w };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex4f(float x, float y, float z, float w)
{
const float v[4] = { x, y, z, w };
- swVertex4fv(v);
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swVertex4fv(const float *v)
{
- // Copy the position in the current vertex
- sw_vertex_t *vertex = &RLSW.vertexBuffer[RLSW.vertexCounter++];
- for (int i = 0; i < 4; i++) vertex->position[i] = v[i];
-
- // Copy additonal vertex data
- for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.current.texcoord[i];
- for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.current.color[i];
-
- // Calculation of homogeneous coordinates
- const float *m = RLSW.matMVP;
- vertex->homogeneous[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3];
- vertex->homogeneous[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3];
- vertex->homogeneous[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3];
- vertex->homogeneous[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3];
-
- // Immediate rendering of the primitive if the required number is reached
- if (RLSW.vertexCounter == RLSW.reqVertices)
- {
- switch (RLSW.polyMode)
- {
- case SW_FILL: sw_poly_fill_render(); break;
- case SW_LINE: sw_poly_line_render(); break;
- case SW_POINT: sw_poly_point_render(); break;
- default: break;
- }
-
- RLSW.vertexCounter = 0;
- }
+ sw_immediate_push_vertex(v, RLSW.current.color, RLSW.current.texcoord);
}
void swColor3ub(uint8_t r, uint8_t g, uint8_t b)
{
float cv[4];
- cv[0] = (float)r/255;
- cv[1] = (float)g/255;
- cv[2] = (float)b/255;
+ cv[0] = (float)r*SW_INV_255;
+ cv[1] = (float)g*SW_INV_255;
+ cv[2] = (float)b*SW_INV_255;
cv[3] = 1.0f;
swColor4fv(cv);
@@ -4650,9 +4378,9 @@ void swColor3ub(uint8_t r, uint8_t g, uint8_t b)
void swColor3ubv(const uint8_t *v)
{
float cv[4];
- cv[0] = (float)v[0]/255;
- cv[1] = (float)v[1]/255;
- cv[2] = (float)v[2]/255;
+ cv[0] = (float)v[0]*SW_INV_255;
+ cv[1] = (float)v[1]*SW_INV_255;
+ cv[2] = (float)v[2]*SW_INV_255;
cv[3] = 1.0f;
swColor4fv(cv);
@@ -4683,10 +4411,10 @@ void swColor3fv(const float *v)
void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
float cv[4];
- cv[0] = (float)r/255;
- cv[1] = (float)g/255;
- cv[2] = (float)b/255;
- cv[3] = (float)a/255;
+ cv[0] = (float)r*SW_INV_255;
+ cv[1] = (float)g*SW_INV_255;
+ cv[2] = (float)b*SW_INV_255;
+ cv[3] = (float)a*SW_INV_255;
swColor4fv(cv);
}
@@ -4694,10 +4422,10 @@ void swColor4ub(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
void swColor4ubv(const uint8_t *v)
{
float cv[4];
- cv[0] = (float)v[0]/255;
- cv[1] = (float)v[1]/255;
- cv[2] = (float)v[2]/255;
- cv[3] = (float)v[3]/255;
+ cv[0] = (float)v[0]*SW_INV_255;
+ cv[1] = (float)v[1]*SW_INV_255;
+ cv[2] = (float)v[2]*SW_INV_255;
+ cv[3] = (float)v[3]*SW_INV_255;
swColor4fv(cv);
}
@@ -4738,9 +4466,9 @@ void swBindArray(SWarray type, void *buffer)
{
switch (type)
{
- case SW_VERTEX_ARRAY: RLSW.array.positions = buffer; break;
- case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = buffer; break;
- case SW_COLOR_ARRAY: RLSW.array.colors = buffer; break;
+ case SW_VERTEX_ARRAY: RLSW.array.positions = (float *)buffer; break;
+ case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = (float *)buffer; break;
+ case SW_COLOR_ARRAY: RLSW.array.colors = (uint8_t *)buffer; break;
default: break;
}
}
@@ -4755,14 +4483,156 @@ void swDrawArrays(SWdraw mode, int offset, int count)
swBegin(mode);
{
- swTexCoord2f(0.0f, 0.0f);
- swColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ const float *texMatrix = RLSW.stackTexture[RLSW.stackTextureCounter - 1];
+ const float *defaultTexcoord = RLSW.current.texcoord;
+ const float *defaultColor = RLSW.current.color;
+
+ const float *positions = RLSW.array.positions;
+ const float *texcoords = RLSW.array.texcoords;
+ const uint8_t *colors = RLSW.array.colors;
- for (int i = offset; i < count; i++)
+ int end = offset + count;
+
+ for (int i = offset; i < end; i++)
{
- if (RLSW.array.texcoords) swTexCoord2fv(RLSW.array.texcoords + 2*i);
- if (RLSW.array.colors) swColor4ubv(RLSW.array.colors + 4*i);
- swVertex3fv(RLSW.array.positions + 3*i);
+ float u, v;
+ if (texcoords)
+ {
+ int idx = 2*i;
+ u = texcoords[idx];
+ v = texcoords[idx + 1];
+ }
+ else
+ {
+ u = defaultTexcoord[0];
+ v = defaultTexcoord[1];
+ }
+
+ float texcoord[2];
+ texcoord[0] = texMatrix[0]*u + texMatrix[4]*v + texMatrix[12];
+ texcoord[1] = texMatrix[1]*u + texMatrix[5]*v + texMatrix[13];
+
+ float color[4] = {
+ defaultColor[0],
+ defaultColor[1],
+ defaultColor[2],
+ defaultColor[3]
+ };
+
+ if (colors)
+ {
+ int idx = 4*i;
+ color[0] *= (float)colors[idx]*SW_INV_255;
+ color[1] *= (float)colors[idx + 1]*SW_INV_255;
+ color[2] *= (float)colors[idx + 2]*SW_INV_255;
+ color[3] *= (float)colors[idx + 3]*SW_INV_255;
+ }
+
+ int idx = 3*i;
+ float position[4] = {
+ positions[idx],
+ positions[idx + 1],
+ positions[idx + 2],
+ 1.0f
+ };
+
+ sw_immediate_push_vertex(position, color, texcoord);
+ }
+ }
+ swEnd();
+}
+
+void swDrawElements(SWdraw mode, int count, int type, const void *indices)
+{
+ if (RLSW.array.positions == 0)
+ {
+ RLSW.errCode = SW_INVALID_OPERATION;
+ return;
+ }
+
+ if (count < 0)
+ {
+ RLSW.errCode = SW_INVALID_VALUE;
+ return;
+ }
+
+ const uint8_t *indicesUb = NULL;
+ const uint16_t *indicesUs = NULL;
+ const uint32_t *indicesUi = NULL;
+
+ switch (type)
+ {
+ case SW_UNSIGNED_BYTE:
+ indicesUb = (const uint8_t *)indices;
+ break;
+ case SW_UNSIGNED_SHORT:
+ indicesUs = (const uint16_t *)indices;
+ break;
+ case SW_UNSIGNED_INT:
+ indicesUi = (const uint32_t *)indices;
+ break;
+ default:
+ RLSW.errCode = SW_INVALID_ENUM;
+ return;
+ }
+
+ swBegin(mode);
+ {
+ const float *texMatrix = RLSW.stackTexture[RLSW.stackTextureCounter - 1];
+ const float *defaultTexcoord = RLSW.current.texcoord;
+ const float *defaultColor = RLSW.current.color;
+
+ const float *positions = RLSW.array.positions;
+ const float *texcoords = RLSW.array.texcoords;
+ const uint8_t *colors = RLSW.array.colors;
+
+ for (int i = 0; i < count; i++)
+ {
+ int index = indicesUb ? indicesUb[i] :
+ (indicesUs ? indicesUs[i] : indicesUi[i]);
+
+ float u, v;
+ if (texcoords)
+ {
+ int idx = 2*index;
+ u = texcoords[idx];
+ v = texcoords[idx + 1];
+ }
+ else
+ {
+ u = defaultTexcoord[0];
+ v = defaultTexcoord[1];
+ }
+
+ float texcoord[2];
+ texcoord[0] = texMatrix[0]*u + texMatrix[4]*v + texMatrix[12];
+ texcoord[1] = texMatrix[1]*u + texMatrix[5]*v + texMatrix[13];
+
+ float color[4] = {
+ defaultColor[0],
+ defaultColor[1],
+ defaultColor[2],
+ defaultColor[3]
+ };
+
+ if (colors)
+ {
+ int idx = 4*index;
+ color[0] *= (float)colors[idx]*SW_INV_255;
+ color[1] *= (float)colors[idx + 1]*SW_INV_255;
+ color[2] *= (float)colors[idx + 2]*SW_INV_255;
+ color[3] *= (float)colors[idx + 3]*SW_INV_255;
+ }
+
+ int idx = 3*index;
+ float position[4] = {
+ positions[idx],
+ positions[idx + 1],
+ positions[idx + 2],
+ 1.0f
+ };
+
+ sw_immediate_push_vertex(position, color, texcoord);
}
}
swEnd();
@@ -4801,17 +4671,14 @@ void swDeleteTextures(int count, uint32_t *textures)
continue;
}
- if (RLSW.loadedTextures[textures[i]].copy)
- {
- SW_FREE(RLSW.loadedTextures[textures[i]].pixels.ptr);
- }
+ SW_FREE(RLSW.loadedTextures[textures[i]].pixels);
- RLSW.loadedTextures[textures[i]].pixels.cptr = NULL;
+ RLSW.loadedTextures[textures[i]].pixels = NULL;
RLSW.freeTextureIds[RLSW.freeTextureIdCount++] = textures[i];
}
}
-void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void *data)
+void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data)
{
uint32_t id = RLSW.currentTexture;
@@ -4831,33 +4698,27 @@ void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy
sw_texture_t *texture = &RLSW.loadedTextures[id];
- if (copy)
+ int size = width*height;
+ texture->pixels = SW_MALLOC(4*size);
+
+ if (texture->pixels == NULL)
{
- int bytes = sw_get_pixel_bytes(pixelFormat);
- int size = bytes*width*height;
- texture->pixels.ptr = SW_MALLOC(size);
-
- if (texture->pixels.ptr == NULL)
- {
- RLSW.errCode = SW_STACK_OVERFLOW; // WARING: Out of memory...
- return;
- }
-
- for (int i = 0; i < size; i++)
- {
- ((uint8_t *)texture->pixels.ptr)[i] = ((uint8_t *)data)[i];
- }
+ RLSW.errCode = SW_STACK_OVERFLOW; // WARNING: Out of memory...
+ return;
+ }
+
+ for (int i = 0; i < size; i++)
+ {
+ uint32_t *dst = &((uint32_t*)texture->pixels)[i];
+ sw_get_pixel((uint8_t*)dst, data, i, pixelFormat);
}
- else texture->pixels.cptr = data;
texture->width = width;
texture->height = height;
texture->wMinus1 = width - 1;
texture->hMinus1 = height - 1;
- texture->format = pixelFormat;
texture->tx = 1.0f/width;
texture->ty = 1.0f/height;
- texture->copy = copy;
}
void swTexParameteri(int param, int value)
@@ -4882,7 +4743,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->minFilter = value;
+ texture->minFilter = (SWfilter)value;
} break;
case SW_TEXTURE_MAG_FILTER:
{
@@ -4892,7 +4753,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->magFilter = value;
+ texture->magFilter = (SWfilter)value;
} break;
case SW_TEXTURE_WRAP_S:
{
@@ -4902,7 +4763,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->sWrap = value;
+ texture->sWrap = (SWwrap)value;
} break;
case SW_TEXTURE_WRAP_T:
{
@@ -4912,7 +4773,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->tWrap = value;
+ texture->tWrap = (SWwrap)value;
} break;
default: RLSW.errCode = SW_INVALID_ENUM; break;
}
@@ -4926,7 +4787,7 @@ void swBindTexture(uint32_t id)
return;
}
- if (RLSW.loadedTextures[id].pixels.cptr == NULL)
+ if (RLSW.loadedTextures[id].pixels == NULL)
{
RLSW.errCode = SW_INVALID_OPERATION;
return;
diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c
index 6ecc41888..47dcce32b 100644
--- a/src/platforms/rcore_android.c
+++ b/src/platforms/rcore_android.c
@@ -461,7 +461,7 @@ int GetCurrentMonitor(void)
if (display == NULL)
{
TRACELOG(LOG_ERROR, "GetCurrentMonitor() couldn't get the display object");
- }
+ }
else
{
jclass displayClass = (*env)->FindClass(env, "android/view/Display");
diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c
index 904f7c963..085c5036f 100644
--- a/src/platforms/rcore_desktop_glfw.c
+++ b/src/platforms/rcore_desktop_glfw.c
@@ -1048,6 +1048,7 @@ Image GetClipboardImage(void)
void ShowCursor(void)
{
glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+
CORE.Input.Mouse.cursorHidden = false;
}
@@ -1055,6 +1056,7 @@ void ShowCursor(void)
void HideCursor(void)
{
glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+
CORE.Input.Mouse.cursorHidden = true;
}
@@ -1076,13 +1078,10 @@ void EnableCursor(void)
void DisableCursor(void)
{
// Reset mouse position within the window area before disabling cursor
- SetMousePosition(CORE.Window.screen.width, CORE.Window.screen.height);
+ SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
- // Set cursor position in the middle
- SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
-
if (glfwRawMouseMotionSupported()) glfwSetInputMode(platform.handle, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
CORE.Input.Mouse.cursorHidden = true;
diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c
index 0e39d79d2..421ef7c46 100644
--- a/src/platforms/rcore_desktop_rgfw.c
+++ b/src/platforms/rcore_desktop_rgfw.c
@@ -80,7 +80,7 @@ void CloseWindow(void);
#define CloseWindow CloseWindow_win32
#define ShowCursor __imp_ShowCursor
#define _APISETSTRING_
-
+
#undef MAX_PATH
#if defined(__cplusplus)
@@ -262,7 +262,7 @@ static int RGFW_gpConvTable[18] = {
[RGFW_gamepadRight] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT,
[RGFW_gamepadDown] = GAMEPAD_BUTTON_LEFT_FACE_DOWN,
[RGFW_gamepadLeft] = GAMEPAD_BUTTON_LEFT_FACE_LEFT,
- [RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB,
+ [RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB,
[RGFW_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB,
};
@@ -936,7 +936,7 @@ void PollInputEvents(void)
// because ProcessGestureEvent() is just called on an event, not every frame
UpdateGestures();
#endif
-
+
// Reset keys/chars pressed registered
CORE.Input.Keyboard.keyPressedQueueCount = 0;
CORE.Input.Keyboard.charPressedQueueCount = 0;
@@ -1028,7 +1028,7 @@ void PollInputEvents(void)
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event->droppedFiles[i]);
-
+
CORE.Window.dropFileCount++;
}
else if (CORE.Window.dropFileCount < 1024)
@@ -1232,7 +1232,7 @@ void PollInputEvents(void)
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
int pressed = (value > 0.1f);
CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = pressed;
-
+
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
}
@@ -1348,7 +1348,7 @@ int InitPlatform(void)
// TODO: Is this needed by raylib now?
// If so, rcore_desktop_sdl should be updated too
//SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
-
+
if (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 feba54e92..0dccfef0c 100644
--- a/src/platforms/rcore_desktop_sdl.c
+++ b/src/platforms/rcore_desktop_sdl.c
@@ -104,7 +104,6 @@ typedef struct {
SDL_GameController *gamepad[MAX_GAMEPADS];
SDL_JoystickID gamepadId[MAX_GAMEPADS]; // Joystick instance ids, they do not start from 0
SDL_Cursor *cursor;
- bool cursorRelative;
} PlatformData;
//----------------------------------------------------------------------------------
@@ -838,7 +837,11 @@ void SetWindowPosition(int x, int y)
void SetWindowMonitor(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
// NOTE:
// 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
@@ -962,7 +965,11 @@ int GetCurrentMonitor(void)
Vector2 GetMonitorPosition(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
SDL_Rect displayBounds;
@@ -986,7 +993,11 @@ int GetMonitorWidth(int monitor)
int width = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
@@ -1003,7 +1014,11 @@ int GetMonitorHeight(int monitor)
int height = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
@@ -1020,7 +1035,11 @@ int GetMonitorPhysicalWidth(int monitor)
int width = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
float ddpi = 0.0f;
SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL);
@@ -1040,7 +1059,11 @@ int GetMonitorPhysicalHeight(int monitor)
int height = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
float ddpi = 0.0f;
SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL);
@@ -1060,7 +1083,11 @@ int GetMonitorRefreshRate(int monitor)
int refresh = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
@@ -1076,7 +1103,14 @@ const char *GetMonitorName(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
- if ((monitor >= 0) && (monitor < monitorCount)) return SDL_GetDisplayName(monitor);
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
+ if ((monitor >= 0) && (monitor < monitorCount))
+#endif
+ {
+ return SDL_GetDisplayName(monitor);
+ }
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
return "";
@@ -1210,7 +1244,6 @@ void EnableCursor(void)
ShowCursor();
- platform.cursorRelative = false;
CORE.Input.Mouse.cursorLocked = false;
}
@@ -1329,7 +1362,7 @@ void PollInputEvents(void)
CORE.Input.Mouse.currentWheelMove.y = 0;
// Register previous mouse position
- if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
+ if (CORE.Input.Mouse.cursorLocked) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
// Reset last gamepad button/axis registered state
@@ -1631,7 +1664,7 @@ void PollInputEvents(void)
} break;
case SDL_MOUSEMOTION:
{
- if (platform.cursorRelative)
+ if (CORE.Input.Mouse.cursorLocked)
{
CORE.Input.Mouse.currentPosition.x = (float)event.motion.xrel;
CORE.Input.Mouse.currentPosition.y = (float)event.motion.yrel;
diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c
index 3ccd4d3bd..1dadd5586 100644
--- a/src/platforms/rcore_desktop_win32.c
+++ b/src/platforms/rcore_desktop_win32.c
@@ -49,8 +49,6 @@
#define CloseWindow CloseWindowWin32
#define Rectangle RectangleWin32
#define ShowCursor ShowCursorWin32
-#define LoadImageA LoadImageAWin32
-#define LoadImageW LoadImageWin32
#define DrawTextA DrawTextAWin32
#define DrawTextW DrawTextWin32
#define DrawTextExA DrawTextExAWin32
@@ -63,8 +61,6 @@
#undef Rectangle // raylib symbol collision
#undef ShowCursor // raylib symbol collision
#undef LoadImage // raylib symbol collision
-#undef LoadImageA
-#undef LoadImageW
#undef DrawText // raylib symbol collision
#undef DrawTextA
#undef DrawTextW
@@ -84,29 +80,31 @@
// Types and Structures Definition
//----------------------------------------------------------------------------------
-// NOTE: appScreenSize is the last screen size requested by the app,
-// the backend must keep the client area this size (after DPI scaling is applied)
+// NOTE: appScreenSize is the last screen size requested by the app,
+// the backend must keep the client area this size (after DPI scaling is applied)
// when the window isn't fullscreen/maximized/minimized
typedef struct {
HWND hwnd; // Window handler
HDC hdc; // Graphic context handler
HGLRC glContext; // OpenGL context handler
+
// Software renderer variables
HDC hdcmem; // Memory graphic context handler
HBITMAP hbitmap; // GDI bitmap handler
unsigned int *pixels; // Pointer to pixel data buffer (BGRA format)
- LARGE_INTEGER timerFrequency;
unsigned int appScreenWidth;
unsigned int appScreenHeight;
unsigned int desiredFlags;
- bool cursorEnabled;
+
+ LARGE_INTEGER timerFrequency;
} PlatformData;
// Define WGL function pointer types (no wglext.h needed)
typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
typedef BOOL (WINAPI *PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC, const int *, const FLOAT *, UINT, int *, UINT *);
typedef BOOL (WINAPI *PFNWGLSWAPINTERVALEXTPROC)(int);
+typedef const char *(WINAPI *PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc);
//----------------------------------------------------------------------------------
// Global Variables Definition
@@ -119,6 +117,7 @@ static PlatformData platform = { 0 }; // Platform specific data
static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
+static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL;
// --------------------------------------------------------------------------------
// This part of the file contains pure functions that never access global state
@@ -133,12 +132,12 @@ static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
// Defines and Macros
//----------------------------------------------------------------------------------
#define A_TO_W_ALLOCA(outWstr, inAnsi) do { \
- size_t len = AToWLen(inAnsi); \
- outWstr = (WCHAR *)alloca(sizeof(WCHAR)*(len + 1)); \
- AToWCopy(outWstr, len, inAnsi); \
- outWstr[len] = 0; \
+ size_t outLen = AToWLen(inAnsi); \
+ outWstr = (WCHAR *)alloca(sizeof(WCHAR)*(outLen + 1)); \
+ AToWCopy(inAnsi, outWstr, outLen); \
+ outWstr[outLen] = 0; \
} while (0)
-
+
#define STYLE_MASK_ALL 0xffffffff
#define STYLE_MASK_READONLY (WS_MINIMIZE | WS_MAXIMIZE)
#define STYLE_MASK_WRITABLE (~STYLE_MASK_READONLY)
@@ -150,7 +149,7 @@ static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
#define WINDOW_STYLE_EX 0
-#define CLASS_NAME L"RaylibWindow"
+#define CLASS_NAME L"raylibWindow"
#define FLAG_MASK_OPTIONAL (FLAG_VSYNC_HINT)
#define FLAG_MASK_REQUIRED ~(FLAG_MASK_OPTIONAL)
@@ -196,93 +195,86 @@ static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
+#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
-typedef enum { MIZED_NONE, MIZED_MIN, MIZED_MAX } Mized;
-
+// Maximize-minimize request types
typedef enum {
- UPDATE_WINDOW_FIRST,
- UPDATE_WINDOW_NORMAL,
-} UpdateWindowKind;
-
-typedef enum {
- SANITIZE_FLAGS_FIRST,
- SANITIZE_FLAGS_NORMAL,
-} SanitizeFlagsKind;
-
-typedef struct {
- HMONITOR needle;
- int index;
- int matchIndex;
- RECT rect;
-} FindMonitorContext;
+ MIZED_NONE,
+ MIZED_MIN,
+ MIZED_MAX
+} Mized;
+// Flag operations
+// NOTE: Some ops need to be deferred
typedef struct {
DWORD set;
DWORD clear;
} FlagsOp;
+// Monitor info type
+typedef struct {
+ HMONITOR needle;
+ int index;
+ int matchIndex;
+ RECT rect;
+} MonitorInfo;
+
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
-static size_t AToWLen(const char *a)
+// Get ASCII to WCHAR length
+static size_t AToWLen(const char *ascii)
{
- int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, a, -1, NULL, 0);
-
- if (sizeNeeded < 0) TRACELOG(LOG_ERROR, "Failed to calculate wide length, result=%d, error=%u", sizeNeeded, GetLastError());
+ int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, ascii, -1, NULL, 0);
+
+ if (sizeNeeded < 0) TRACELOG(LOG_ERROR, "WIN32: Failed to calculate wide length [ERROR: %u]", GetLastError());
return sizeNeeded;
}
-static void AToWCopy(wchar_t *outPtr, size_t outLen, const char *a)
+
+// Copy ASCII to WCHAR string
+static void AToWCopy(const char *ascii, wchar_t *outPtr, size_t outLen)
{
- int size = MultiByteToWideChar(CP_UTF8, 0, a, -1, outPtr, (int)outLen);
- if (size != outLen) TRACELOG(LOG_WARNING, "WIN32: Convert %zu UTF-8 chars to WCHAR but converted %zu", outLen, size);
+ int size = MultiByteToWideChar(CP_UTF8, 0, ascii, -1, outPtr, (int)outLen);
+ if (size != outLen) TRACELOG(LOG_WARNING, "WIN32: Failed to convert %i UTF-8 chars to WCHAR, converted %i chars", outLen, size);
}
static bool DecoratedFromStyle(DWORD style)
{
if (style & STYLE_FLAGS_UNDECORATED_ON)
{
- if (style & STYLE_FLAGS_UNDECORATED_OFF) TRACELOG(LOG_ERROR, "FLAGS: Style 0x%x has both undecorated on/off flags", style);
+ if (style & STYLE_FLAGS_UNDECORATED_OFF) TRACELOG(LOG_ERROR, "WIN32: FLAGS: Style 0x%x has both undecorated on/off flags", style);
return false; // Not decorated
}
DWORD masked = (style & STYLE_FLAGS_UNDECORATED_OFF);
- if (STYLE_FLAGS_UNDECORATED_OFF != masked) TRACELOG(LOG_ERROR, "FLAGS: Style 0x%x is missing these flags 0x%x", masked, masked ^ STYLE_FLAGS_UNDECORATED_OFF);
+ if (STYLE_FLAGS_UNDECORATED_OFF != masked) TRACELOG(LOG_ERROR, "WIN32: FLAGS: Style 0x%x is missing flags 0x%x", masked, masked ^ STYLE_FLAGS_UNDECORATED_OFF);
return true; // Decorated
}
-static Mized MizedFromStyle(DWORD style)
-{
- // Minimized takes precedence over maximized
- if (style & WS_MINIMIZE) return MIZED_MIN;
- if (style & WS_MAXIMIZE) return MIZED_MAX;
- return MIZED_NONE;
-}
-
-static Mized MizedFromFlags(unsigned flags)
-{
- // minimized takes precedence over maximized
- if (FLAG_CHECK(flags, FLAG_WINDOW_MINIMIZED)) return MIZED_MIN;
- if (flags & FLAG_WINDOW_MAXIMIZED) return MIZED_MAX;
- return MIZED_NONE;
-}
-
+// Get window style from required flags
static DWORD MakeWindowStyle(unsigned flags)
{
- // we don't need this since we don't have any child windows, but I guess
+ // We don't need this since we don't have any child windows, but I guess
// it improves efficiency, plus, windows adds this flag automatically anyway
// so it keeps our flags in sync with the OS
- DWORD style = WS_CLIPSIBLINGS ;
-
+ DWORD style = WS_CLIPSIBLINGS;
+
style |= (flags & FLAG_WINDOW_HIDDEN)? 0 : WS_VISIBLE;
style |= (flags & FLAG_WINDOW_RESIZABLE)? STYLE_FLAGS_RESIZABLE : 0;
style |= (flags & FLAG_WINDOW_UNDECORATED)? STYLE_FLAGS_UNDECORATED_ON : STYLE_FLAGS_UNDECORATED_OFF;
- switch (MizedFromFlags(flags))
+ // Minimized takes precedence over maximized
+ int mized = MIZED_NONE;
+ if (FLAG_CHECK(flags, FLAG_WINDOW_MINIMIZED)) mized = MIZED_MIN;
+ if (flags & FLAG_WINDOW_MAXIMIZED) mized = MIZED_MAX;
+
+ switch (mized)
{
case MIZED_NONE: break;
case MIZED_MIN: style |= WS_MINIMIZE; break;
@@ -293,15 +285,13 @@ static DWORD MakeWindowStyle(unsigned flags)
return style;
}
-// Enforces that the actual window/platform state is in sync with raylib's flags
+// Check flags state, enforces that the actual window/platform state is in sync with raylib's flags
static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expectedStyle, DWORD styleCheckMask)
{
- //TRACELOG(LOG_INFO, "Verifying Flags 0x%x Style 0x%x Mask 0x%x", flags, expectedStyle & styleCheckMask, styleCheckMask);
-
DWORD styleFromFlags = MakeWindowStyle(flags);
if ((styleFromFlags & styleCheckMask) != (expectedStyle & styleCheckMask))
{
- TRACELOG(LOG_ERROR, "%s: window flags (0x%x) produced style 0x%x which != expected 0x%x (diff=0x%x, mask=0x%x)",
+ TRACELOG(LOG_ERROR, "WIN32: FLAGS: %s: window flags (0x%x) produced style 0x%x which != expected 0x%x (diff=0x%x, mask=0x%x)",
context, flags, styleFromFlags & styleCheckMask, expectedStyle & styleCheckMask,
(styleFromFlags & styleCheckMask) ^ (expectedStyle & styleCheckMask), styleCheckMask);
}
@@ -310,7 +300,7 @@ static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expect
LONG actualStyle = (LONG)GetWindowLongPtrW(hwnd, GWL_STYLE);
if ((actualStyle & styleCheckMask) != (expectedStyle & styleCheckMask))
{
- TRACELOG(LOG_ERROR, "%s: expected style 0x%x but got 0x%x (diff=0x%x, mask=0x%x, lasterror=%lu)",
+ TRACELOG(LOG_ERROR, "WIN32: FLAGS: %s: expected style 0x%x but got 0x%x (diff=0x%x, mask=0x%x, lasterror=%lu)",
context, expectedStyle & styleCheckMask, actualStyle & styleCheckMask,
(expectedStyle & styleCheckMask) ^ (actualStyle & styleCheckMask),
styleCheckMask, GetLastError());
@@ -320,7 +310,7 @@ static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expect
{
bool isIconic = IsIconic(hwnd);
bool styleMinimized = !!(WS_MINIMIZE & actualStyle);
- if (isIconic != styleMinimized) TRACELOG(LOG_ERROR, "IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized);
+ if (isIconic != styleMinimized) TRACELOG(LOG_ERROR, "WIN32: FLAGS: IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized);
}
if (styleCheckMask & WS_MAXIMIZE)
@@ -329,49 +319,32 @@ static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expect
placement.length = sizeof(placement);
if (!GetWindowPlacement(hwnd, &placement))
{
- TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowPlacement", GetLastError());
+ TRACELOG(LOG_ERROR, "WIN32: FLAGS: %s failed, error=%lu", "GetWindowPlacement", GetLastError());
}
bool placementMaximized = (placement.showCmd == SW_SHOWMAXIMIZED);
bool styleMaximized = WS_MAXIMIZE & actualStyle;
if (placementMaximized != styleMaximized)
{
- TRACELOG(LOG_ERROR, "maximized state desync, placement maximized=%d (showCmd=%lu) style maximized=%d",
+ TRACELOG(LOG_ERROR, "WIN32: FLAGS: Maximized state desync, placement maximized=%d (showCmd=%lu) style maximized=%d",
placementMaximized, placement.showCmd, styleMaximized);
}
}
}
-static SIZE PxFromPt2(float dpiScale, bool highdpiEnabled, int screenWidth, int screenHeight)
-{
- // Get size in pixels from points
- return (SIZE){
- highdpiEnabled? (int)((float)screenWidth*dpiScale) : screenWidth,
- highdpiEnabled? (int)((float)screenHeight*dpiScale) : screenHeight,
- };
-}
-
-static SIZE GetClientSize(HWND hwnd)
-{
- RECT rect = { 0 };
-
- if (GetClientRect(hwnd, &rect) == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetClientRect", GetLastError());
-
- return (SIZE){ rect.right, rect.bottom };
-}
-
+// Calculate window size (with borders, title-bar...) from desired client size (framebuffer size)
static SIZE CalcWindowSize(UINT dpi, SIZE clientSize, DWORD style)
{
RECT rect = { 0, 0, clientSize.cx, clientSize.cy };
-
+
int result = AdjustWindowRectExForDpi(&rect, style, 0, WINDOW_STYLE_EX, dpi);
-
- if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "AdjustWindowRect", GetLastError());
+ if (result == 0) TRACELOG(LOG_ERROR, "WIN32: Failed to adjust window rect [ERROR: %lu]", GetLastError());
return (SIZE){ rect.right - rect.left, rect.bottom - rect.top };
}
-// returns true if the window size was updated, false otherwise
-static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int height, unsigned flags)
+// Update window size if required
+// NOTE: Returns true if the window size was updated, false otherwise
+static bool UpdateWindowSize(int mode, HWND hwnd, int width, int height, unsigned flags)
{
if (flags & FLAG_WINDOW_MINIMIZED) return false;
@@ -386,10 +359,10 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he
MONITORINFO info = { 0 };
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
info.cbSize = sizeof(info);
- if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError());
+ if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "WIN32: Failed to get monitor info [ERROR: %lu]", GetLastError());
RECT windowRect = { 0 };
- if (!GetWindowRect(hwnd, &windowRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowRect", GetLastError());
+ if (!GetWindowRect(hwnd, &windowRect)) TRACELOG(LOG_ERROR, "WIN32: Failed to get window rect [ERROR: %lu]", GetLastError());
if ((windowRect.left == info.rcMonitor.left) &&
(windowRect.top == info.rcMonitor.top) &&
@@ -402,33 +375,45 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he
info.rcMonitor.bottom - info.rcMonitor.top,
SWP_NOOWNERZORDER))
{
- TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError());
+ TRACELOG(LOG_ERROR, "WIN32: Failed to set window position [ERROR: %lu]", GetLastError());
}
return true;
}
+ // Get size in pixels from points, considering high-dpi
UINT dpi = GetDpiForWindow(hwnd);
float dpiScale = ((float)dpi)/96.0f;
bool dpiScaling = flags & FLAG_WINDOW_HIGHDPI;
- SIZE desired = PxFromPt2(dpiScale, dpiScaling, width, height);
- SIZE actual = GetClientSize(hwnd);
- if ((actual.cx == desired.cx) || (actual.cy == desired.cy)) return false;
+ SIZE desiredSize = {
+ .cx = dpiScaling? (int)((float)width*dpiScale) : width,
+ .cy = dpiScaling? (int)((float)height*dpiScale) : height
+ };
- TRACELOG(LOG_INFO, "Restoring client size from [%dx%d] to [%dx%d] (dpi:%lu dpiScaling:%d app:%ix%i)",
- actual.cx, actual.cy, desired.cx, desired.cy, dpi, dpiScaling, width, height);
+ // Get client size (framebuffer inside the window)
+ RECT rect = { 0 };
+ GetClientRect(hwnd, &rect);
+ SIZE clientSize = { rect.right, rect.bottom };
- SIZE windowSize = CalcWindowSize(dpi, desired, MakeWindowStyle(flags));
- POINT windowPos = (POINT){ 0, 0 };
+ // If client size is alread desired size, no need to update
+ if ((clientSize.cx == desiredSize.cx) || (clientSize.cy == desiredSize.cy)) return false;
+
+ TRACELOG(LOG_INFO, "WIN32: Restoring client size from [%dx%d] to [%dx%d] (dpi:%lu dpiScaling:%d app:%ix%i)",
+ clientSize.cx, clientSize.cy, desiredSize.cx, desiredSize.cy, dpi, dpiScaling, width, height);
+
+ // Calculate window size from desired framebuffer size and window flags
+ SIZE windowSize = CalcWindowSize(dpi, desiredSize, MakeWindowStyle(flags));
+ POINT windowPos = { 0 };
UINT swpFlags = SWP_NOZORDER | SWP_FRAMECHANGED;
- if (kind == UPDATE_WINDOW_FIRST)
+
+ if (mode == 0) // UPDATE_WINDOW_FIRST
{
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
- if (!monitor) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "MonitorFromWindow", GetLastError());
+ if (!monitor) TRACELOG(LOG_ERROR, "WIN32: Failed to get monitor from window [ERROR: %lu]", GetLastError());
- MONITORINFO info;
+ MONITORINFO info = { 0 };
info.cbSize = sizeof(info);
- if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError());
+ if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "WIN32: Failed to get monitor info [ERROR: %lu]", GetLastError());
#define MAX(a,b) (((a)>(b))? (a):(b))
@@ -446,24 +431,19 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he
//AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0);
//SetWindowPos(hwnd, NULL, windowPos.x, windowPos.y, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER);
- // Old code
- //if (!SetWindowPos(hwnd, NULL, windowPos.x, windowPos.y, windowSize.cx, windowSize.cy, swpFlags))
- //{
- // TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError());
- //}
-
return true;
}
+// Verify if we are running in Windows 10 version 1703 (Creators Update)
static BOOL IsWindows10Version1703OrGreaterWin32(void)
{
HMODULE ntdll = LoadLibraryW(L"ntdll.dll");
-
- DWORD (*Verify)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG) =
+
+ DWORD (*Verify)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG) =
(DWORD (*)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG))GetProcAddress(ntdll, "RtlVerifyVersionInfo");
if (!Verify)
{
- TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetProcAddress 'RtlVerifyVersionInfo'", GetLastError());
+ TRACELOG(LOG_ERROR, "WIN32: Failed to verify Windows version [ERROR: %lu]", GetLastError());
return 0;
}
@@ -472,11 +452,12 @@ static BOOL IsWindows10Version1703OrGreaterWin32(void)
osvi.dwMajorVersion = 10;
osvi.dwMinorVersion = 0;
osvi.dwBuildNumber = 15063; // Build 15063 corresponds to Windows 10 version 1703 (Creators Update)
+
DWORDLONG cond = 0;
VER_SET_CONDITION(cond, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL);
-
+
return 0 == (*Verify)(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, cond);
}
@@ -488,8 +469,8 @@ static void *WglGetProcAddress(const char *procname)
if ((proc == NULL) ||
// NOTE: Some GPU drivers could return following
// invalid sentinel values instead of NULL
- (proc == (void *)0x1) ||
- (proc == (void *)0x2) ||
+ (proc == (void *)0x1) ||
+ (proc == (void *)0x2) ||
(proc == (void *)0x3) ||
(proc == (void *)-1))
{
@@ -504,7 +485,8 @@ static void *WglGetProcAddress(const char *procname)
return proc;
}
-static KeyboardKey KeyFromWparam(WPARAM wparam)
+// Get key from wparam (mapping)
+static KeyboardKey GetKeyFromWparam(WPARAM wparam)
{
switch (wparam)
{
@@ -687,6 +669,7 @@ static KeyboardKey KeyFromWparam(WPARAM wparam)
}
}
+// Get cursor name
static LPCWSTR GetCursorName(int cursor)
{
LPCWSTR name = (LPCWSTR)IDC_ARROW;
@@ -710,37 +693,46 @@ static LPCWSTR GetCursorName(int cursor)
return name;
}
-static BOOL CALLBACK CountMonitorsProc(HMONITOR handle, HDC _, LPRECT rect, LPARAM lparam)
+// Count monitors process
+// NOTE: Required by GetMonitorCount()
+static BOOL CALLBACK CountMonitorsProc(HMONITOR handle, HDC hdc, LPRECT rect, LPARAM lparam)
{
int *count = (int *)lparam;
*count += 1;
+
// Always return TRUE to continue the loop, otherwise, the caller
// can't distinguish between stopping the loop and an error
return TRUE;
}
-static BOOL CALLBACK FindMonitorProc(HMONITOR handle, HDC _, LPRECT rect, LPARAM lparam)
+// Find monitor process
+// NOTE: Required by GetCurrentMonitor()
+static BOOL CALLBACK FindMonitorProc(HMONITOR handle, HDC hdc, LPRECT rect, LPARAM lparam)
{
- FindMonitorContext *c = (FindMonitorContext*)lparam;
- if (handle == c->needle)
+ MonitorInfo *monitor = (MonitorInfo *)lparam;
+
+ if (handle == monitor->needle)
{
- c->matchIndex = c->index;
- c->rect = *rect;
+ monitor->matchIndex = monitor->index;
+ monitor->rect = *rect;
}
- c->index += 1;
+ monitor->index += 1;
+
// Always return TRUE to continue the loop, otherwise, the caller
// can't distinguish between stopping the loop and an error
return TRUE;
}
-static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsOp *deferredFlags)
+// Get style changed required operations flags
+// NOTE: Required for deferred operations
+static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *style, FlagsOp *deferredFlags)
{
// Check window resizable flag change
bool resizable = (coreWindowFlags & FLAG_WINDOW_RESIZABLE);
- bool resizableOld = ((ss->styleOld & STYLE_FLAGS_RESIZABLE) != 0);
- bool resizableNew = ((ss->styleNew & STYLE_FLAGS_RESIZABLE) != 0);
- if (resizable != resizableOld) TRACELOG(LOG_ERROR, "expected resizable %u but got %u", resizable, resizableOld);
+ bool resizableOld = ((style->styleOld & STYLE_FLAGS_RESIZABLE) != 0);
+ bool resizableNew = ((style->styleNew & STYLE_FLAGS_RESIZABLE) != 0);
+ if (resizable != resizableOld) TRACELOG(LOG_ERROR, "WIN32: Expected resizable %u but got %u", resizable, resizableOld);
if (resizableOld != resizableNew)
{
if (resizableNew) deferredFlags->set |= FLAG_WINDOW_RESIZABLE;
@@ -749,9 +741,9 @@ static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsO
// Check window decorated flag change
bool decorated = (0 == (coreWindowFlags & FLAG_WINDOW_UNDECORATED));
- bool decoratedOld = DecoratedFromStyle(ss->styleOld);
- bool decoratedNew = DecoratedFromStyle(ss->styleNew);
- if (decorated != decoratedOld) TRACELOG(LOG_ERROR, "expected decorated %u but got %u", decorated, decoratedOld);
+ bool decoratedOld = DecoratedFromStyle(style->styleOld);
+ bool decoratedNew = DecoratedFromStyle(style->styleNew);
+ if (decorated != decoratedOld) TRACELOG(LOG_ERROR, "WIN32: Expected decorated %u but got %u", decorated, decoratedOld);
if (decoratedOld != decoratedNew)
{
if (decoratedNew) deferredFlags->clear |= FLAG_WINDOW_UNDECORATED;
@@ -760,9 +752,9 @@ static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsO
// Check window hidden flag change
bool hidden = (coreWindowFlags & FLAG_WINDOW_HIDDEN);
- bool hiddenOld = ((ss->styleOld & WS_VISIBLE) == 0);
- bool hiddenNew = ((ss->styleNew & WS_VISIBLE) == 0);
- if (hidden != hiddenOld) TRACELOG(LOG_ERROR, "expected hidden %u but got %u", hidden, hiddenOld);
+ bool hiddenOld = ((style->styleOld & WS_VISIBLE) == 0);
+ bool hiddenNew = ((style->styleNew & WS_VISIBLE) == 0);
+ if (hidden != hiddenOld) TRACELOG(LOG_ERROR, "WIN32: Expected hidden %u but got %u", hidden, hiddenOld);
if (hiddenOld != hiddenNew)
{
if (hiddenNew) deferredFlags->set |= FLAG_WINDOW_HIDDEN;
@@ -770,7 +762,9 @@ static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsO
}
}
-// Call when the window is rezised, returns true if the new window size should update the desired app size
+// Adopt window resize
+// NOTE: Call when the window is rezised, returns true
+// if the new window size should update the desired app size
static bool AdoptWindowResize(unsigned flags)
{
if (flags & FLAG_WINDOW_MINIMIZED) return false;
@@ -778,7 +772,7 @@ static bool AdoptWindowResize(unsigned flags)
if (flags & FLAG_FULLSCREEN_MODE) return false;
if (flags & FLAG_BORDERLESS_WINDOWED_MODE) return false;
if (!(flags & FLAG_WINDOW_RESIZABLE)) return false;
-
+
return true;
}
@@ -805,9 +799,12 @@ static void HandleRawInput(LPARAM lparam);
static void HandleWindowResize(HWND hwnd, int *width, int *height);
static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags);
-static unsigned SanitizeFlags(SanitizeFlagsKind kind, unsigned flags);
+static unsigned SanitizeFlags(int mode, unsigned flags);
static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height); // Update window flags
+// Check if OpenGL extension is available
+static bool IsWglExtensionAvailable(HDC hdc, const char *extension);
+
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
@@ -826,20 +823,14 @@ bool WindowShouldClose(void)
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
- TRACELOG(LOG_WARNING, "ToggleFullscreen not implemented");
+ TRACELOG(LOG_WARNING, "WIN32: Toggle full screen functionality not implemented");
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
- if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE)
- {
- ClearWindowState(FLAG_BORDERLESS_WINDOWED_MODE);
- }
- else
- {
- SetWindowState(FLAG_BORDERLESS_WINDOWED_MODE);
- }
+ if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) ClearWindowState(FLAG_BORDERLESS_WINDOWED_MODE);
+ else SetWindowState(FLAG_BORDERLESS_WINDOWED_MODE);
}
// Set window state: maximized, if resizable
@@ -858,57 +849,123 @@ void MinimizeWindow(void)
void RestoreWindow(void)
{
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) &&
- (CORE.Window.flags & FLAG_WINDOW_MINIMIZED)
- ) {
- ClearWindowState(FLAG_WINDOW_MINIMIZED);
- }
- else
- {
- ClearWindowState(FLAG_WINDOW_MINIMIZED|FLAG_WINDOW_MAXIMIZED);
- }
+ (CORE.Window.flags & FLAG_WINDOW_MINIMIZED)) ClearWindowState(FLAG_WINDOW_MINIMIZED);
+ else ClearWindowState(FLAG_WINDOW_MINIMIZED | FLAG_WINDOW_MAXIMIZED);
}
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
- platform.desiredFlags = SanitizeFlags(SANITIZE_FLAGS_NORMAL, CORE.Window.flags | flags);
+ platform.desiredFlags = SanitizeFlags(1 /*SANITIZE_FLAGS_NORMAL*/, CORE.Window.flags | flags);
UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight);
}
// Clear window configuration state flags
void ClearWindowState(unsigned int flags)
{
- platform.desiredFlags = SanitizeFlags(SANITIZE_FLAGS_NORMAL, CORE.Window.flags & ~flags);
+ platform.desiredFlags = SanitizeFlags(1 /*SANITIZE_FLAGS_NORMAL*/, CORE.Window.flags & ~flags);
UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight);
}
// Set icon for window
void SetWindowIcon(Image image)
{
- TRACELOG(LOG_WARNING, "SetWindowIcon not implemented");
+ if (!platform.hwnd || (image.data == NULL) || (image.width <= 0) || (image.height <= 0)) return;
+
+ HDC hdc = GetDC(platform.hwnd);
+
+ // Create 32-bit BGRA DIB for color
+ BITMAPV5HEADER bi = { 0 };
+ ZeroMemory(&bi, sizeof(bi));
+ bi.bV5Size = sizeof(bi);
+ bi.bV5Width = image.width;
+ bi.bV5Height = -image.height; // Negative = top-down bitmap
+ bi.bV5Planes = 1;
+ bi.bV5BitCount = 32;
+ bi.bV5Compression = BI_BITFIELDS;
+ bi.bV5RedMask = 0x00FF0000;
+ bi.bV5GreenMask = 0x0000FF00;
+ bi.bV5BlueMask = 0x000000FF;
+ bi.bV5AlphaMask = 0xFF000000;
+
+ unsigned char *targetBits = NULL;
+ HBITMAP hColorBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&targetBits, NULL, 0);
+ if (!hColorBitmap)
+ {
+ ReleaseDC(platform.hwnd, hdc);
+ return;
+ }
+
+ // Copy RGBA > BGRA (Win32 expects BGRA)
+ for (int y = 0; y < image.height; y++)
+ {
+ for (int x = 0; x < image.width; x++)
+ {
+ int i = (y*image.width + x)*4;
+ targetBits[i + 0] = ((unsigned char *)image.data)[i + 2]; // B
+ targetBits[i + 1] = ((unsigned char *)image.data)[i + 1]; // G
+ targetBits[i + 2] = ((unsigned char *)image.data)[i + 0]; // R
+ targetBits[i + 3] = ((unsigned char *)image.data)[i + 3]; // A
+ }
+ }
+
+ // Create mask bitmap (1-bit, all opaque)
+ HBITMAP hMaskBitmap = CreateBitmap(image.width, image.height, 1, 1, NULL);
+
+ // Build icon info
+ ICONINFO ii = { 0 };
+ ZeroMemory(&ii, sizeof(ii));
+ ii.fIcon = TRUE;
+ ii.hbmMask = hMaskBitmap;
+ ii.hbmColor = hColorBitmap;
+
+ HICON hIcon = CreateIconIndirect(&ii);
+
+ // Clean up GDI bitmaps (icon keeps copies internally)
+ DeleteObject(hColorBitmap);
+ DeleteObject(hMaskBitmap);
+ ReleaseDC(platform.hwnd, hdc);
+
+ if (hIcon)
+ {
+ // Set both large and small icons
+ SendMessage(platform.hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
+ SendMessage(platform.hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
+ }
}
// Set icon for window
void SetWindowIcons(Image *images, int count)
{
- TRACELOG(LOG_WARNING, "SetWindowIcons not implemented");
+ // TODO.
}
void SetWindowTitle(const char *title)
{
CORE.Window.title = title;
-
+
WCHAR *titleWide = NULL;
A_TO_W_ALLOCA(titleWide, CORE.Window.title);
-
+
int result = SetWindowTextW(platform.hwnd, titleWide);
- if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowText", GetLastError());
+ if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Failed to set window title [ERROR: %lu]", GetLastError());
}
// Set window position on screen (windowed mode)
void SetWindowPosition(int x, int y)
{
- TRACELOG(LOG_WARNING, "SetWindowPosition not implemented");
+ if (platform.hwnd != NULL)
+ {
+ RECT rect = { 0 };
+ if (GetWindowRect(platform.hwnd, &rect))
+ {
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+
+ // Move the window to the new position (keeping size and z-order)
+ SetWindowPos(platform.hwnd, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ }
}
// Set monitor for the current window
@@ -962,7 +1019,7 @@ void *GetWindowHandle(void)
int GetMonitorCount(void)
{
int count = 0;
-
+
int result = EnumDisplayMonitors(NULL, NULL, CountMonitorsProc, (LPARAM)&count);
if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "EnumDisplayMonitors", GetLastError());
@@ -975,15 +1032,15 @@ int GetCurrentMonitor(void)
HMONITOR monitor = MonitorFromWindow(platform.hwnd, MONITOR_DEFAULTTOPRIMARY);
if (!monitor) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "MonitorFromWindow", GetLastError());
- FindMonitorContext context;
- context.needle = monitor;
- context.index = 0;
- context.matchIndex = -1;
-
- int result = EnumDisplayMonitors(NULL, NULL, FindMonitorProc, (LPARAM)&context);
+ MonitorInfo info = { 0 };
+ info.needle = monitor;
+ info.index = 0;
+ info.matchIndex = -1;
+
+ int result = EnumDisplayMonitors(NULL, NULL, FindMonitorProc, (LPARAM)&info);
if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "EnumDisplayMonitors", GetLastError());
- return context.matchIndex;
+ return info.matchIndex;
}
// Get selected monitor position
@@ -1066,7 +1123,7 @@ const char *GetClipboardText(void)
Image GetClipboardImage(void)
{
Image image = { 0 };
-
+
TRACELOG(LOG_WARNING, "GetClipboardText not implemented");
return image;
@@ -1075,26 +1132,25 @@ Image GetClipboardImage(void)
// Show mouse cursor
void ShowCursor(void)
{
- CORE.Input.Mouse.cursorHidden = false;
SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_ARROW));
+ CORE.Input.Mouse.cursorHidden = false;
}
// Hides mouse cursor
void HideCursor(void)
{
- // NOTE: we use SetCursor instead of ShowCursor because it makes it easy
- // to only hide the cursor while it's inside the client area
- CORE.Input.Mouse.cursorHidden = true;
+ // NOTE: We use SetCursor() instead of ShowCursor() because
+ // it makes it easy to only hide the cursor while it's inside the client area
SetCursor(NULL);
+ CORE.Input.Mouse.cursorHidden = true;
}
// Enables cursor (unlock cursor)
void EnableCursor(void)
{
- if (platform.cursorEnabled) TRACELOG(LOG_INFO, "EnableCursor: already enabled");
- else
+ if (CORE.Input.Mouse.cursorLocked)
{
- if (!ClipCursor(NULL)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClipCursor", GetLastError());
+ if (!ClipCursor(NULL)) TRACELOG(LOG_WARNING, "WIN32: Failed to clip cursor [ERROR: %lu]", GetLastError());
RAWINPUTDEVICE rid = { 0 };
rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
@@ -1102,18 +1158,17 @@ void EnableCursor(void)
rid.dwFlags = RIDEV_REMOVE; // Add to this window even in background
rid.hwndTarget = NULL;
int result = RegisterRawInputDevices(&rid, 1, sizeof(rid));
- if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "RegisterRawInputDevices", GetLastError());
+ if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Failed to register raw input devices [ERROR: %lu]", GetLastError());
ShowCursor();
- platform.cursorEnabled = true;
- TRACELOG(LOG_INFO, "EnableCursor: enabled");
+ CORE.Input.Mouse.cursorLocked = false;
}
}
// Disables cursor (lock cursor)
void DisableCursor(void)
{
- if (platform.cursorEnabled)
+ if (!CORE.Input.Mouse.cursorLocked)
{
RAWINPUTDEVICE rid = { 0 };
rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
@@ -1121,33 +1176,31 @@ void DisableCursor(void)
rid.dwFlags = RIDEV_INPUTSINK; // Add to this window even in background
rid.hwndTarget = platform.hwnd;
int result = RegisterRawInputDevices(&rid, 1, sizeof(rid));
- if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "RegisterRawInputDevices", GetLastError());
+ if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Failed to register raw input devices [ERROR: %lu]", GetLastError());
RECT clientRect = { 0 };
- if (!GetClientRect(platform.hwnd, &clientRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetClientRect", GetLastError());
+ if (!GetClientRect(platform.hwnd, &clientRect)) TRACELOG(LOG_WARNING, "WIN32: Failed to get client rectangle [ERROR: %lu]", GetLastError());
POINT topleft = { clientRect.left, clientRect.top };
- if (!ClientToScreen(platform.hwnd, &topleft)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClientToScreen", GetLastError());
+ if (!ClientToScreen(platform.hwnd, &topleft)) TRACELOG(LOG_WARNING, "WIN32: Failed to get client to screen size [ERROR: %lu]", GetLastError());
LONG width = clientRect.right - clientRect.left;
LONG height = clientRect.bottom - clientRect.top;
- TRACELOG(LOG_INFO, "ClipCursor client %d,%d %d,%d (topleft %d,%d)",
+ TRACELOG(LOG_INFO, "WIN32: Clip cursor client rect: [%d,%d %d,%d], top-left: (%d,%d)",
clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, topleft.x, topleft.y);
-
+
LONG centerX = topleft.x + width/2;
LONG centerY = topleft.y + height/2;
RECT clipRect = { centerX, centerY, centerX + 1, centerY + 1 };
- if (!ClipCursor(&clipRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClipCursor", GetLastError());
+ if (!ClipCursor(&clipRect)) TRACELOG(LOG_WARNING, "WIN32: Failed to clip cursor [ERROR: %lu]", GetLastError());
CORE.Input.Mouse.previousPosition = (Vector2){ 0, 0 };
CORE.Input.Mouse.currentPosition = (Vector2){ 0, 0 };
HideCursor();
- platform.cursorEnabled = false;
- TRACELOG(LOG_INFO, "DisableCursor: disabled");
+ CORE.Input.Mouse.cursorLocked = true;
}
- else TRACELOG(LOG_INFO, "DisableCursor: already disabled");
}
// Swap back buffer with front buffer (screen drawing)
@@ -1163,8 +1216,8 @@ void SwapScreenBuffer(void)
InvalidateRect(platform.hwnd, NULL, FALSE);
UpdateWindow(platform.hwnd);
#else
- if (!SwapBuffers(platform.hdc)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SwapBuffers", GetLastError());
- if (!ValidateRect(platform.hwnd, NULL)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ValidateRect", GetLastError());
+ if (!SwapBuffers(platform.hdc)) TRACELOG(LOG_ERROR, "WIN32: Failed to swap buffers [ERROR: %lu]", GetLastError());
+ if (!ValidateRect(platform.hwnd, NULL)) TRACELOG(LOG_ERROR, "WIN32: Failed to validate screen rect [ERROR: %lu]", GetLastError());
#endif
}
@@ -1216,7 +1269,7 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
// Set mouse position XY
void SetMousePosition(int x, int y)
{
- if (platform.cursorEnabled)
+ if (!CORE.Input.Mouse.cursorLocked)
{
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
@@ -1230,7 +1283,7 @@ void SetMouseCursor(int cursor)
{
LPCWSTR cursorName = GetCursorName(cursor);
HCURSOR hcursor = LoadCursorW(NULL, cursorName);
- if (!hcursor) TRACELOG(LOG_ERROR, "LoadCursor %d (win32 %d) failed, error=%lu", cursor, (size_t)cursorName, GetLastError());
+ if (!hcursor) TRACELOG(LOG_ERROR, "WIN32: Failed to load requested cursor [ERROR: %lu]", GetLastError());
SetCursor(hcursor);
CORE.Input.Mouse.cursorHidden = false;
@@ -1289,7 +1342,7 @@ void PollInputEvents(void)
//----------------------------------------------------------------------------------
// Initialize modern OpenGL context
-// NOTE: We need to create a dummy context first to query requried extensions
+// NOTE: We need to create a dummy context first to query required extensions
HGLRC InitOpenGL(HWND hwnd, HDC hdc)
{
// First, create a dummy context to get WGL extensions
@@ -1319,6 +1372,7 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
+ wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
// Setup modern pixel format if extension is available
if (wglChoosePixelFormatARB)
@@ -1353,10 +1407,52 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
HGLRC realContext = NULL;
if (wglCreateContextAttribsARB)
{
+ int glContextVersionMajor = 1;
+ int glContextVersionMinor = 1;
+ int glContextProfile = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
+
+ if (rlGetVersion() == RL_OPENGL_21) // Request OpenGL 2.1 context
+ {
+ glContextVersionMajor = 2;
+ glContextVersionMinor = 1;
+ }
+ else if (rlGetVersion() == RL_OPENGL_33) // Request OpenGL 3.3 context
+ {
+ glContextVersionMajor = 3;
+ glContextVersionMinor = 3;
+ }
+ else if (rlGetVersion() == RL_OPENGL_43) // Request OpenGL 4.3 context
+ {
+ glContextVersionMajor = 4;
+ glContextVersionMinor = 3;
+ }
+ else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context
+ {
+ if (IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es_profile") ||
+ IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es2_profile"))
+ {
+ glContextVersionMajor = 2;
+ glContextVersionMinor = 0;
+ glContextProfile = WGL_CONTEXT_ES_PROFILE_BIT_EXT;
+ }
+ else TRACELOG(LOG_WARNING, "GL: OpenGL ES context not supported by GPU");
+ }
+ else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context
+ {
+ if (IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es_profile") ||
+ IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es2_profile"))
+ {
+ glContextVersionMajor = 3;
+ glContextVersionMinor = 0;
+ glContextProfile = WGL_CONTEXT_ES_PROFILE_BIT_EXT;
+ }
+ else TRACELOG(LOG_WARNING, "GL: OpenGL ES context not supported by GPU");
+ }
+
int contextAttribs[] = {
- WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
- WGL_CONTEXT_MINOR_VERSION_ARB, 3,
- WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, // WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, WGL_CONTEXT_ES_PROFILE_BIT_EXT (if supported)
+ WGL_CONTEXT_MAJOR_VERSION_ARB, glContextVersionMajor,
+ WGL_CONTEXT_MINOR_VERSION_ARB, glContextVersionMinor,
+ WGL_CONTEXT_PROFILE_MASK_ARB, glContextProfile, // WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, WGL_CONTEXT_ES_PROFILE_BIT_EXT (if supported)
//WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB [glDebugMessageCallback()]
0 // Terminator
};
@@ -1387,9 +1483,11 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
// Initialize platform: graphics, inputs and more
int InitPlatform(void)
{
- platform.desiredFlags = SanitizeFlags(SANITIZE_FLAGS_FIRST, CORE.Window.flags);
+ int result = 0;
+
platform.appScreenWidth = CORE.Window.screen.width;
platform.appScreenHeight = CORE.Window.screen.height;
+ platform.desiredFlags = SanitizeFlags(0 /*SANITIZE_FLAGS_FIRST*/, CORE.Window.flags);
// NOTE: From this point CORE.Window.flags should always reflect the actual state of the window
CORE.Window.flags = FLAG_WINDOW_HIDDEN | (platform.desiredFlags & FLAG_MASK_NO_UPDATE);
@@ -1400,7 +1498,7 @@ int InitPlatform(void)
if (IsWindows10Version1703OrGreaterWin32())
{
TRACELOG(LOG_INFO, "DpiAware: >=Win10Creators");
- if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
+ if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
TRACELOG(LOG_ERROR, "%s failed, error %u", "SetProcessDpiAwarenessContext", GetLastError());
}
else
@@ -1411,37 +1509,56 @@ int InitPlatform(void)
}
*/
+ HINSTANCE hInstance = GetModuleHandleW(0);
+
+ // Define window class
WNDCLASSEXW windowClass = {
.cbSize = sizeof(WNDCLASSEXW),
.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
.lpfnWndProc = WndProc, // Custom procedure assigned
.cbWndExtra = sizeof(LONG_PTR), // extra space for the Tuple object ptr
- .hInstance = GetModuleHandleW(0),
+ .hInstance = hInstance,
.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW), // TODO: Audit if we want to set this since we're implementing WM_SETCURSOR
- .lpszClassName = CLASS_NAME //L"GLWindowClass";
+ .lpszClassName = CLASS_NAME // Class name: L"raylibWindow"
};
- // Register window class
- if (RegisterClassExW(&windowClass) == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "RegisterClass", GetLastError());
+ // Load user-provided icon if available
+ // NOTE: raylib resource file defaults to GLFW_ICON id, so looking for same identifier
+ windowClass.hIcon = LoadImageW(hInstance, L"GLFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+ if (!windowClass.hIcon) windowClass.hIcon = LoadImageW(NULL, (LPCWSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
-/*
- // TODO: Remove or move this code that sets the display size; should maybe go somewhere in WndProc?
+ // Register window class
+ result = (int)RegisterClassExW(&windowClass);
+ if (result == 0) TRACELOG(LOG_ERROR, "WIN32: Failed to register window class [ERROR: %lu]", GetLastError());
+
+ // Get primary monitor info
POINT primaryTopLeft = { 0 };
HMONITOR monitor = MonitorFromPoint(primaryTopLeft, MONITOR_DEFAULTTOPRIMARY);
if (monitor != NULL)
{
- MONITORINFO info;
+ MONITORINFO info = { 0 };
info.cbSize = sizeof(info);
- if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_WARNING, "%s failed, error: %u", "GetMonitorInfo", GetLastError());
+ result = (int)GetMonitorInfoW(monitor, &info);
+
+ if (result == 0) TRACELOG(LOG_WARNING, "WIN32: DISPLAY: Failed to get monitor info [ERROR: %u]", GetLastError());
else
{
CORE.Window.display.width = info.rcMonitor.right - info.rcMonitor.left;
CORE.Window.display.height = info.rcMonitor.bottom - info.rcMonitor.top;
}
}
- else TRACELOG(LOG_WARNING, "MonitorFromPoint, error: %s", GetLastError());
-*/
-
+ else TRACELOG(LOG_WARNING, "WIN32: DISPLAY: Failed to get primary monitor from point [ERROR: %u]", GetLastError());
+
+ // Adjust the window rectangle so the *client area* matches desired size
+ // NOTE: Window width/height includes borders and title-bar
+ DWORD style = WS_OVERLAPPEDWINDOW;
+ RECT rect = { 0, 0, platform.appScreenWidth, platform.appScreenHeight };
+ AdjustWindowRect(&rect, style, FALSE);
+ //AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, FALSE, WINDOW_STYLE_EX);
+ //AdjustWindowRectExForDpi(&rect, style, FALSE, WINDOW_STYLE_EX, dpi);
+ int windowWidth = rect.right - rect.left;
+ int windowHeight = rect.bottom - rect.top;
+
// Create window
// NOTE: Title string needs to be converted to WCHAR
WCHAR *titleWide = NULL;
@@ -1454,13 +1571,13 @@ int InitPlatform(void)
titleWide,
MakeWindowStyle(CORE.Window.flags), // WS_OVERLAPPEDWINDOW | WS_VISIBLE
CW_USEDEFAULT, CW_USEDEFAULT,
- platform.appScreenWidth, platform.appScreenHeight, // TODO: Window size [width, height], needs to be updated?
+ windowWidth, windowHeight, // TODO: Window size [width, height], needs to be updated?
NULL, NULL,
GetModuleHandleW(NULL), NULL);
if (!platform.hwnd)
{
- TRACELOG(LOG_ERROR, "%s failed, error=%lu", "CreateWindow", GetLastError());
+ TRACELOG(LOG_ERROR, "WIN32: WINDOW: Failed to create window [ERROR: %lu]", GetLastError());
return -1;
}
@@ -1475,11 +1592,11 @@ int InitPlatform(void)
// Initialize software framebuffer
BITMAPINFO bmi = { 0 };
ZeroMemory(&bmi, sizeof(bmi));
- bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bmi.bmiHeader.biWidth = platform.appScreenWidth;
- bmi.bmiHeader.biHeight = -(int)(platform.appScreenHeight); // Top-down bitmap
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = 32; // 32-bit BGRA
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = platform.appScreenWidth;
+ bmi.bmiHeader.biHeight = -(int)(platform.appScreenHeight); // Top-down bitmap
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32; // 32-bit BGRA
bmi.bmiHeader.biCompression = BI_RGB;
platform.hdcmem = CreateCompatibleDC(platform.hdc);
@@ -1499,11 +1616,12 @@ int InitPlatform(void)
}
CORE.Window.ready = true;
-
- // TODO: Should this function be called before or after drawing context is created? --> After swInit() called!
- //UpdateWindowSize(UPDATE_WINDOW_FIRST, platform.hwnd, platform.appScreenWidth, platform.appScreenHeight, platform.desiredFlags);
+
+ // Update flags (in case of deferred state change required)
UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight);
+ CORE.Window.render.width = CORE.Window.screen.width;
+ CORE.Window.render.height = CORE.Window.screen.height;
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
@@ -1512,20 +1630,32 @@ int InitPlatform(void)
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
- CORE.Storage.basePath = GetWorkingDirectory();
+ if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer
+ {
+ TRACELOG(LOG_INFO, "GL: OpenGL device information:");
+ TRACELOG(LOG_INFO, " > Vendor: %s", "raylib");
+ TRACELOG(LOG_INFO, " > Renderer: %s", "rlsw - OpenGL 1.1 Software Renderer");
+ TRACELOG(LOG_INFO, " > Version: %s", "1.0");
+ TRACELOG(LOG_INFO, " > GLSL: %s", "NOT SUPPORTED");
+ }
+ // Initialize timming system
+ //----------------------------------------------------------------------------
LARGE_INTEGER time = { 0 };
QueryPerformanceCounter(&time);
QueryPerformanceFrequency(&platform.timerFrequency);
CORE.Time.base = time.QuadPart;
InitTimer();
-
- // TODO: Enable cursor? -> Use default value as 0
- platform.cursorEnabled = true;
+ //----------------------------------------------------------------------------
+
+ // Initialize storage system
+ //----------------------------------------------------------------------------
+ CORE.Storage.basePath = GetWorkingDirectory();
+ //----------------------------------------------------------------------------
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP: WIN32: Initialized successfully");
-
+
return 0;
}
@@ -1535,7 +1665,7 @@ void ClosePlatform(void)
if (platform.hwnd)
{
int result = DestroyWindow(platform.hwnd);
- if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Error on window destroy: %u", GetLastError());
+ if (result == 0) TRACELOG(LOG_WARNING, "WIN32: WINDOW: Failed on window destroy [ERROR: %u]", GetLastError());
platform.hwnd = NULL;
}
}
@@ -1556,7 +1686,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
FlagsOp flagsOp = { 0 };
FlagsOp *deferredFlags = &flagsOp;
-
+
// Message processing
//------------------------------------------------------------------------------------
switch (msg)
@@ -1572,13 +1702,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
// Clean up for window destruction
if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer
{
- if (platform.hdcmem)
+ if (platform.hdcmem)
{
DeleteDC(platform.hdcmem);
platform.hdcmem = NULL;
}
- if (platform.hbitmap)
+ if (platform.hbitmap)
{
DeleteObject(platform.hbitmap); // Clears platform.pixels data
platform.hbitmap = NULL;
@@ -1616,9 +1746,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
if (CORE.Window.flags & FLAG_WINDOW_RESIZABLE)
{
// TODO: Enforce min/max size
- }
- else TRACELOG(LOG_WARNING, "WINDOW: Trying to resize a non-resizable window");
-
+ }
+ else TRACELOG(LOG_WARNING, "WIN32: WINDOW: Trying to resize a non-resizable window");
+
result = TRUE;
} break;
case WM_STYLECHANGING:
@@ -1629,19 +1759,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
GetStyleChangeFlagOps(CORE.Window.flags, ss, deferredFlags);
UINT dpi = GetDpiForWindow(hwnd);
- SIZE clientSize = GetClientSize(hwnd);
+ // Get client size (framebuffer inside the window)
+ RECT rect = { 0 };
+ GetClientRect(hwnd, &rect);
+ SIZE clientSize = { rect.right, rect.bottom };
SIZE oldSize = CalcWindowSize(dpi, clientSize, ss->styleOld);
SIZE newSize = CalcWindowSize(dpi, clientSize, ss->styleNew);
-
+
if (oldSize.cx != newSize.cx || oldSize.cy != newSize.cy)
{
- TRACELOG(LOG_INFO, "resize from style change: %dx%d to %dx%d", oldSize.cx, oldSize.cy, newSize.cx, newSize.cy);
-
+ TRACELOG(LOG_INFO, "WIN32: WINDOW: Resize from style change [%dx%d] to [%dx%d]", oldSize.cx, oldSize.cy, newSize.cx, newSize.cy);
+
if (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED)
{
// looks like windows will automatically "unminimize" a window
// if a style changes modifies it's size
- TRACELOG(LOG_INFO, "style change modifed window size, removing maximized flag");
+ TRACELOG(LOG_INFO, "WIN32: WINDOW: Style change modifed window size, removing maximized flag");
deferredFlags->clear |= FLAG_WINDOW_MAXIMIZED;
}
}
@@ -1650,27 +1783,20 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
case WM_WINDOWPOSCHANGING:
{
WINDOWPOS *pos = (WINDOWPOS *)lparam;
- if (pos->flags & SWP_SHOWWINDOW)
- {
- //if (pos->flags & SWP_HIDEWINDOW) abort();
- deferredFlags->clear |= FLAG_WINDOW_HIDDEN;
- }
- else if (pos->flags & SWP_HIDEWINDOW)
- {
- deferredFlags->set |= FLAG_WINDOW_HIDDEN;
- }
+ if (pos->flags & SWP_SHOWWINDOW) deferredFlags->clear |= FLAG_WINDOW_HIDDEN;
+ else if (pos->flags & SWP_HIDEWINDOW) deferredFlags->set |= FLAG_WINDOW_HIDDEN;
Mized mized = MIZED_NONE;
bool isIconic = IsIconic(hwnd);
bool styleMinimized = !!(WS_MINIMIZE & GetWindowLongPtrW(hwnd, GWL_STYLE));
- if (isIconic != styleMinimized) TRACELOG(LOG_WARNING, "IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized);
-
+ if (isIconic != styleMinimized) TRACELOG(LOG_WARNING, "WIN32: IsIconic state different from WS_MINIMIZED state");
+
if (isIconic) mized = MIZED_MIN;
else
{
WINDOWPLACEMENT placement;
placement.length = sizeof(placement);
- if (!GetWindowPlacement(hwnd, &placement)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowPlacement", GetLastError());
+ if (!GetWindowPlacement(hwnd, &placement)) TRACELOG(LOG_ERROR, "WIN32: WINDOW: FAiled to get monitor placement [ERROR: %lu]", GetLastError());
if (placement.showCmd == SW_SHOWMAXIMIZED) mized = MIZED_MAX;
}
@@ -1683,19 +1809,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO info;
info.cbSize = sizeof(info);
- if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError());
+ if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "WIN32: MONITOR: Failed to get monitor info [ERROR: %lu]", GetLastError());
if ((pos->x == info.rcMonitor.left) &&
(pos->y == info.rcMonitor.top) &&
(pos->cx == (info.rcMonitor.right - info.rcMonitor.left)) &&
- (pos->cy == (info.rcMonitor.bottom - info.rcMonitor.top)))
- {
- deferredFlags->set |= FLAG_BORDERLESS_WINDOWED_MODE;
- }
- else
- {
- deferredFlags->clear |= FLAG_BORDERLESS_WINDOWED_MODE;
- }
+ (pos->cy == (info.rcMonitor.bottom - info.rcMonitor.top))) deferredFlags->set |= FLAG_BORDERLESS_WINDOWED_MODE;
+ else deferredFlags->clear |= FLAG_BORDERLESS_WINDOWED_MODE;
} break;
case MIZED_MIN:
@@ -1739,29 +1859,30 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
float dpiScale = ((float)newDpi)/96.0f;
bool dpiScaling = CORE.Window.flags & FLAG_WINDOW_HIGHDPI;
- SIZE desired = PxFromPt2(dpiScale, dpiScaling, platform.appScreenWidth, platform.appScreenHeight);
+ // Get size in pixels from points
+ SIZE desired = {
+ .cx = dpiScaling? (int)((float)platform.appScreenWidth*dpiScale) : platform.appScreenWidth,
+ .cy = dpiScaling? (int)((float)platform.appScreenHeight*dpiScale) : platform.appScreenHeight
+ };
inoutSize->cx = desired.cx;
inoutSize->cy = desired.cy;
-
+
result = TRUE;
} break;
case WM_DPICHANGED:
{
- RECT *suggestedRect = (RECT*)lparam;
+ RECT *suggestedRect = (RECT *)lparam;
+
// Never set the window size to anything other than the suggested rect here
// Doing so can cause a window to stutter between monitors when transitioning between them
- if (!SetWindowPos(hwnd, NULL,
- suggestedRect->left,
- suggestedRect->top,
- suggestedRect->right - suggestedRect->left,
- suggestedRect->bottom - suggestedRect->top,
- SWP_NOZORDER | SWP_NOACTIVATE))
- {
- TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError());
- }
+ int result = (int)SetWindowPos(hwnd, NULL, suggestedRect->left, suggestedRect->top,
+ suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top, SWP_NOZORDER | SWP_NOACTIVATE);
+ if (result == 0) TRACELOG(LOG_ERROR, "Failed to set window position [ERROR: %lu]", GetLastError());
+
} break;
case WM_SETCURSOR:
{
+ // Called when mouse moves, enters/leaves window...
if (LOWORD(lparam) == HTCLIENT)
{
SetCursor(CORE.Input.Mouse.cursorHidden? NULL : LoadCursorW(NULL, (LPCWSTR)IDC_ARROW));
@@ -1789,7 +1910,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
} break;
case WM_MOUSEMOVE:
{
- if (platform.cursorEnabled)
+ if (!CORE.Input.Mouse.cursorLocked)
{
CORE.Input.Mouse.currentPosition.x = (float)GET_X_LPARAM(lparam);
CORE.Input.Mouse.currentPosition.y = (float)GET_Y_LPARAM(lparam);
@@ -1804,7 +1925,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
case WM_RBUTTONUP : HandleMouseButton(MOUSE_BUTTON_RIGHT, 0); break;
case WM_MBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_MIDDLE, 1); break;
case WM_MBUTTONUP : HandleMouseButton(MOUSE_BUTTON_MIDDLE, 0); break;
- case WM_XBUTTONDOWN:
+ case WM_XBUTTONDOWN:
{
switch (HIWORD(wparam))
{
@@ -1833,37 +1954,29 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
}
//------------------------------------------------------------------------------------
- // Sanity check
- if (platform.hwnd == hwnd)
- {
- CheckFlags("After WndProc", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), mask);
- }
+ // Sanity check for flags
+ if (platform.hwnd == hwnd) CheckFlags("After WndProc", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), mask);
// Operations to execute after the above check
- if (flagsOp.set & flagsOp.clear)
- {
- TRACELOG(LOG_ERROR, "the flags 0x%x were both set and cleared!", flagsOp.set & flagsOp.clear);
- }
+ if (flagsOp.set & flagsOp.clear) TRACELOG(LOG_WARNING, "WIN32: FLAGS: Flags 0x%x were both set and cleared", flagsOp.set & flagsOp.clear);
DWORD save = CORE.Window.flags;
CORE.Window.flags |= flagsOp.set;
CORE.Window.flags &= ~flagsOp.clear;
- if (save != CORE.Window.flags)
- {
- TRACELOG(LOG_DEBUG, "DeferredFlags: 0x%x > 0x%x (diff 0x%x)", save, CORE.Window.flags, save ^ CORE.Window.flags);
- }
+ if (save != CORE.Window.flags) TRACELOG(LOG_DEBUG, "WIN32: FLAGS: Current deferred flags: 0x%x > 0x%x (diff 0x%x)", save, CORE.Window.flags, save ^ CORE.Window.flags);
return result;
}
+// Handle keyboard input event
static void HandleKey(WPARAM wparam, LPARAM lparam, char state)
{
- KeyboardKey key = KeyFromWparam(wparam);
-
+ KeyboardKey key = GetKeyFromWparam(wparam);
+
// TODO: Use scancode?
//BYTE scancode = lparam >> 16;
//TRACELOG(LOG_INFO, "KEY key=%d vk=%lu scan=%u = %u", key, wparam, scancode, state);
-
+
if (key != KEY_NULL)
{
CORE.Input.Keyboard.currentKeyState[key] = state;
@@ -1875,22 +1988,25 @@ static void HandleKey(WPARAM wparam, LPARAM lparam, char state)
// TODO: Add key to the queue as well?
}
+// Handle mouse button input event
static void HandleMouseButton(int button, char state)
{
+ // Register current mouse button state
CORE.Input.Mouse.currentButtonState[button] = state;
CORE.Input.Touch.currentTouchState[button] = state;
}
+// Handle raw input event
static void HandleRawInput(LPARAM lparam)
{
RAWINPUT input = { 0 };
UINT inputSize = sizeof(input);
UINT size = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &input, &inputSize, sizeof(RAWINPUTHEADER));
-
- if (size == (UINT)-1) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetRawInputData", GetLastError());
-
- if (input.header.dwType != RIM_TYPEMOUSE) TRACELOG(LOG_ERROR, "Unexpected WM_INPUT type %lu", input.header.dwType);
+
+ if (size == (UINT)-1) TRACELOG(LOG_ERROR, "WIN32: Failed to get raw input data [ERROR: %lu]", GetLastError());
+
+ if (input.header.dwType != RIM_TYPEMOUSE) TRACELOG(LOG_ERROR, "WIN32: Unexpected WM_INPUT type %lu", input.header.dwType);
if (input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) TRACELOG(LOG_ERROR, "TODO: handle absolute mouse inputs!");
@@ -1904,16 +2020,19 @@ static void HandleRawInput(LPARAM lparam)
//if (CORE.Input.Mouse.currentPosition.y != 0) abort();
}
+// Handle window resizing event
static void HandleWindowResize(HWND hwnd, int *width, int *height)
{
if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) return;
- SIZE clientSize = GetClientSize(hwnd);
+ // Get client size (framebuffer inside the window)
+ RECT rect = { 0 };
+ GetClientRect(hwnd, &rect);
+ SIZE clientSize = { rect.right, rect.bottom };
- //TRACELOG(LOG_DEBUG, "WINDOW: New widow client size: [%lux%lu]", clientSize.cx, clientSize.cy);
-
- //CORE.Window.currentFbo.width = clientSize.cx;
- //CORE.Window.currentFbo.height = clientSize.cy;
+ // TODO: Update framebuffer on resize
+ CORE.Window.currentFbo.width = (int)clientSize.cx;
+ CORE.Window.currentFbo.height = (int)clientSize.cy;
//glViewport(0, 0, clientSize.cx, clientSize.cy);
//SetupFramebuffer(0, 0);
@@ -1925,18 +2044,16 @@ static void HandleWindowResize(HWND hwnd, int *width, int *height)
unsigned int screenHeight = highdpi? (unsigned int)(((float)clientSize.cy)/dpiScale) : clientSize.cy;
CORE.Window.screen.width = screenWidth;
CORE.Window.screen.height = screenHeight;
-
+
if (AdoptWindowResize(CORE.Window.flags))
{
- TRACELOG(LOG_DEBUG, "WINDOW: Updating app size to %ix%i from window resize", screenWidth, screenHeight);
+ TRACELOG(LOG_DEBUG, "WIN32: WINDOW: Updating app size to [%ix%i] from window resize", screenWidth, screenHeight);
*width = screenWidth;
*height = screenHeight;
}
- CORE.Window.screenScale = MatrixScale(
- (float)CORE.Window.render.width/CORE.Window.screen.width,
- (float)CORE.Window.render.height/CORE.Window.screen.height,
- 1.0f);
+ CORE.Window.screenScale = MatrixScale( (float)CORE.Window.render.width/CORE.Window.screen.width,
+ (float)CORE.Window.render.height/CORE.Window.screen.height, 1.0f);
}
// Update window style
@@ -1944,22 +2061,28 @@ static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags)
{
DWORD current = STYLE_MASK_WRITABLE & MakeWindowStyle(CORE.Window.flags);
DWORD desired = STYLE_MASK_WRITABLE & MakeWindowStyle(desiredFlags);
-
+
if (current != desired)
{
SetLastError(0);
DWORD previous = STYLE_MASK_WRITABLE & SetWindowLongPtrW(hwnd, GWL_STYLE, desired);
if (previous != current)
{
- TRACELOG(LOG_ERROR, "SetWindowLong returned writable flags 0x%x but expected 0x%x (diff=0x%x, error=%lu)",
+ TRACELOG(LOG_ERROR, "WIN32: WINDOW: SetWindowLongPtr() returned writable flags 0x%x but expected 0x%x (diff=0x%x, error=%lu)",
previous, current, previous ^ current, GetLastError());
}
CheckFlags("UpdateWindowStyle", hwnd, desiredFlags, desired, STYLE_MASK_WRITABLE);
}
- Mized currentMized = MizedFromStyle(MakeWindowStyle(CORE.Window.flags));
- Mized desiredMized = MizedFromStyle(MakeWindowStyle(desiredFlags));
+ // Minimized takes precedence over maximized
+ Mized currentMized = MIZED_NONE;
+ Mized desiredMized = MIZED_NONE;
+ if (CORE.Window.flags & WS_MINIMIZE) currentMized = MIZED_MIN;
+ else if (CORE.Window.flags & WS_MAXIMIZE) currentMized = MIZED_MAX;
+ if (desiredFlags & WS_MINIMIZE) currentMized = MIZED_MIN;
+ else if (desiredFlags & WS_MAXIMIZE) currentMized = MIZED_MAX;
+
if (currentMized != desiredMized)
{
switch (desiredMized)
@@ -1972,24 +2095,21 @@ static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags)
}
// Sanitize flags
-static unsigned SanitizeFlags(SanitizeFlagsKind kind, unsigned flags)
+static unsigned SanitizeFlags(int mode, unsigned flags)
{
if ((flags & FLAG_WINDOW_MAXIMIZED) && (flags & FLAG_BORDERLESS_WINDOWED_MODE))
{
- TRACELOG(LOG_INFO, "borderless windows mode is overriding maximized");
+ TRACELOG(LOG_WARNING, "WIN32: WINDOW: Borderless windows mode overriding maximized window flag");
flags &= ~FLAG_WINDOW_MAXIMIZED;
}
- switch (kind)
+ if (mode == 1)
{
- case SANITIZE_FLAGS_FIRST: break;
- case SANITIZE_FLAGS_NORMAL:
- if ((flags & FLAG_MSAA_4X_HINT) && (!(CORE.Window.flags & FLAG_MSAA_4X_HINT)))
- {
- TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
- flags &= ~FLAG_MSAA_4X_HINT;
- }
- break;
+ if ((flags & FLAG_MSAA_4X_HINT) && (!(CORE.Window.flags & FLAG_MSAA_4X_HINT)))
+ {
+ TRACELOG(LOG_WARNING, "WIN32: WINDOW: MSAA can only be configured before window initialization");
+ flags &= ~FLAG_MSAA_4X_HINT;
+ }
}
return flags;
@@ -2018,16 +2138,15 @@ static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height)
CORE.Window.flags |= (desiredFlags & FLAG_MASK_NO_UPDATE);
int vsync = (CORE.Window.flags & FLAG_VSYNC_HINT)? 1 : 0;
- PFNWGLSWAPINTERVALEXTPROC wglSwapInterval = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
- if (wglSwapInterval)
+ if (wglSwapIntervalEXT)
{
- (*wglSwapInterval)(vsync);
+ (*wglSwapIntervalEXT)(vsync);
if (vsync) CORE.Window.flags |= FLAG_VSYNC_HINT;
else CORE.Window.flags &= ~FLAG_VSYNC_HINT;
}
// TODO: Review all this code...
- DWORD previousStyle;
+ DWORD previousStyle = 0;
for (unsigned attempt = 1; ; attempt++)
{
CheckFlags("UpdateFlags", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), STYLE_MASK_ALL);
@@ -2035,15 +2154,14 @@ static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height)
bool windowSizeUpdated = false;
if (MakeWindowStyle(CORE.Window.flags) == MakeWindowStyle(desiredFlags))
{
- windowSizeUpdated = UpdateWindowSize(UPDATE_WINDOW_NORMAL, hwnd, width, height, desiredFlags);
+ windowSizeUpdated = UpdateWindowSize(1, hwnd, width, height, desiredFlags);
if ((FLAG_MASK_REQUIRED & desiredFlags) == (FLAG_MASK_REQUIRED & CORE.Window.flags)) break;
}
- if ((attempt > 1) &&
- (previousStyle == MakeWindowStyle(CORE.Window.flags)) &&
- !windowSizeUpdated)
+
+ if ((attempt > 1) && (previousStyle == MakeWindowStyle(CORE.Window.flags)) && !windowSizeUpdated)
{
- TRACELOG(LOG_ERROR, "WINDOW: UpdateFlags() failed after %u attempt(s) wanted 0x%x but is 0x%x (diff=0x%x)",
+ TRACELOG(LOG_ERROR, "WIN32: WINDOW: UpdateFlags() failed after %u attempt(s) wanted 0x%x but is 0x%x (diff=0x%x)",
attempt, desiredFlags, CORE.Window.flags, desiredFlags ^ CORE.Window.flags);
}
@@ -2051,3 +2169,21 @@ static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height)
UpdateWindowStyle(hwnd, desiredFlags);
}
}
+
+// Check if OpenGL extension is available
+static bool IsWglExtensionAvailable(HDC hdc, const char *extension)
+{
+ bool result = false;
+
+ if (wglGetExtensionsStringARB != NULL)
+ {
+ const char *extList = wglGetExtensionsStringARB(hdc);
+ if (extList != NULL)
+ {
+ // Simple substring search (could use strtok or strstr)
+ if (strstr(extList, extension) != NULL) result = true;
+ }
+ }
+
+ return result;
+}
\ No newline at end of file
diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c
index 58e820af1..da0d08aca 100644
--- a/src/platforms/rcore_drm.c
+++ b/src/platforms/rcore_drm.c
@@ -824,15 +824,6 @@ void SwapScreenBuffer(void)
return;
}
- // Get the software rendered color buffer
- int bufferWidth = 0, bufferHeight = 0;
- void *colorBuffer = swGetColorBuffer(&bufferWidth, &bufferHeight);
- if (!colorBuffer)
- {
- TRACELOG(LOG_ERROR, "DISPLAY: Failed to get software color buffer");
- return;
- }
-
// Retrieving the dimensions of the display mode used
drmModeModeInfo *mode = &platform.connector->modes[platform.modeIndex];
uint32_t width = mode->hdisplay;
@@ -864,7 +855,7 @@ void SwapScreenBuffer(void)
// Create framebuffer with the correct format
uint32_t fb = 0;
result = drmModeAddFB(platform.fd, width, height, depth, bpp, creq.pitch, creq.handle, &fb);
- if (result != 0)
+ if (result != 0)
{
TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d (%s)", result, strerror(errno));
struct drm_mode_destroy_dumb dreq = { 0 };
@@ -900,16 +891,8 @@ void SwapScreenBuffer(void)
}
// Copy the software rendered buffer to the dumb buffer with scaling if needed
- if (bufferWidth == width && bufferHeight == height)
- {
- // Direct copy if sizes match
- swCopyFramebuffer(0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
- }
- else
- {
- // Scale the software buffer to match the display mode
- swBlitFramebuffer(0, 0, width, height, 0, 0, bufferWidth, bufferHeight, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
- }
+ // NOTE: RLSW will make a simple copy if the dimensions match
+ swBlitFramebuffer(0, 0, width, height, 0, 0, width, height, SW_RGBA, SW_UNSIGNED_BYTE, dumbBuffer);
// Unmap the buffer
munmap(dumbBuffer, creq.size);
@@ -974,12 +957,12 @@ void SwapScreenBuffer(void)
// Set CRTC with better error handling
result = drmModeSetCrtc(platform.fd, crtcId, fb, 0, 0, &platform.connector->connector_id, 1, mode);
- if (result != 0)
+ if (result != 0)
{
TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d (%s)", result, strerror(errno));
TRACELOG(LOG_ERROR, "DISPLAY: CRTC ID: %u, FB ID: %u, Connector ID: %u", crtcId, fb, platform.connector->connector_id);
TRACELOG(LOG_ERROR, "DISPLAY: Mode: %dx%d@%d", mode->hdisplay, mode->vdisplay, mode->vrefresh);
-
+
drmModeRmFB(platform.fd, fb);
struct drm_mode_destroy_dumb dreq = {0};
dreq.handle = creq.handle;
@@ -1229,7 +1212,7 @@ int InitPlatform(void)
}
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i modes detected: %i", i, con->count_modes);
- TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i,
+ TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i,
(con->connection == DRM_MODE_CONNECTED) ? "CONNECTED" :
(con->connection == DRM_MODE_DISCONNECTED) ? "DISCONNECTED" :
(con->connection == DRM_MODE_UNKNOWNCONNECTION) ? "UNKNOWN" : "OTHER");
@@ -1357,10 +1340,10 @@ int InitPlatform(void)
platform.modeIndex = 0;
CORE.Window.display.width = platform.connector->modes[0].hdisplay;
CORE.Window.display.height = platform.connector->modes[0].vdisplay;
-
- TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u) for software rendering",
+
+ TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u) for software rendering",
platform.connector->modes[0].name,
- platform.connector->modes[0].hdisplay,
+ platform.connector->modes[0].hdisplay,
platform.connector->modes[0].vdisplay,
(platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
platform.connector->modes[0].vrefresh);
diff --git a/src/rcore.c b/src/rcore.c
index f87b68783..d06e3089b 100644
--- a/src/rcore.c
+++ b/src/rcore.c
@@ -26,7 +26,8 @@
* - Linux DRM subsystem (KMS mode)
* > PLATFORM_ANDROID:
* - Android (ARM, ARM64)
-*
+* > PLATFORM_DESKTOP_WIN32 (Native Win32):
+* - Windows (Win32, Win64)
* CONFIGURATION:
* #define SUPPORT_DEFAULT_FONT (default)
* Default font is loaded on window initialization to be available for the user to render simple text.
@@ -161,7 +162,10 @@
#endif
// Platform specific defines to handle GetApplicationDirectory()
-#if (defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)) || (defined(_MSC_VER) && defined(PLATFORM_DESKTOP_RGFW))
+#if defined(_WIN32)
+ #if !defined(MAX_PATH)
+ #define MAX_PATH 260
+ #endif
struct HINSTANCE__;
#if defined(__cplusplus)
@@ -679,12 +683,15 @@ void InitWindow(int width, int height, const char *title)
// Initialize window data
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
+ CORE.Window.currentFbo.width = CORE.Window.screen.width;
+ CORE.Window.currentFbo.height = CORE.Window.screen.height;
+
CORE.Window.eventWaiting = false;
- CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
+ CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
// Initialize global input state
- memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
+ memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
@@ -696,13 +703,13 @@ void InitWindow(int width, int height, const char *title)
if (result != 0)
{
- TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize Platform");
+ TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize platform");
return;
}
//--------------------------------------------------------------
// Initialize rlgl default data (buffers and shaders)
- // NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
+ // NOTE: Current fbo size stored as globals in rlgl for convenience
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
isGpuReady = true; // Flag to note GPU has been initialized successfully
@@ -2521,7 +2528,7 @@ int MakeDirectory(const char *dirPath)
// Create final directory
if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);
RL_FREE(pathcpy);
-
+
// In case something failed and requested directory
// was not successfully created, return -1
if (!DirectoryExists(dirPath)) return -1;
@@ -3145,7 +3152,7 @@ unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
unsigned char *block = buffer + (blockN*64);
unsigned int w[64];
for (int i = 0; i < 16; i++)
- {
+ {
w[i] =
((unsigned int)block[i*4 + 0] << 24) |
((unsigned int)block[i*4 + 1] << 16) |
diff --git a/src/rlgl.h b/src/rlgl.h
index f587d81a2..99e9037d5 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -21,6 +21,7 @@
* Internal buffer (and resources) must be manually unloaded calling rlglClose()
*
* CONFIGURATION:
+* #define GRAPHICS_API_OPENGL_11_SOFTWARE
* #define GRAPHICS_API_OPENGL_11
* #define GRAPHICS_API_OPENGL_21
* #define GRAPHICS_API_OPENGL_33
@@ -2329,6 +2330,16 @@ void rlglInit(int width, int height)
RLGL.State.currentMatrix = &RLGL.State.modelview;
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
+#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+ // Initialize software renderer backend
+ int result = swInit(width, height);
+ if (result == 0)
+ {
+ TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!");
+ exit(-1);
+ }
+#endif
+
// Initialize OpenGL default states
//----------------------------------------------------------
// Init state: Depth test
@@ -2345,39 +2356,28 @@ void rlglInit(int width, int height)
glFrontFace(GL_CCW); // Front face are defined counter clockwise (default)
glEnable(GL_CULL_FACE); // Enable backface culling
- // Init state: Cubemap seamless
-#if defined(GRAPHICS_API_OPENGL_33)
- glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0)
-#endif
-
#if defined(GRAPHICS_API_OPENGL_11)
// Init state: Color hints (deprecated in OpenGL 3.0+)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation
glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation)
#endif
-
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
- int result = swInit(width, height); // Initialize software renderer backend
- if (result == 0)
- {
- TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!");
- exit(-1);
- }
+#if defined(GRAPHICS_API_OPENGL_33)
+ // Init state: Cubemap seamless
+ glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0)
#endif
-
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Store screen size into global variables
RLGL.State.framebufferWidth = width;
RLGL.State.framebufferHeight = height;
-
- TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully");
- //----------------------------------------------------------
#endif
// Init state: Color/Depth buffers clear
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black)
glClearDepth(1.0f); // Set clear depth value (default)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D)
+
+ TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully");
+ //----------------------------------------------------------
}
// Vertex Buffer Object deinitialization (memory free)
diff --git a/src/rmodels.c b/src/rmodels.c
index 3c904c396..ed86fb19a 100644
--- a/src/rmodels.c
+++ b/src/rmodels.c
@@ -2352,8 +2352,6 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
Mesh mesh = model.meshes[m];
Vector3 animVertex = { 0 };
Vector3 animNormal = { 0 };
- Matrix boneMatrix = { 0 };
- Matrix InverseBoneMatrix = { 0 };
int boneId = 0;
int boneCounter = 0;
float boneWeight = 0.0;
@@ -2361,50 +2359,47 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
const int vValues = mesh.vertexCount*3;
// Skip if missing bone data, causes segfault without on some models
- if ((mesh.boneWeights == NULL) || (mesh.boneIds == NULL)) continue;
+ if ((mesh.boneWeights == NULL) || (mesh.boneIds == NULL)) continue;
- // Iterates over 4 bones per vertex
- for (int j = 0; j < 4; j++, boneCounter++)
- {
- boneWeight = mesh.boneWeights[boneCounter];
- boneId = mesh.boneIds[boneCounter];
+ for (int vCounter = 0; vCounter < vValues; vCounter += 3)
+ {
+ mesh.animVertices[vCounter] = 0;
+ mesh.animVertices[vCounter + 1] = 0;
+ mesh.animVertices[vCounter + 2] = 0;
+ if (mesh.animNormals != NULL)
+ {
+ mesh.animNormals[vCounter] = 0;
+ mesh.animNormals[vCounter + 1] = 0;
+ mesh.animNormals[vCounter + 2] = 0;
+ }
- // Early stop when no transformation will be applied
- if (boneWeight == 0.0f) continue;
+ // Iterates over 4 bones per vertex
+ for (int j = 0; j < 4; j++, boneCounter++)
+ {
+ boneWeight = mesh.boneWeights[boneCounter];
+ boneId = mesh.boneIds[boneCounter];
- boneMatrix = model.meshes[m].boneMatrices[boneId];
- InverseBoneMatrix = MatrixTranspose(MatrixInvert(boneMatrix));
+ // Early stop when no transformation will be applied
+ if (boneWeight == 0.0f) continue;
+ animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
+ animVertex = Vector3Transform(animVertex,model.meshes[m].boneMatrices[boneId]);
+ mesh.animVertices[vCounter] += animVertex.x*boneWeight;
+ mesh.animVertices[vCounter+1] += animVertex.y*boneWeight;
+ mesh.animVertices[vCounter+2] += animVertex.z*boneWeight;
+ updated = true;
- for (int vCounter = 0; vCounter < vValues; vCounter += 3)
- {
- mesh.animVertices[vCounter] = 0;
- mesh.animVertices[vCounter + 1] = 0;
- mesh.animVertices[vCounter + 2] = 0;
- if (mesh.animNormals != NULL)
- {
- mesh.animNormals[vCounter] = 0;
- mesh.animNormals[vCounter + 1] = 0;
- mesh.animNormals[vCounter + 2] = 0;
- }
- animVertex = (Vector3){ mesh.vertices[vCounter], mesh.vertices[vCounter + 1], mesh.vertices[vCounter + 2] };
- animVertex = Vector3Transform(animVertex, boneMatrix);
- mesh.animVertices[vCounter] += animVertex.x*boneWeight;
- mesh.animVertices[vCounter+1] += animVertex.y*boneWeight;
- mesh.animVertices[vCounter+2] += animVertex.z*boneWeight;
- updated = true;
-
- // Normals processing
- // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
- if ((mesh.normals != NULL) && (mesh.animNormals != NULL))
- {
- animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
- animNormal = Vector3Transform(animNormal, InverseBoneMatrix);
- mesh.animNormals[vCounter] += animNormal.x*boneWeight;
- mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
- mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
- }
- }
- }
+ // Normals processing
+ // NOTE: We use meshes.baseNormals (default normal) to calculate meshes.normals (animated normals)
+ if ((mesh.normals != NULL) && (mesh.animNormals != NULL ))
+ {
+ animNormal = (Vector3){ mesh.normals[vCounter], mesh.normals[vCounter + 1], mesh.normals[vCounter + 2] };
+ animNormal = Vector3Transform(animNormal, MatrixTranspose(MatrixInvert(model.meshes[m].boneMatrices[boneId])));
+ mesh.animNormals[vCounter] += animNormal.x*boneWeight;
+ mesh.animNormals[vCounter + 1] += animNormal.y*boneWeight;
+ mesh.animNormals[vCounter + 2] += animNormal.z*boneWeight;
+ }
+ }
+ }
if (updated)
{
diff --git a/src/rshapes.c b/src/rshapes.c
index 55f7d7fb9..2b5854f86 100644
--- a/src/rshapes.c
+++ b/src/rshapes.c
@@ -1432,6 +1432,7 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
Rectangle shapeRect = GetShapesTextureRectangle();
rlBegin(RL_QUADS);
+ rlNormal3f(0.0f, 0.0f, 1.0f);
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
@@ -1441,7 +1442,7 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
rlVertex2f(v2.x, v2.y);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
- rlVertex2f(v2.x, v2.y);
+ rlVertex2f(v3.x, v3.y);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(v3.x, v3.y);
diff --git a/src/rtext.c b/src/rtext.c
index 9951dc66d..b4cd560ba 100644
--- a/src/rtext.c
+++ b/src/rtext.c
@@ -1701,9 +1701,9 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
char *TextReplace(const char *text, const char *search, const char *replacement)
{
char *result = NULL;
-
+
if (!text || !search) return NULL; // Sanity check
-
+
char *insertPoint = NULL; // Next insert point
char *temp = NULL; // Temp pointer
int searchLen = 0; // Search string length of (the string to remove)
@@ -1753,7 +1753,7 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c
char *result = NULL;
if (!text || !begin || !end) return NULL; // Sanity check
-
+
int beginIndex = TextFindIndex(text, begin);
if (beginIndex > -1)
diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md
index e058e09a7..7734a234c 100644
--- a/tools/rexm/examples_report.md
+++ b/tools/rexm/examples_report.md
@@ -64,6 +64,7 @@ Example elements validated:
| core_highdpi_testbed | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_screen_recording | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| core_clipboard_text | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| core_text_file_loading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_basic_shapes | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_bouncing_ball | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_bullet_hell | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -92,9 +93,12 @@ Example elements validated:
| shapes_pie_chart | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_kaleidoscope | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_clock_of_clocks | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_math_sine_cosine | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_mouse_trail | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_simple_particles | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shapes_starfield_effect | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_lines_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shapes_math_angle_rotation | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_logo_raylib | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_srcrec_dstrec | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| textures_image_drawing | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -161,6 +165,7 @@ Example elements validated:
| models_tesseract_view | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| models_basic_voxel | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| models_rotating_cube | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| models_decals | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_ascii_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_basic_lighting | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_model_shader | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -173,6 +178,8 @@ Example elements validated:
| shaders_texture_outline | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_texture_waves | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_julia_set | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shaders_mandelbrot_set | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shaders_color_correction | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_eratosthenes_sieve | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_fog_rendering | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| shaders_simple_mask | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
@@ -204,4 +211,4 @@ Example elements validated:
| easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
| embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
diff --git a/tools/rexm/examples_report_issues.md b/tools/rexm/examples_report_issues.md
index 3136c2709..8d24a251d 100644
--- a/tools/rexm/examples_report_issues.md
+++ b/tools/rexm/examples_report_issues.md
@@ -27,4 +27,4 @@ Example elements validated:
| easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
| embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| web_basic_window | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c
index 20fc1d5e5..f45ce9be3 100644
--- a/tools/rexm/rexm.c
+++ b/tools/rexm/rexm.c
@@ -239,7 +239,7 @@ int main(int argc, char *argv[])
// build : Build example for Desktop and Web platforms
// validate : Validate examples collection, generates report
// update : Validate and update examples collection, generates report
-
+
if (strcmp(argv[1], "create") == 0)
{
// Check for valid upcoming argument
@@ -394,8 +394,8 @@ int main(int argc, char *argv[])
{
// Support building not only individual examples but categories and "ALL"
if ((strcmp(argv[2], "ALL") == 0) || TextInList(argv[2], exCategories, REXM_MAX_EXAMPLE_CATEGORIES))
- {
- // Category/ALL rebuilt requested
+ {
+ // Category/ALL rebuilt requested
strcpy(exRebuildRequested, argv[2]);
}
else
@@ -464,12 +464,14 @@ int main(int argc, char *argv[])
// Create: raylib/examples//_example_name.png
if (FileExists(TextFormat("%s/%s.png", GetDirectoryPath(inFileName), exName)))
{
+ LOG("INFO: [%s] Copying file screenshot...\n", GetFileName(inFileName));
FileCopy(TextFormat("%s/%s.png", GetDirectoryPath(inFileName), exName),
TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName));
}
else // No screenshot available next to source file
{
// Copy screenshot template
+ LOG("WARNING: [%s] No screenshot found, using placeholder screenshot\n", GetFileName(inFileName));
FileCopy(exTemplateScreenshot, TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName));
}
@@ -478,10 +480,13 @@ int main(int argc, char *argv[])
// Scan resources used in example to copy
// NOTE: resources path will be relative to example source file directory
int resPathCount = 0;
+ LOG("INFO: [%s] Scanning file for resources...\n", GetFileName(inFileName));
char **resPaths = ScanExampleResources(TextFormat("%s/%s.c", GetDirectoryPath(inFileName), exName), &resPathCount);
if (resPathCount > 0)
{
+ LOG("INFO: [%s] Required resources found: %i\n", GetFileName(inFileName), resPathCount);
+
for (int r = 0; r < resPathCount; r++)
{
// WARNING: Special case to consider: shaders, resource paths could use conditions: "glsl%i"
@@ -494,7 +499,7 @@ int main(int argc, char *argv[])
{
char *resPathUpdated = TextReplace(resPaths[r], "glsl%i", TextFormat("glsl%i", glslVer[v]));
- LOG("INFO: Example resource required: %s\n", resPathUpdated);
+ LOG("INFO: [%s] Resource required [%i/%i]: %s\n", GetFileName(inFileName), r, resPathCount, resPathUpdated);
if (FileExists(TextFormat("%s/%s", GetDirectoryPath(inFileName), resPathUpdated)))
{
@@ -515,7 +520,7 @@ int main(int argc, char *argv[])
}
else
{
- LOG("INFO: Example resource required: %s\n", resPaths[r]);
+ LOG("INFO: [%s] Resource required [%i/%i]: %s\n", GetFileName(inFileName), r, resPathCount, resPaths[r]);
if (FileExists(TextFormat("%s/%s", GetDirectoryPath(inFileName), resPaths[r])))
{
@@ -543,6 +548,8 @@ int main(int argc, char *argv[])
char *exCollectionList = LoadFileText(exCollectionFilePath);
if (TextFindIndex(exCollectionList, exName) == -1) // Example not found
{
+ LOG("INFO: [%s] Adding example to collection list (%s)\n", GetFileName(inFileName), exCategory);
+
char *exCollectionListUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); // Updated list copy, 2MB
// Add example to the main list, by category
@@ -560,9 +567,15 @@ int main(int argc, char *argv[])
// Get required example info from example file header (if provided)
- // NOTE: If no example info is provided (other than category/name), just using some default values
+ // NOTE: Load example info from provided example header
rlExampleInfo *exInfo = LoadExampleInfo(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
+ LOG("INFO: [%s] Example info: \n", GetFileName(inFileName));
+ LOG(" > Author: %s (@%s)\n", exInfo->author, exInfo->authorGitHub);
+ LOG(" > Stars: %i\n", exInfo->stars);
+ LOG(" > Version-Update: %s-%s\n", exInfo->verCreated, exInfo->verUpdated);
+ LOG(" > Created-Reviewed: %i-%i\n", exInfo->yearCreated, exInfo->yearReviewed);
+
// Get example difficulty stars text
char starsText[16] = { 0 };
for (int i = 0; i < 4; i++)
@@ -599,13 +612,14 @@ int main(int argc, char *argv[])
UnloadFileText(exCollectionList);
//------------------------------------------------------------------------------------------------
- // Update: Makefile, Makefile.Web, README.md, examples.js
+ // Update: Metadata, Makefile, Makefile.Web, README.md, examples.js
//------------------------------------------------------------------------------------------------
UpdateRequiredFiles();
//------------------------------------------------------------------------------------------------
// Create: raylib/projects/VS2022/examples/_example_name.vcxproj
//------------------------------------------------------------------------------------------------
+ LOG("INFO: [%s] Creating example project\n", TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName));
// WARNING: When adding new project a unique UUID should be assigned!
FileCopy(TextFormat("%s/../projects/VS2022/examples/core_basic_window.vcxproj", exBasePath),
TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName));
@@ -619,6 +633,7 @@ int main(int argc, char *argv[])
// we must store provided file paths because pointers will be overwriten
// TODO: It seems projects are added to solution BUT not to required solution folder,
// that process still requires to be done manually
+ LOG("INFO: [%s] Adding project to raylib solution (.sln)\n", TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName));
AddVSProjectToSolution(exVSProjectSolutionFile,
TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName), exCategory);
//------------------------------------------------------------------------------------------------
@@ -633,17 +648,21 @@ int main(int argc, char *argv[])
// WARNING 1: EMSDK_PATH must be set to proper location when calling from GitHub Actions
// WARNING 2: raylib.a and raylib.web.a must be available when compiling locally
#if defined(_WIN32)
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", GetFileNameWithoutExt(inFileName));
//putenv("RAYLIB_DIR=C:\\GitHub\\raylib");
- putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
+ _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
#else
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", GetFileNameWithoutExt(inFileName));
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
#endif
// Update generated .html metadata
+ LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exName));
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
// Copy results to web side
+ LOG("INFO: [%s] Copy example build to raylib.com\n", exName);
FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName),
TextFormat("%s/%s/%s.html", exWebPath, exCategory, exName));
FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exCategory, exName),
@@ -732,7 +751,7 @@ int main(int argc, char *argv[])
// Recompile example (on raylib side)
// WARNING: EMSDK_PATH must be set to proper location when calling from GitHub Actions
#if defined(_WIN32)
- putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
+ _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename));
#else
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRecategory, exRename));
@@ -776,6 +795,7 @@ int main(int argc, char *argv[])
// Remove example from collection for files update
//------------------------------------------------------------------------------------------------
+ LOG("INFO: [%s] Removing example from collection\n", exName);
char *exCollectionList = LoadFileText(exCollectionFilePath);
int exIndex = TextFindIndex(exCollectionList, TextFormat("%s;%s", exCategory, exName));
if (exIndex > 0) // Example found
@@ -831,22 +851,33 @@ int main(int argc, char *argv[])
// Remove: raylib/examples//_example_name.c
// Remove: raylib/examples//_example_name.png
+ LOG("INFO: [%s] Removing example code file\n", TextFormat("%s.c", exName));
FileRemove(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
+ LOG("INFO: [%s] Removing example screenshot file\n", TextFormat("%s.png", exName));
FileRemove(TextFormat("%s/%s/%s.png", exBasePath, exCategory, exName));
// Edit: Update required files: Makefile, Makefile.Web, README.md, examples.js
UpdateRequiredFiles();
// Remove: raylib/projects/VS2022/examples/_example_name.vcxproj
+ LOG("INFO: [%s] Removing example project file\n", TextFormat("%s.vcxproj", exName));
FileRemove(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exName));
// Edit: raylib/projects/VS2022/raylib.sln --> Remove example project
+ LOG("INFO: [%s] Removing example from raylib solution (.sln)\n", exName);
RemoveVSProjectFromSolution(TextFormat("%s/../projects/VS2022/raylib.sln", exBasePath), exName);
+ // Remove: Delete example build from local copy (if exists)
+ FileRemove(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName));
+ FileRemove(TextFormat("%s/%s/%s.data", exBasePath, exCategory, exName));
+ FileRemove(TextFormat("%s/%s/%s.wasm", exBasePath, exCategory, exName));
+ FileRemove(TextFormat("%s/%s/%s.js", exBasePath, exCategory, exName));
+
// Remove: raylib.com/examples//_example_name.html
// Remove: raylib.com/examples//_example_name.data
// Remove: raylib.com/examples//_example_name.wasm
// Remove: raylib.com/examples//_example_name.js
+ LOG("INFO: [%s] Deleting example from raylib.com\n", exName);
FileRemove(TextFormat("%s/%s/%s.html", exWebPath, exCategory, exName));
FileRemove(TextFormat("%s/%s/%s.data", exWebPath, exCategory, exName));
FileRemove(TextFormat("%s/%s/%s.wasm", exWebPath, exCategory, exName));
@@ -868,11 +899,10 @@ int main(int argc, char *argv[])
// Build: raylib.com/examples//_example_name.data
// Build: raylib.com/examples//_example_name.wasm
// Build: raylib.com/examples//_example_name.js
-
#if defined(_WIN32)
// Set required environment variables
//putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
- putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
+ _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
//putenv("MAKE=mingw32-make");
//ChangeDirectory(exBasePath);
#endif
@@ -880,22 +910,28 @@ int main(int argc, char *argv[])
{
// Build example for PLATFORM_DESKTOP
#if defined(_WIN32)
+ LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
#else
+ LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: POSIX)\n", exName);
system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
#endif
// Build example for PLATFORM_WEB
#if defined(_WIN32)
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
#else
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName);
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
#endif
// Update generated .html metadata
+ LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exRebuildList[i].name));
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
TextFormat("%s/%s/%s.c", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
// Copy results to web side
+ LOG("INFO: [%s] Copy example build to raylib.com\n", exRebuildList[i].name);
FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
TextFormat("%s/%s/%s.html", exWebPath, exRebuildList[i].category, exRebuildList[i].name));
FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
@@ -933,10 +969,9 @@ int main(int argc, char *argv[])
VALID_INVALID_CATEGORY
*/
- // TODO: Log more details about the validation process
-
// Scan available example .c files and add to collection missing ones
// NOTE: Source of truth is what we have in the examples directories (on validation/update)
+ LOG("INFO: Scanning available example (.c) files to be added to collection...\n");
FilePathList clist = LoadDirectoryFilesEx(exBasePath, ".c", true);
char *exList = LoadFileText(exCollectionFilePath);
@@ -968,6 +1003,9 @@ int main(int argc, char *argv[])
if (!TextIsEqual(GetFileNameWithoutExt(clist.paths[i]), "examples_template") &&
(TextFindIndex(exList, GetFileNameWithoutExt(clist.paths[i])) == -1))
{
+ // TODO: Examples to be added in the list should be added at the end of their categories,
+ // not at the end of the file...
+
// Add example to the examples collection list
// WARNING: Added to the end of the list, order must be set by users and
// defines placement on raylib webpage
@@ -1007,6 +1045,7 @@ int main(int argc, char *argv[])
UnloadDirectoryFiles(clist);
// Check all examples in collection [examples_list.txt] -> Source of truth!
+ LOG("INFO: Validating examples in collection...\n");
int exCollectionCount = 0;
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, "ALL", false, &exCollectionCount);
@@ -1016,6 +1055,8 @@ int main(int argc, char *argv[])
rlExampleInfo *exInfo = &exCollection[i];
exInfo->status = 0;
+ LOG("INFO: [%s] Validating example...\n", exInfo->name);
+
// Validate: raylib/examples//_example_name.c -> File exists?
if (!FileExists(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name))) exInfo->status |= VALID_MISSING_C;
@@ -1138,11 +1179,16 @@ int main(int argc, char *argv[])
exInfo->status |= VALID_INCONSISTENT_INFO;
}
+ if (exInfo->status == 0) LOG("INFO: [%s] Validation result: OK\n", exInfo->name);
+ else LOG("WARNING: [%s] Validation result: ISSUES FOUND\n", exInfo->name);
+
UnloadExampleInfo(exInfoHeader);
}
if (opCode == OP_UPDATE)
{
+ LOG("INFO: Updating examples with issues in collection...\n");
+
// Actions to fix/review anything possible from validation results
//------------------------------------------------------------------------------------------------
// Check examples "status" information
@@ -1162,16 +1208,16 @@ int main(int argc, char *argv[])
// NOTE: Some examples should be excluded from VS2022 solution because
// they have specific platform/linkage requirements:
- if ((strcmp(exInfo->name, "core_basic_window_web") == 0) ||
- (strcmp(exInfo->name, "core_input_gestures_web") == 0) ||
- (strcmp(exInfo->name, "raylib_opengl_interop") == 0) ||
- (strcmp(exInfo->name, "raymath_vector_angle") == 0)) continue;
+ if ((strcmp(exInfo->name, "web_basic_window") == 0) ||
+ (strcmp(exInfo->name, "raylib_opengl_interop") == 0)) continue;
// Review: Add: raylib/projects/VS2022/examples/_example_name.vcxproj
// Review: Add: raylib/projects/VS2022/raylib.sln
// Solves: VALID_MISSING_VCXPROJ, VALID_NOT_IN_VCXSOL
if (exInfo->status & VALID_MISSING_VCXPROJ)
{
+ LOG("WARNING: [%s] Missing VS2022 project file\n", exInfo->name);
+ LOG("INFO: [%s.vcxproj] Creating VS2022 project file\n", exInfo->name);
FileCopy(TextFormat("%s/../projects/VS2022/examples/core_basic_window.vcxproj", exBasePath),
TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name));
FileTextReplace(TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name),
@@ -1185,6 +1231,8 @@ int main(int argc, char *argv[])
// Add project (.vcxproj) to raylib solution (.sln)
if (exInfo->status & VALID_NOT_IN_VCXSOL)
{
+ LOG("WARNING: [%s.vcxproj] Project not included in raylib solution (.sln)\n", exInfo->name);
+ LOG("INFO: [%s.vcxproj] Adding project to raylib solution (.sln)\n", exInfo->name);
AddVSProjectToSolution(exVSProjectSolutionFile,
TextFormat("%s/../projects/VS2022/examples/%s.vcxproj", exBasePath, exInfo->name), exInfo->category);
@@ -1199,19 +1247,25 @@ int main(int argc, char *argv[])
if ((strcmp(exInfo->category, "others") != 0) && // Skipping "others" category
((exInfo->status & VALID_MISSING_WEB_OUTPUT) || (exInfo->status & VALID_MISSING_WEB_METADATA)))
{
+ LOG("WARNING: [%s] Example not available on raylib web\n", exInfo->name);
+
// Build example for PLATFORM_WEB
#if defined(_WIN32)
- putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exInfo->name);
+ _putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
#else
+ LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->name);
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
#endif
// Update generated .html metadata
+ LOG("INFO: [%s.html] Updating HTML Metadata...\n", exInfo->name);
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exInfo->category, exInfo->name),
TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name));
// Copy results to web side
+ LOG("INFO: [%s] Copy example build to raylib.com\n", exInfo->name);
FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exInfo->category, exInfo->name),
TextFormat("%s/%s/%s.html", exWebPath, exInfo->category, exInfo->name));
FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exInfo->category, exInfo->name),
@@ -1228,6 +1282,8 @@ int main(int argc, char *argv[])
if (exInfo->status & VALID_INCONSISTENT_INFO)
{
// Update source code header info
+ LOG("WARNING: [%s.c] Inconsistent source code metadata\n", exInfo->name);
+ LOG("INFO: [%s.c] Updating source code metadata...\n", exInfo->name);
UpdateSourceMetadata(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name), exInfo);
exInfo->status &= ~VALID_INCONSISTENT_INFO;
@@ -1273,6 +1329,7 @@ int main(int argc, char *argv[])
| shapes_colors_palette | ✘ | ✔ | ✘ | ✔ | ✘ | ✔ | ✔ | ✘ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| text_format_text | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✔ | ✘ | ✔ | ✔ | ✔ | ✔ |
*/
+ LOG("INFO: [examples_report.md] Generating examples validation report...\n");
char *report = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
@@ -1324,6 +1381,8 @@ int main(int argc, char *argv[])
// Generate a report with only the examples missing some elements
//-----------------------------------------------------------------------------------------------------
+ LOG("INFO: [examples_report_issues.md] Generating examples issues report...\n");
+
char *reportIssues = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
repIndex = 0;
@@ -1437,6 +1496,7 @@ static int UpdateRequiredFiles(void)
// Edit: Example source code metadata for consistency
//------------------------------------------------------------------------------------------------
+ LOG("INFO: Updating all examples metadata...\n");
int exListCount = 0;
rlExampleInfo *exList = LoadExamplesData(exCollectionFilePath, "ALL", true, &exListCount);
for (int i = 0; i < exListCount; i++)
@@ -1449,6 +1509,7 @@ static int UpdateRequiredFiles(void)
// Edit: raylib/examples/Makefile --> Update from collection
//------------------------------------------------------------------------------------------------
+ LOG("INFO: Updating raylib/examples/Makefile\n");
char *mkText = LoadFileText(TextFormat("%s/Makefile", exBasePath));
char *mkTextUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); // Updated Makefile copy, 2MB
@@ -1484,6 +1545,7 @@ static int UpdateRequiredFiles(void)
// Edit: raylib/examples/Makefile.Web --> Update from collection
// NOTE: We avoid the "others" category on web building
//------------------------------------------------------------------------------------------------
+ LOG("INFO: Updating raylib/examples/Makefile.Web\n");
char *mkwText = LoadFileText(TextFormat("%s/Makefile.Web", exBasePath));
char *mkwTextUpdated = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1); // Updated Makefile copy, 2MB
@@ -1602,6 +1664,7 @@ static int UpdateRequiredFiles(void)
// Edit: raylib/examples/README.md --> Update from collection
//------------------------------------------------------------------------------------------------
+ LOG("INFO: Updating raylib/examples/README.md\n");
// NOTE: Using [examples_list.txt] to update/regen README.md
// Lines format: | 01 | [core_basic_window](core/core_basic_window.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
char *mdText = LoadFileText(TextFormat("%s/README.md", exBasePath));
@@ -1710,6 +1773,7 @@ static int UpdateRequiredFiles(void)
// Edit: raylib.com/common/examples.js --> Update from collection
// NOTE: Entries format: exampleEntry('⭐️☆☆☆' , 'core' , 'basic_window'),
//------------------------------------------------------------------------------------------------
+ LOG("INFO: Updating raylib.com/common/examples.js\n");
char *jsText = LoadFileText(TextFormat("%s/../common/examples.js", exWebPath));
if (!jsText)
{
@@ -2233,7 +2297,7 @@ static int RemoveVSProjectFromSolution(const char *slnFile, const char *exName)
char uuid[38] = { 0 };
strcpy(uuid, "ABCDEF00-0123-4567-89AB-000000000012"); // Temp value
int textUpdatedOfsset = 0;
- int exNameLen = strlen(exName);
+ int exNameLen = (int)strlen(exName);
for (int i = 0, index = 0; i < lineCount; i++)
{
@@ -2304,7 +2368,7 @@ static void UpdateSourceMetadata(const char *exSrcPath, const rlExampleInfo *inf
char exNameFormated[256] = { 0 }; // Example name without category and using spaces
int exNameIndex = TextFindIndex(info->name, "_");
strcpy(exNameFormated, info->name + exNameIndex + 1);
- int exNameLen = strlen(exNameFormated);
+ int exNameLen = (int)strlen(exNameFormated);
for (int i = 0; i < exNameLen; i++) { if (exNameFormated[i] == '_') exNameFormated[i] = ' '; }
// Update example header title (line #3 - ALWAYS)
@@ -2432,7 +2496,7 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath)
static bool TextInList(const char *text, const char **list, int listCount)
{
bool result = false;
-
+
for (int i = 0; i < listCount; i++)
{
if (TextIsEqual(text, list[i])) { result = true; break; }