diff --git a/CMakeOptions.txt b/CMakeOptions.txt
index ce9141e22..d65ba52a3 100644
--- a/CMakeOptions.txt
+++ b/CMakeOptions.txt
@@ -2,7 +2,7 @@
include(CMakeDependentOption)
include(EnumOption)
-enum_option(PLATFORM "Desktop;Web;Android;Raspberry Pi;DRM;SDL" "Platform to build for.")
+enum_option(PLATFORM "Desktop;Web;Android;Raspberry Pi;DRM;SDL;Offscreen;None" "Platform to build for.")
enum_option(OPENGL_VERSION "OFF;4.3;3.3;2.1;1.1;ES 2.0;ES 3.0" "Force a specific OpenGL Version?")
diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake
index 6d2250c71..4dee74b07 100644
--- a/cmake/LibraryConfigurations.cmake
+++ b/cmake/LibraryConfigurations.cmake
@@ -96,7 +96,24 @@ elseif ("${PLATFORM}" MATCHES "SDL")
find_package(SDL2 REQUIRED)
set(PLATFORM_CPP "PLATFORM_DESKTOP_SDL")
set(LIBS_PRIVATE SDL2::SDL2)
+elseif ("${PLATFORM}" MATCHES "None")
+ set(PLATFORM_CPP "PLATFORM_NONE")
+ set(CUSTOMIZE_BUILD TRUE)
+ set(USE_AUDIO FALSE)
+ find_library(pthread NAMES pthread)
+ find_package(OpenGL)
+
+ set(LIBS_PRIVATE m atomic pthread ${OPENGL_LIBRARIES})
+elseif ("${PLATFORM}" MATCHES "Offscreen")
+ set(GRAPHICS "GRAPHICS_API_OPENGL_33")
+ set(PLATFORM_CPP "PLATFORM_OFFSCREEN")
+
+ find_library(pthread NAMES pthread)
+ find_package(OpenGL)
+
+ set(LIBS_PRIVATE m atomic pthread ${OPENGL_LIBRARIES})
+ set(LIBS_PRIVATE ${LIBS_PRIVATE} glfw)
endif ()
if (NOT ${OPENGL_VERSION} MATCHES "OFF")
diff --git a/examples/Makefile.Web b/examples/Makefile.Web
index bd48c2a4a..d3c8f38ca 100644
--- a/examples/Makefile.Web
+++ b/examples/Makefile.Web
@@ -448,7 +448,6 @@ MODELS = \
models/models_mesh_generation \
models/models_mesh_picking \
models/models_orthographic_projection \
- models/models_point_rendering \
models/models_rlgl_solar_system \
models/models_skybox \
models/models_waving_cubes \
@@ -478,8 +477,7 @@ SHADERS = \
shaders/shaders_texture_outline \
shaders/shaders_texture_tiling \
shaders/shaders_texture_waves \
- shaders/shaders_write_depth \
- shaders/shaders_vertex_displacement
+ shaders/shaders_write_depth
AUDIO = \
audio/audio_mixed_processor \
diff --git a/examples/README.md b/examples/README.md
index d573ff23e..d790f7d84 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -147,12 +147,11 @@ Examples using raylib models functionality, including models loading/generation
| 91 | [models_loading_vox](models/models_loading_vox.c) |
| ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) |
| 92 | [models_loading_m3d](models/models_loading_m3d.c) |
| ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) |
| 93 | [models_orthographic_projection](models/models_orthographic_projection.c) |
| ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) |
-| 94 | [models_point_rendering](models/models_point_rendering.c) |
| ⭐️⭐️☆☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) |
-| 95 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
-| 96 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) |
-| 97 | [models_waving_cubes](models/models_waving_cubes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) |
-| 98 | [models_heightmap](models/models_heightmap.c) |
| ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
-| 99 | [models_skybox](models/models_skybox.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
+| 94 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
+| 95 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) |
+| 96 | [models_waving_cubes](models/models_waving_cubes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) |
+| 97 | [models_heightmap](models/models_heightmap.c) |
| ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
+| 98 | [models_skybox](models/models_skybox.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
### category: shaders
@@ -160,25 +159,25 @@ Examples using raylib shaders functionality, including shaders loading, paramete
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 100 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) |
| ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) |
-| 101 | [shaders_model_shader](shaders/shaders_model_shader.c) |
| ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) |
-| 102 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) |
| ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
-| 103 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 104 | [shaders_postprocessing](shaders/shaders_postprocessing.c) |
| ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 105 | [shaders_palette_switch](shaders/shaders_palette_switch.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) |
-| 106 | [shaders_raymarching](shaders/shaders_raymarching.c) |
| ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) |
-| 107 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) |
| ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) |
-| 108 | [shaders_texture_outline](shaders/shaders_texture_outline.c) |
| ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) |
-| 109 | [shaders_texture_waves](shaders/shaders_texture_waves.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) |
-| 110 | [shaders_julia_set](shaders/shaders_julia_set.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) |
-| 111 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) |
-| 112 | [shaders_fog](shaders/shaders_fog.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 113 | [shaders_simple_mask](shaders/shaders_simple_mask.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 114 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) |
-| 115 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) |
| ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) |
-| 116 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 117 | [shaders_spotlight](shaders/shaders_spotlight.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 118 | [shaders_deferred_render](shaders/shaders_deferred_render.c) |
| ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) |
+| 99 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) |
| ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) |
+| 100 | [shaders_model_shader](shaders/shaders_model_shader.c) |
| ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) |
+| 101 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) |
| ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
+| 102 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 103 | [shaders_postprocessing](shaders/shaders_postprocessing.c) |
| ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 104 | [shaders_palette_switch](shaders/shaders_palette_switch.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) |
+| 105 | [shaders_raymarching](shaders/shaders_raymarching.c) |
| ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) |
+| 106 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) |
| ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) |
+| 107 | [shaders_texture_outline](shaders/shaders_texture_outline.c) |
| ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) |
+| 108 | [shaders_texture_waves](shaders/shaders_texture_waves.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) |
+| 109 | [shaders_julia_set](shaders/shaders_julia_set.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) |
+| 110 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) |
+| 111 | [shaders_fog](shaders/shaders_fog.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 112 | [shaders_simple_mask](shaders/shaders_simple_mask.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 113 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) |
+| 114 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) |
| ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) |
+| 115 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 116 | [shaders_spotlight](shaders/shaders_spotlight.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 117 | [shaders_deferred_render](shaders/shaders_deferred_render.c) |
| ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) |
### category: audio
@@ -186,10 +185,10 @@ Examples using raylib audio functionality, including sound/music loading and pla
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 119 | [audio_module_playing](audio/audio_module_playing.c) |
| ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 120 | [audio_music_stream](audio/audio_music_stream.c) |
| ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
-| 121 | [audio_raw_stream](audio/audio_raw_stream.c) |
| ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) |
-| 122 | [audio_sound_loading](audio/audio_sound_loading.c) |
| ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) |
+| 118 | [audio_module_playing](audio/audio_module_playing.c) |
| ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 119 | [audio_music_stream](audio/audio_music_stream.c) |
| ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
+| 120 | [audio_raw_stream](audio/audio_raw_stream.c) |
| ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) |
+| 121 | [audio_sound_loading](audio/audio_sound_loading.c) |
| ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) |
### category: others
@@ -197,11 +196,11 @@ Examples showing raylib misc functionality that does not fit in other categories
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 123 | [rlgl_standalone](others/rlgl_standalone.c) |
| ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) |
-| 124 | [rlgl_compute_shader](others/rlgl_compute_shader.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) |
-| 125 | [easings_testbed](others/easings_testbed.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
-| 126 | [raylib_opengl_interop](others/raylib_opengl_interop.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) |
-| 127 | [embedded_files_loading](others/embedded_files_loading.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
+| 122 | [rlgl_standalone](others/rlgl_standalone.c) |
| ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) |
+| 123 | [rlgl_compute_shader](others/rlgl_compute_shader.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) |
+| 124 | [easings_testbed](others/easings_testbed.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
+| 125 | [raylib_opengl_interop](others/raylib_opengl_interop.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) |
+| 126 | [embedded_files_loading](others/embedded_files_loading.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
As always contributions are welcome, feel free to send new examples! Here is an [examples template](examples_template.c) to start with!
diff --git a/examples/core/core_ascii_rendering.c b/examples/core/core_ascii_rendering.c
new file mode 100644
index 000000000..e2017ec3d
--- /dev/null
+++ b/examples/core/core_ascii_rendering.c
@@ -0,0 +1,119 @@
+/*******************************************************************************************
+*
+* raylib [core] example - Ascii rendering
+*
+* Example originally created with raylib 5.5, last time updated with raylib 5.5
+*
+* Example contributed by Gavin Parker (@IoIxD) 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) 2023 Gavin Parker (@IoIxD)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "rmod.h"
+
+#include "GLFW/glfw3.h" // Windows/Context and inputs management
+
+#include // Required for: printf()
+#include "rlgl.h"
+#include "raymath.h"
+
+const int screenWidth = 800;
+const int screenHeight = 450;
+GLFWwindow *window;
+
+int CustomInitPlatform(void) {
+ if (!glfwInit())
+ {
+ printf("GLFW3: Can not initialize GLFW\n");
+ return 1;
+ }
+ else printf("GLFW3: GLFW initialized successfully\n");
+
+ glfwWindowHint(GLFW_SAMPLES, 4);
+ glfwWindowHint(GLFW_DEPTH_BITS, 16);
+
+ // WARNING: OpenGL 3.3 Core profile only
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ //glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
+#if defined(__APPLE__)
+ glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );
+#endif
+
+ window = glfwCreateWindow(screenWidth, screenHeight, "rlgl standalone", NULL, NULL);
+
+ if (!window)
+ {
+ glfwTerminate();
+ return 2;
+ }
+ else printf("GLFW3: Window created successfully\n");
+
+ //glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
+ glfwSetWindowPos(window, 200, 200);
+
+ glfwMakeContextCurrent(window);
+ glfwSwapInterval(0);
+
+ // Load OpenGL 3.3 supported extensions
+ rlLoadExtensions(glfwGetProcAddress);
+ //--------------------------------------------------------
+
+ // Initialize OpenGL context (states and resources)
+ rlglInit(screenWidth, screenHeight);
+
+ // Initialize viewport and internal projection/modelview matrices
+ rlViewport(0, 0, screenWidth, screenHeight);
+ rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix
+ rlLoadIdentity(); // Reset current matrix (PROJECTION)
+ rlOrtho(0, screenWidth, screenHeight, 0, 0.0f, 1.0f); // Orthographic projection with top-left corner at (0,0)
+ rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix
+ rlLoadIdentity(); // Reset current matrix (MODELVIEW)
+ return 0;
+}
+
+void CustomClosePlatform(void) {
+ glfwDestroyWindow(window); // Close window
+ glfwTerminate(); // Free GLFW3 resources
+}
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ union OverridableFunctionPointer funcs;
+ CustomInitPlatform();
+
+ OverrideInternalFunction("InitPlatform",&funcs);
+ OverrideInternalFunction("ClosePlatform",&funcs);
+
+ RenderTexture2D fb = LoadRenderTexture(80,24);
+
+ InitWindow(1,1,"r");
+
+ Color col;
+
+ //--------------------------------------------------------------------------------------
+
+ while(!WindowShouldClose()) {
+ BeginDrawing();
+ ClearBackground(WHITE);
+ BeginTextureMode(fb);
+ ClearBackground(RED);
+ EndTextureMode();
+ EndDrawing();
+
+ glfwSwapBuffers(window);
+ glfwPollEvents();
+ }
+
+ CustomClosePlatform();
+ return 0;
+}
diff --git a/examples/core/core_automation_events.c b/examples/core/core_automation_events.c
index 64ca51fda..b61a436c8 100644
--- a/examples/core/core_automation_events.c
+++ b/examples/core/core_automation_events.c
@@ -333,4 +333,4 @@ int main(void)
//--------------------------------------------------------------------------------------
return 0;
-}
+}
\ No newline at end of file
diff --git a/examples/core/core_input_gamepad_info.c b/examples/core/core_input_gamepad_info.c
index 096294681..66fedda90 100644
--- a/examples/core/core_input_gamepad_info.c
+++ b/examples/core/core_input_gamepad_info.c
@@ -47,25 +47,25 @@ int main(void)
ClearBackground(RAYWHITE);
- for (int i = 0, y = 5; i < 4; i++) // MAX_GAMEPADS = 4
+ for (int i = 0, y = 10; i < 4; i++) // MAX_GAMEPADS = 4
{
if (IsGamepadAvailable(i))
{
- DrawText(TextFormat("Gamepad name: %s", GetGamepadName(i)), 10, y, 10, BLACK);
- y += 11;
- DrawText(TextFormat("\tAxis count: %d", GetGamepadAxisCount(i)), 10, y, 10, BLACK);
- y += 11;
+ DrawText(TextFormat("Gamepad name: %s", GetGamepadName(i)), 10, y, 20, BLACK);
+ y += 30;
+ DrawText(TextFormat("\tAxis count: %d", GetGamepadAxisCount(i)), 10, y, 20, BLACK);
+ y += 30;
for (int axis = 0; axis < GetGamepadAxisCount(i); axis++)
{
- DrawText(TextFormat("\tAxis %d = %f", axis, GetGamepadAxisMovement(i, axis)), 10, y, 10, BLACK);
- y += 11;
+ DrawText(TextFormat("\tAxis %d = %f", axis, GetGamepadAxisMovement(i, axis)), 10, y, 20, BLACK);
+ y += 30;
}
for (int button = 0; button < 32; button++)
{
- DrawText(TextFormat("\tButton %d = %d", button, IsGamepadButtonDown(i, button)), 10, y, 10, BLACK);
- y += 11;
+ DrawText(TextFormat("\tButton %d = %d", button, IsGamepadButtonDown(i, button)), 10, y, 20, BLACK);
+ y += 30;
}
}
}
@@ -80,4 +80,4 @@ int main(void)
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
-}
+}
\ No newline at end of file
diff --git a/examples/core/core_vr_simulator.c b/examples/core/core_vr_simulator.c
index 021698edb..c98fce931 100644
--- a/examples/core/core_vr_simulator.c
+++ b/examples/core/core_vr_simulator.c
@@ -100,7 +100,7 @@ int main(void)
DisableCursor(); // Limit cursor to relative movement inside the window
- SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ SetTargetFPS(90); // Set our game to run at 90 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
diff --git a/examples/models/models_box_collisions.c b/examples/models/models_box_collisions.c
index 4d98a776a..936f65f38 100644
--- a/examples/models/models_box_collisions.c
+++ b/examples/models/models_box_collisions.c
@@ -109,7 +109,7 @@ int main(void)
EndMode3D();
- DrawText("Move player with arrow keys to collide", 220, 40, 20, GRAY);
+ DrawText("Move player with cursors to collide", 220, 40, 20, GRAY);
DrawFPS(10, 10);
diff --git a/examples/models/models_yaw_pitch_roll.c b/examples/models/models_yaw_pitch_roll.c
index 5374c035e..91a11f73c 100644
--- a/examples/models/models_yaw_pitch_roll.c
+++ b/examples/models/models_yaw_pitch_roll.c
@@ -114,7 +114,6 @@ int main(void)
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadModel(model); // Unload model data
- UnloadTexture(texture); // Unload texture data
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
diff --git a/examples/shaders/resources/shaders/glsl100/raymarching.fs b/examples/shaders/resources/shaders/glsl100/raymarching.fs
index a7339d216..d58d9d331 100644
--- a/examples/shaders/resources/shaders/glsl100/raymarching.fs
+++ b/examples/shaders/resources/shaders/glsl100/raymarching.fs
@@ -38,7 +38,7 @@ uniform vec2 resolution;
//
// More info here: http://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
-#define AA 1 // make this 1 if your machine is too slow
+#define AA 1 // make this 1 is your machine is too slow
//------------------------------------------------------------------
diff --git a/examples/shaders/shaders_basic_pbr.c b/examples/shaders/shaders_basic_pbr.c
index c3f2bad88..d025ab8a9 100644
--- a/examples/shaders/shaders_basic_pbr.c
+++ b/examples/shaders/shaders_basic_pbr.c
@@ -236,7 +236,7 @@ int main()
float emissiveIntensity = 0.01f;
SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, SHADER_UNIFORM_FLOAT);
- DrawModel(car, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.25f, WHITE); // Draw car model
+ DrawModel(car, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.005f, WHITE); // Draw car model
// Draw spheres to show the lights positions
for (int i = 0; i < MAX_LIGHTS; i++)
diff --git a/examples/shaders/shaders_lightmap.c b/examples/shaders/shaders_lightmap.c
index 91ed8bfd2..01b80a6fb 100644
--- a/examples/shaders/shaders_lightmap.c
+++ b/examples/shaders/shaders_lightmap.c
@@ -164,8 +164,6 @@ int main(void)
//--------------------------------------------------------------------------------------
UnloadMesh(mesh); // Unload the mesh
UnloadShader(shader); // Unload shader
- UnloadTexture(texture); // Unload texture
- UnloadTexture(light); // Unload texture
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
diff --git a/examples/shaders/shaders_texture_drawing.c b/examples/shaders/shaders_texture_drawing.c
index ada44299d..52b8967f6 100644
--- a/examples/shaders/shaders_texture_drawing.c
+++ b/examples/shaders/shaders_texture_drawing.c
@@ -77,7 +77,6 @@ int main(void)
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadShader(shader);
- UnloadTexture(texture);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
diff --git a/examples/shapes/raygui.h b/examples/shapes/raygui.h
index 16e01a28f..623115fce 100644
--- a/examples/shapes/raygui.h
+++ b/examples/shapes/raygui.h
@@ -1,6 +1,6 @@
/*******************************************************************************************
*
-* raygui v4.5-dev - A simple and easy-to-use immediate-mode gui library
+* raygui v4.0 - 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
@@ -26,7 +26,7 @@
* 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
+* no unload function is explicitly provided... but note that GuiLoadStyleDefaulf() unloads
* by default any previously loaded font (texture, recs, glyphs).
* - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions
*
@@ -141,24 +141,6 @@
* 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
@@ -332,9 +314,9 @@
#define RAYGUI_H
#define RAYGUI_VERSION_MAJOR 4
-#define RAYGUI_VERSION_MINOR 5
+#define RAYGUI_VERSION_MINOR 0
#define RAYGUI_VERSION_PATCH 0
-#define RAYGUI_VERSION "4.5-dev"
+#define RAYGUI_VERSION "4.0"
#if !defined(RAYGUI_STANDALONE)
#include "raylib.h"
@@ -459,6 +441,7 @@
} Font;
#endif
+
// Style property
// NOTE: Used when exporting style as code for convenience
typedef struct GuiStyleProp {
@@ -563,6 +546,7 @@ typedef enum {
// 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)
//----------------------------------------------------------------------------------
@@ -578,12 +562,12 @@ typedef enum {
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
+ //TEXT_DECORATION_THICK // Text decoration line thikness
} GuiDefaultProperty;
// Other possible text properties:
// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change
-// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING...
+// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING...
// Label
//typedef enum { } GuiLabelProperty;
@@ -631,9 +615,7 @@ typedef enum {
// 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)
+ DROPDOWN_ITEMS_SPACING // DropdownBox items separation
} GuiDropdownBoxProperty;
// TextBox/TextBoxMulti/ValueBox/Spinner
@@ -653,7 +635,6 @@ typedef enum {
LIST_ITEMS_SPACING, // ListView items separation
SCROLLBAR_WIDTH, // ListView scrollbar size (usually width)
SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE)
- LIST_ITEMS_BORDER_WIDTH // ListView items border width
} GuiListViewProperty;
// ColorPicker
@@ -717,6 +698,7 @@ RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load
RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position
#endif
+
// Controls
//----------------------------------------------------------------------------------------------------------
// Container/separator controls, useful for controls organization
@@ -728,30 +710,29 @@ RAYGUIAPI int GuiTabBar(Rectangle bounds, const char **text, int count, int *act
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 GuiLabel(Rectangle bounds, const char *text); // Label control, shows text
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 GuiLabelButton(Rectangle bounds, const char *text); // Label button control, show true when clicked
+RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control, returns true when active
+RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control, returns active toggle index
+RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control, returns true when clicked
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 GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control, returns selected item index
-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 GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control, returns selected item
+RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control, returns selected value
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 GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control, returns selected value
+RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control, returns selected value
+RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control, shows current progress value
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
+RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control, returns mouse cell position
// Advance controls set
-RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control
+RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control, returns selected list item index
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
@@ -760,9 +741,10 @@ RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color);
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()
+RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that returns HSV color value, used by GuiColorPickerHSV()
//----------------------------------------------------------------------------------------------------------
+
#if !defined(RAYGUI_NO_ICONS)
#if !defined(RAYGUI_CUSTOM_ICONS)
@@ -990,14 +972,14 @@ typedef enum {
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_220 = 220,
+ ICON_221 = 221,
+ ICON_222 = 222,
+ ICON_223 = 223,
+ ICON_224 = 224,
+ ICON_225 = 225,
+ ICON_226 = 226,
+ ICON_227 = 227,
ICON_228 = 228,
ICON_229 = 229,
ICON_230 = 230,
@@ -1308,14 +1290,14 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] =
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
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_220
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_221
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_222
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_223
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_224
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_225
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_226
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_227
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_228
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_229
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_230
@@ -1346,7 +1328,7 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] =
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255
};
-// NOTE: A pointer to current icons array should be defined
+// NOTE: We keep a pointer to the icons array, useful to point to other sets if required
static unsigned int *guiIconsPtr = guiIcons;
#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS
@@ -1381,8 +1363,8 @@ static unsigned int guiIconScale = 1; // Gui icon default scale (if ic
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 bool guiSliderDragging = false; // Gui slider drag state (no inputs processed except dragged slider)
+static Rectangle guiSliderActive = { 0 }; // Gui slider active 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
@@ -1468,7 +1450,6 @@ static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if
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)
@@ -1763,9 +1744,6 @@ int GuiTabBar(Rectangle bounds, const char **text, int count, int *active)
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);
@@ -1797,10 +1775,10 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector
{
#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;
+ float mouseWheelSpeed = 20.0f; // Default movement speed with mouse wheel
Rectangle temp = { 0 };
if (view == NULL) view = &temp;
@@ -1842,8 +1820,17 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector
};
// 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;
+ // NOTE: If content >>> bounds, size could be very small or even 0
+ if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH)
+ {
+ horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH;
+ mouseWheelSpeed = 30.0f; // TODO: Calculate speed increment based on content.height vs bounds.height
+ }
+ if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT)
+ {
+ verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT;
+ mouseWheelSpeed = 30.0f; // TODO: Calculate speed increment based on content.width vs bounds.width
+ }
// Calculate view area (area without the scrollbars)
*view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)?
@@ -1886,14 +1873,9 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector
#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
+ if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed;
+ else scrollPos.y += wheelMove*mouseWheelSpeed; // Vertical scroll
}
}
@@ -1939,7 +1921,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector
}
// Draw scrollbar lines depending on current state
- GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK);
+ GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, 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);
@@ -1977,7 +1959,7 @@ int GuiButton(Rectangle bounds, const char *text)
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
{
Vector2 mousePoint = GetMousePosition();
@@ -2015,7 +1997,7 @@ int GuiLabelButton(Rectangle bounds, const char *text)
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
{
Vector2 mousePoint = GetMousePosition();
@@ -2038,7 +2020,7 @@ int GuiLabelButton(Rectangle bounds, const char *text)
return pressed;
}
-// Toggle Button control
+// Toggle Button control, returns true when active
int GuiToggle(Rectangle bounds, const char *text, bool *active)
{
int result = 0;
@@ -2049,7 +2031,7 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active)
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
{
Vector2 mousePoint = GetMousePosition();
@@ -2086,7 +2068,7 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active)
return result;
}
-// Toggle Group control
+// Toggle Group control, returns toggled button codepointIndex
int GuiToggleGroup(Rectangle bounds, const char *text, int *active)
{
#if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS)
@@ -2135,7 +2117,7 @@ int GuiToggleGroup(Rectangle bounds, const char *text, int *active)
return result;
}
-// Toggle Slider control extended
+// Toggle Slider control extended, returns true when clicked
int GuiToggleSlider(Rectangle bounds, const char *text, int *active)
{
int result = 0;
@@ -2229,7 +2211,7 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked)
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
{
Vector2 mousePoint = GetMousePosition();
@@ -2274,7 +2256,7 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked)
return result;
}
-// Combo Box control
+// Combo Box control, returns selected item codepointIndex
int GuiComboBox(Rectangle bounds, const char *text, int *active)
{
int result = 0;
@@ -2297,7 +2279,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active)
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode)
+ if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiSliderDragging)
{
Vector2 mousePoint = GetMousePosition();
@@ -2345,28 +2327,21 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod
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)
+ if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiSliderDragging)
{
Vector2 mousePoint = GetMousePosition();
@@ -2387,8 +2362,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod
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));
+ itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
if (CheckCollisionPointRec(mousePoint, itemBounds))
{
@@ -2432,8 +2406,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod
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));
+ itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING));
if (i == itemSelected)
{
@@ -2449,17 +2422,14 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod
}
}
- if (!GuiGetStyle(DROPDOWNBOX, DROPDOWN_ARROW_HIDDEN))
- {
- // Draw arrows (using icon if available)
+ // 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))));
+ 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
+ GuiDrawText("#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;
@@ -2470,7 +2440,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod
// Text Box control
// NOTE: Returns true on ENTER pressed (useful for data validation)
-int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
+int GuiTextBox(Rectangle bounds, char *text, int bufferSize, bool editMode)
{
#if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN)
#define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 40 // Frames to wait for autocursor movement
@@ -2486,10 +2456,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE);
Rectangle textBounds = GetTextBounds(TEXTBOX, bounds);
- int textLength = (int)strlen(text); // Get current text length
- int thisCursorIndex = textBoxCursorIndex;
- if (thisCursorIndex > textLength) thisCursorIndex = textLength;
- int textWidth = GetTextWidth(text) - GetTextWidth(text + thisCursorIndex);
+ int textWidth = GetTextWidth(text) - GetTextWidth(text + textBoxCursorIndex);
int textIndexOffset = 0; // Text index offset to start drawing in the box
// Cursor rectangle
@@ -2529,7 +2496,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
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
+ !guiSliderDragging && // No gui slider on dragging
(wrapMode == TEXT_WRAP_NONE)) // No wrap mode
{
Vector2 mousePosition = GetMousePosition();
@@ -2538,8 +2505,6 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool 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)
@@ -2552,16 +2517,19 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
textWidth = GetTextWidth(text + textIndexOffset) - GetTextWidth(text + textBoxCursorIndex);
}
+ int textLength = (int)strlen(text); // Get current text length
int codepoint = GetCharPressed(); // Get Unicode codepoint
if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n';
+ if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength;
+
// 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))
+ if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < bufferSize))
{
// Move forward data from cursor position
for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize];
@@ -2596,7 +2564,6 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
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';
@@ -2616,8 +2583,6 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
// Move backward text from cursor position
for (int i = (textBoxCursorIndex - prevCodepointSize); i < textLength; i++) text[i] = text[i + prevCodepointSize];
- // TODO Check: >= cursor+codepointsize and <= length-codepointsize
-
// Prevent cursor index from decrementing past 0
if (textBoxCursorIndex > 0)
{
@@ -2688,7 +2653,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2))
{
mouseCursor.x = textBounds.x + textEndWidth;
- mouseCursorIndex = textLength;
+ mouseCursorIndex = (int)strlen(text);
}
// Place cursor at required index on mouse click
@@ -2720,7 +2685,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
{
- textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text
+ textBoxCursorIndex = (int)strlen(text); // GLOBAL: Place cursor index to the end of current text
result = 1;
}
}
@@ -2762,7 +2727,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode)
/*
// 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 GuiTextBoxMulti(Rectangle bounds, char *text, int bufferSize, bool editMode)
{
bool pressed = false;
@@ -2771,7 +2736,7 @@ bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode)
GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP);
// TODO: Implement methods to calculate cursor position properly
- pressed = GuiTextBox(bounds, text, textSize, editMode);
+ pressed = GuiTextBox(bounds, text, bufferSize, editMode);
GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE);
GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE);
@@ -2806,7 +2771,7 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
{
Vector2 mousePoint = GetMousePosition();
@@ -2881,7 +2846,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
{
Vector2 mousePoint = GetMousePosition();
@@ -2925,13 +2890,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
//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;
- }
+ if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1;
}
else
{
@@ -2971,152 +2930,55 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in
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;
+ float oldValue = *value;
GuiState state = guiState;
float temp = (maxValue - minValue)/2.0f;
if (value == NULL) value = &temp;
- float oldValue = *value;
+
+ int sliderValue = (int)(((*value - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH)));
Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING),
0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) };
+ if (sliderWidth > 0) // Slider
+ {
+ slider.x += (sliderValue - sliderWidth/2);
+ slider.width = (float)sliderWidth;
+ }
+ else if (sliderWidth == 0) // SliderBar
+ {
+ slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH);
+ slider.width = (float)sliderValue;
+ }
+
// Update control
//--------------------------------------------------------------------
if ((state != STATE_DISABLED) && !guiLocked)
{
Vector2 mousePoint = GetMousePosition();
- if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ if (guiSliderDragging) // Keep dragging outside of bounds
{
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
{
- if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ if (CHECK_BOUNDS_ID(bounds, guiSliderActive))
{
state = STATE_PRESSED;
+
// Get equivalent value and slider position from mousePosition.x
- *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width-sliderWidth)) + minValue;
+ *value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue;
}
}
else
{
- guiControlExclusiveMode = false;
- guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ guiSliderDragging = false;
+ guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
}
}
else if (CheckCollisionPointRec(mousePoint, bounds))
@@ -3124,13 +2986,16 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
{
state = STATE_PRESSED;
- guiControlExclusiveMode = true;
- guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+ guiSliderDragging = true;
+ guiSliderActive = 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;
+ *value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue;
+
+ if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider
+ else if (sliderWidth == 0) slider.width = (float)sliderValue; // SliderBar
}
}
else state = STATE_FOCUSED;
@@ -3141,22 +3006,17 @@ int GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight,
}
// Control value change check
- if (oldValue == *value) result = 0;
+ 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)));
+ // Bar limits check
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);
}
//--------------------------------------------------------------------
@@ -3311,7 +3171,7 @@ int GuiDummyRec(Rectangle bounds, const char *text)
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
{
Vector2 mousePoint = GetMousePosition();
@@ -3378,7 +3238,7 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
{
Vector2 mousePoint = GetMousePosition();
@@ -3431,8 +3291,6 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd
// Draw visible items
for (int i = 0; ((i < visibleItems) && (text != NULL)); i++)
{
- GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK);
-
if (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)));
@@ -3495,32 +3353,83 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd
return result;
}
-// Color Panel control - Color (RGBA) variant.
+// Color Panel control
int GuiColorPanel(Rectangle bounds, const char *text, Color *color)
{
int result = 0;
+ GuiState state = guiState;
+ Vector2 pickerSelector = { 0 };
+
+ const Color colWhite = { 255, 255, 255, 255 };
+ const Color colBlack = { 0, 0, 0, 255 };
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);
+ pickerSelector.x = bounds.x + (float)hsv.y*bounds.width; // HSV: Saturation
+ pickerSelector.y = bounds.y + (1.0f - (float)hsv.z)*bounds.height; // HSV: Value
- // 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 maxHue = { hsv.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 && !guiSliderDragging)
{
- Vector3 rgb = ConvertHSVtoRGB(hsv);
+ Vector2 mousePoint = GetMousePosition();
- // 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 };
+ if (CheckCollisionPointRec(mousePoint, bounds))
+ {
+ if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
+ {
+ state = STATE_PRESSED;
+ 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
+
+ hsv.y = colorPick.x;
+ hsv.z = 1.0f - colorPick.y;
+
+ 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),
+ (unsigned char)(255.0f*(float)color->a/255.0f) };
+
+ }
+ 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;
}
@@ -3542,11 +3451,11 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
{
Vector2 mousePoint = GetMousePosition();
- if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ if (guiSliderDragging) // Keep dragging outside of bounds
{
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
{
- if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ if (CHECK_BOUNDS_ID(bounds, guiSliderActive))
{
state = STATE_PRESSED;
@@ -3557,8 +3466,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
}
else
{
- guiControlExclusiveMode = false;
- guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ guiSliderDragging = false;
+ guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
}
}
else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector))
@@ -3566,8 +3475,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha)
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
{
state = STATE_PRESSED;
- guiControlExclusiveMode = true;
- guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+ guiSliderDragging = true;
+ guiSliderActive = bounds; // Store bounds as an identifier when dragging starts
*alpha = (mousePoint.x - bounds.x)/bounds.width;
if (*alpha <= 0.0f) *alpha = 0.0f;
@@ -3628,11 +3537,11 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue)
{
Vector2 mousePoint = GetMousePosition();
- if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ if (guiSliderDragging) // Keep dragging outside of bounds
{
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
{
- if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ if (CHECK_BOUNDS_ID(bounds, guiSliderActive))
{
state = STATE_PRESSED;
@@ -3643,8 +3552,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue)
}
else
{
- guiControlExclusiveMode = false;
- guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ guiSliderDragging = false;
+ guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
}
}
else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector))
@@ -3652,8 +3561,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue)
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
{
state = STATE_PRESSED;
- guiControlExclusiveMode = true;
- guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+ guiSliderDragging = true;
+ guiSliderActive = bounds; // Store bounds as an identifier when dragging starts
*hue = (mousePoint.y - bounds.y)*360/bounds.height;
if (*hue <= 0.0f) *hue = 0.0f;
@@ -3706,7 +3615,6 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue)
// 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;
@@ -3719,7 +3627,6 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color)
Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height };
//Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) };
- // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used.
Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f });
GuiColorBarHue(boundsHue, NULL, &hsv.x);
@@ -3761,7 +3668,8 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
return result;
}
-// Color Panel control - HSV variant
+// Color Panel control, returns HSV color value in *colorHsv.
+// Used by GuiColorPickerHSV()
int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
{
int result = 0;
@@ -3782,47 +3690,15 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv)
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked)
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
{
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 (CheckCollisionPointRec(mousePoint, bounds))
{
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON))
{
state = STATE_PRESSED;
- guiControlExclusiveMode = true;
- guiControlExclusiveRec = bounds;
pickerSelector = mousePoint;
// Calculate color from picker
@@ -3884,9 +3760,9 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons
int textWidth = GetTextWidth(message) + 2;
Rectangle textBounds = { 0 };
- textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
+ textBounds.x = bounds.x + bounds.width/2 - textWidth/2;
textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING;
- textBounds.width = bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*2;
+ textBounds.width = (float)textWidth;
textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT;
// Draw control
@@ -4029,7 +3905,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect
// Update control
//--------------------------------------------------------------------
- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode)
+ if ((state != STATE_DISABLED) && !guiLocked && !guiSliderDragging)
{
if (CheckCollisionPointRec(mousePoint, bounds))
{
@@ -4049,14 +3925,14 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect
// Draw vertical grid lines
for (int i = 0; i < linesV; i++)
{
- Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height + 1 };
+ Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height };
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 };
+ Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width, 1 };
GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA));
}
}
@@ -4078,6 +3954,7 @@ void GuiDisableTooltip(void) { guiTooltip = false; }
// Set tooltip string
void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; }
+
//----------------------------------------------------------------------------------
// Styles loading functions
//----------------------------------------------------------------------------------
@@ -4090,7 +3967,6 @@ 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");
@@ -4724,7 +4600,7 @@ static int GetTextWidth(const char *text)
}
}
- if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING);
+ if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE - ICON_TEXT_PADDING);
}
return (int)textSize.x;
@@ -4897,7 +4773,6 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
// 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?
@@ -4923,8 +4798,6 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
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;
@@ -4947,8 +4820,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
{
// 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);
+ textBoundsPosition.x += (RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING);
}
#endif
// Get size in bytes of text,
@@ -4957,15 +4829,9 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
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);
@@ -4973,51 +4839,36 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
// 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
+ 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
+ // Wrap mode text measuring to space to validate if it can be drawn or
+ // a new line is required
if (wrapMode == TEXT_WRAP_CHAR)
{
+ // 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;
+
// Jump to next line if current character reach end of the box limits
- if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset)
+ if ((textOffsetX + glyphWidth) > textBounds.width)
{
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)
+ if ((textOffsetX + nextSpaceWidth) > textBounds.width)
{
textOffsetX = 0.0f;
textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING);
}
+
+ // TODO: Consider case: (nextSpaceWidth >= textBounds.width)
}
if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint
@@ -5030,23 +4881,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C
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
+ if (textOffsetX <= (textBounds.width - glyphWidth))
{
DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha));
}
@@ -5102,7 +4937,7 @@ static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor,
// Draw tooltip using control bounds
static void GuiTooltip(Rectangle controlRec)
{
- if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode)
+ if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiSliderDragging)
{
Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING));
@@ -5168,7 +5003,7 @@ static const char **GuiTextSplit(const char *text, char delimiter, int *count, i
buffer[i] = '\0'; // Set an end of string at this point
counter++;
- if (counter > RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
+ if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break;
}
}
@@ -5328,11 +5163,8 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
if (value > maxValue) value = maxValue;
if (value < minValue) value = minValue;
- int valueRange = maxValue - minValue;
- if (valueRange <= 0) valueRange = 1;
-
+ const int valueRange = maxValue - minValue;
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){
@@ -5373,13 +5205,13 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
{
Vector2 mousePoint = GetMousePosition();
- if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds
+ if (guiSliderDragging) // Keep dragging outside of bounds
{
if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) &&
!CheckCollisionPointRec(mousePoint, arrowUpLeft) &&
!CheckCollisionPointRec(mousePoint, arrowDownRight))
{
- if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec))
+ if (CHECK_BOUNDS_ID(bounds, guiSliderActive))
{
state = STATE_PRESSED;
@@ -5389,8 +5221,8 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
}
else
{
- guiControlExclusiveMode = false;
- guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
+ guiSliderDragging = false;
+ guiSliderActive = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 };
}
}
else if (CheckCollisionPointRec(mousePoint, bounds))
@@ -5404,8 +5236,8 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue)
// Handle mouse button down
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
{
- guiControlExclusiveMode = true;
- guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts
+ guiSliderDragging = true;
+ guiSliderActive = bounds; // Store bounds as an identifier when dragging starts
// Check arrows click
if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED);
@@ -5605,37 +5437,6 @@ static int TextToInteger(const char *text)
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)
{
@@ -5689,21 +5490,21 @@ static int GetCodepointNext(const char *text, int *codepointSize)
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
+ 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
+ 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
+ if((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks
codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]);
*codepointSize = 2;
}
@@ -5714,8 +5515,9 @@ static int GetCodepointNext(const char *text, int *codepointSize)
*codepointSize = 1;
}
+
return codepoint;
}
#endif // RAYGUI_STANDALONE
-#endif // RAYGUI_IMPLEMENTATION
\ No newline at end of file
+#endif // RAYGUI_IMPLEMENTATION
diff --git a/examples/shapes/shapes_bouncing_ball.c b/examples/shapes/shapes_bouncing_ball.c
index df0c37c1c..7a3068163 100644
--- a/examples/shapes/shapes_bouncing_ball.c
+++ b/examples/shapes/shapes_bouncing_ball.c
@@ -62,7 +62,7 @@ int main(void)
ClearBackground(RAYWHITE);
DrawCircleV(ballPosition, (float)ballRadius, MAROON);
- DrawText("PRESS SPACE to PAUSE BALL MOVEMENT", 10, GetScreenHeight() - 25, 20, LIGHTGRAY);
+ //DrawText("PRESS SPACE to PAUSE BALL MOVEMENT", 10, GetScreenHeight() - 25, 20, LIGHTGRAY);
// On pause, we draw a blinking message
if (pause && ((framesCounter/30)%2)) DrawText("PAUSED", 350, 200, 30, GRAY);
diff --git a/examples/shapes/shapes_draw_circle_sector.c b/examples/shapes/shapes_draw_circle_sector.c
index cb9ab859b..30eaaf4bd 100644
--- a/examples/shapes/shapes_draw_circle_sector.c
+++ b/examples/shapes/shapes_draw_circle_sector.c
@@ -63,11 +63,11 @@ int main(void)
// Draw GUI controls
//------------------------------------------------------------------------------
- GuiSliderBar((Rectangle){ 600, 40, 120, 20}, "StartAngle", TextFormat("%.2f", startAngle), &startAngle, 0, 720);
- GuiSliderBar((Rectangle){ 600, 70, 120, 20}, "EndAngle", TextFormat("%.2f", endAngle), &endAngle, 0, 720);
+ GuiSliderBar((Rectangle){ 600, 40, 120, 20}, "StartAngle", NULL, &startAngle, 0, 720);
+ GuiSliderBar((Rectangle){ 600, 70, 120, 20}, "EndAngle", NULL, &endAngle, 0, 720);
- GuiSliderBar((Rectangle){ 600, 140, 120, 20}, "Radius", TextFormat("%.2f", outerRadius), &outerRadius, 0, 200);
- GuiSliderBar((Rectangle){ 600, 170, 120, 20}, "Segments", TextFormat("%.2f", segments), &segments, 0, 100);
+ GuiSliderBar((Rectangle){ 600, 140, 120, 20}, "Radius", NULL, &outerRadius, 0, 200);
+ GuiSliderBar((Rectangle){ 600, 170, 120, 20}, "Segments", NULL, &segments, 0, 100);
//------------------------------------------------------------------------------
minSegments = truncf(ceilf((endAngle - startAngle) / 90));
diff --git a/examples/shapes/shapes_draw_rectangle_rounded.c b/examples/shapes/shapes_draw_rectangle_rounded.c
index 58991884c..19280ed00 100644
--- a/examples/shapes/shapes_draw_rectangle_rounded.c
+++ b/examples/shapes/shapes_draw_rectangle_rounded.c
@@ -66,11 +66,11 @@ int main(void)
// Draw GUI controls
//------------------------------------------------------------------------------
- GuiSliderBar((Rectangle){ 640, 40, 105, 20 }, "Width", TextFormat("%.2f", width), &width, 0, (float)GetScreenWidth() - 300);
- GuiSliderBar((Rectangle){ 640, 70, 105, 20 }, "Height", TextFormat("%.2f", height), &height, 0, (float)GetScreenHeight() - 50);
- GuiSliderBar((Rectangle){ 640, 140, 105, 20 }, "Roundness", TextFormat("%.2f", roundness), &roundness, 0.0f, 1.0f);
- GuiSliderBar((Rectangle){ 640, 170, 105, 20 }, "Thickness", TextFormat("%.2f", lineThick), &lineThick, 0, 20);
- GuiSliderBar((Rectangle){ 640, 240, 105, 20}, "Segments", TextFormat("%.2f", segments), &segments, 0, 60);
+ GuiSliderBar((Rectangle){ 640, 40, 105, 20 }, "Width", NULL, &width, 0, (float)GetScreenWidth() - 300);
+ GuiSliderBar((Rectangle){ 640, 70, 105, 20 }, "Height", NULL, &height, 0, (float)GetScreenHeight() - 50);
+ GuiSliderBar((Rectangle){ 640, 140, 105, 20 }, "Roundness", NULL, &roundness, 0.0f, 1.0f);
+ GuiSliderBar((Rectangle){ 640, 170, 105, 20 }, "Thickness", NULL, &lineThick, 0, 20);
+ GuiSliderBar((Rectangle){ 640, 240, 105, 20}, "Segments", NULL, &segments, 0, 60);
GuiCheckBox((Rectangle){ 640, 320, 20, 20 }, "DrawRoundedRect", &drawRoundedRect);
GuiCheckBox((Rectangle){ 640, 350, 20, 20 }, "DrawRoundedLines", &drawRoundedLines);
diff --git a/examples/shapes/shapes_draw_ring.c b/examples/shapes/shapes_draw_ring.c
index 8bccdf729..60c95a4c0 100644
--- a/examples/shapes/shapes_draw_ring.c
+++ b/examples/shapes/shapes_draw_ring.c
@@ -69,13 +69,13 @@ int main(void)
// Draw GUI controls
//------------------------------------------------------------------------------
- GuiSliderBar((Rectangle){ 600, 40, 120, 20 }, "StartAngle", TextFormat("%.2f", startAngle), &startAngle, -450, 450);
- GuiSliderBar((Rectangle){ 600, 70, 120, 20 }, "EndAngle", TextFormat("%.2f", endAngle), &endAngle, -450, 450);
+ GuiSliderBar((Rectangle){ 600, 40, 120, 20 }, "StartAngle", NULL, &startAngle, -450, 450);
+ GuiSliderBar((Rectangle){ 600, 70, 120, 20 }, "EndAngle", NULL, &endAngle, -450, 450);
- GuiSliderBar((Rectangle){ 600, 140, 120, 20 }, "InnerRadius", TextFormat("%.2f", innerRadius), &innerRadius, 0, 100);
- GuiSliderBar((Rectangle){ 600, 170, 120, 20 }, "OuterRadius", TextFormat("%.2f", outerRadius), &outerRadius, 0, 200);
+ GuiSliderBar((Rectangle){ 600, 140, 120, 20 }, "InnerRadius", NULL, &innerRadius, 0, 100);
+ GuiSliderBar((Rectangle){ 600, 170, 120, 20 }, "OuterRadius", NULL, &outerRadius, 0, 200);
- GuiSliderBar((Rectangle){ 600, 240, 120, 20 }, "Segments", TextFormat("%.2f", segments), &segments, 0, 100);
+ GuiSliderBar((Rectangle){ 600, 240, 120, 20 }, "Segments", NULL, &segments, 0, 100);
GuiCheckBox((Rectangle){ 600, 320, 20, 20 }, "Draw Ring", &drawRing);
GuiCheckBox((Rectangle){ 600, 350, 20, 20 }, "Draw RingLines", &drawRingLines);
diff --git a/examples/text/text_input_box.c b/examples/text/text_input_box.c
index c53057711..eeb338f1f 100644
--- a/examples/text/text_input_box.c
+++ b/examples/text/text_input_box.c
@@ -35,7 +35,7 @@ int main(void)
int framesCounter = 0;
- SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ SetTargetFPS(10); // Set our game to run at 10 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
diff --git a/examples/text/text_writing_anim.c b/examples/text/text_writing_anim.c
index 8e2820fc9..1e7cd569f 100644
--- a/examples/text/text_writing_anim.c
+++ b/examples/text/text_writing_anim.c
@@ -52,7 +52,7 @@ int main(void)
DrawText(TextSubtext(message, 0, framesCounter/10), 210, 160, 20, MAROON);
DrawText("PRESS [ENTER] to RESTART!", 240, 260, 20, LIGHTGRAY);
- DrawText("HOLD [SPACE] to SPEED UP!", 239, 300, 20, LIGHTGRAY);
+ DrawText("PRESS [SPACE] to SPEED UP!", 239, 300, 20, LIGHTGRAY);
EndDrawing();
//----------------------------------------------------------------------------------
diff --git a/examples/textures/textures_blend_modes.c b/examples/textures/textures_blend_modes.c
index d97432cb2..660aa57a7 100644
--- a/examples/textures/textures_blend_modes.c
+++ b/examples/textures/textures_blend_modes.c
@@ -43,9 +43,6 @@ int main(void)
const int blendCountMax = 4;
BlendMode blendMode = 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
{
diff --git a/examples/textures/textures_image_rotate.c b/examples/textures/textures_image_rotate.c
index 94c42034b..51724e037 100644
--- a/examples/textures/textures_image_rotate.c
+++ b/examples/textures/textures_image_rotate.c
@@ -43,8 +43,6 @@ int main(void)
textures[2] = LoadTextureFromImage(imageNeg90);
int currentTexture = 0;
-
- SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//---------------------------------------------------------------------------------------
// Main game loop
diff --git a/examples/textures/textures_logo_raylib.c b/examples/textures/textures_logo_raylib.c
index 35baa1223..f170dab48 100644
--- a/examples/textures/textures_logo_raylib.c
+++ b/examples/textures/textures_logo_raylib.c
@@ -27,8 +27,6 @@ int main(void)
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
Texture2D texture = LoadTexture("resources/raylib_logo.png"); // Texture loading
-
- SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//---------------------------------------------------------------------------------------
// Main game loop
diff --git a/examples/textures/textures_raw_data.c b/examples/textures/textures_raw_data.c
index 6fb41b143..38229f1ba 100644
--- a/examples/textures/textures_raw_data.c
+++ b/examples/textures/textures_raw_data.c
@@ -63,8 +63,6 @@ int main(void)
Texture2D checked = LoadTextureFromImage(checkedIm);
UnloadImage(checkedIm); // Unload CPU (RAM) image data (pixels)
-
- SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//---------------------------------------------------------------------------------------
// Main game loop
diff --git a/examples/textures/textures_sprite_explosion.c b/examples/textures/textures_sprite_explosion.c
index a65426cb6..06b4f1dad 100644
--- a/examples/textures/textures_sprite_explosion.c
+++ b/examples/textures/textures_sprite_explosion.c
@@ -48,8 +48,8 @@ int main(void)
bool active = false;
int framesCounter = 0;
- SetTargetFPS(60); // Set our game to run at 60 frames-per-second
- //---------------------------------------------------------------------------------------
+ SetTargetFPS(120);
+ //--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
diff --git a/examples/textures/textures_to_image.c b/examples/textures/textures_to_image.c
index e1d88c4cd..2d09623eb 100644
--- a/examples/textures/textures_to_image.c
+++ b/examples/textures/textures_to_image.c
@@ -38,8 +38,6 @@ int main(void)
texture = LoadTextureFromImage(image); // Recreate texture from retrieved image data (RAM -> VRAM)
UnloadImage(image); // Unload retrieved image data from CPU memory (RAM)
-
- SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//---------------------------------------------------------------------------------------
// Main game loop
diff --git a/src/Makefile b/src/Makefile
index 4740f1f01..8cd30a324 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -27,6 +27,10 @@
# - Linux DRM subsystem (KMS mode)
# > PLATFORM_ANDROID:
# - Android (ARM, ARM64)
+# > PLATFORM_OFFSCREEN:
+# - Offscreen rendering
+# > PLATFORM_NONE:
+# - No platform
#
# Many thanks to Milan Nikolic (@gen2brain) for implementing Android platform pipeline.
# Many thanks to Emanuele Petriglia for his contribution on GNU/Linux pipeline.
@@ -127,7 +131,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_ANDROID))
+ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW PLATFORM_WEB PLATFORM_ANDROID PLATFORM_NONE PLATFORM_OFFSCREEN))
# No uname.exe on MinGW!, but OS=Windows_NT on Windows!
# ifeq ($(UNAME),Msys) -> Windows
ifeq ($(OS),Windows_NT)
@@ -237,6 +241,13 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
#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),$(filter $(TARGET_PLATFORM),PLATFORM_NONE PLATFORM_OFFSCREEN))
+ GRAPHICS ?= GRAPHICS_API_OPENGL_33
+ #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_DESKTOP_SDL)
# By default use OpenGL 3.3 on desktop platform with SDL backend
GRAPHICS ?= GRAPHICS_API_OPENGL_33
@@ -622,6 +633,9 @@ endif
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
LDLIBS = -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lc -lm
endif
+ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_NONE PLATFORM_OFFSCREEN))
+ LDLIBS = -lGL -lc -lm -lpthread -ldl -lrt
+endif
# Define source code object files required
#------------------------------------------------------------------------------------------------
@@ -725,7 +739,7 @@ endif
rcore.o : platforms/*.c
# Compile core module
-rcore.o : rcore.c raylib.h rlgl.h utils.h raymath.h rcamera.h rgestures.h
+rcore.o : rcore.c raylib.h rcore.h rlgl.h utils.h raymath.h rcamera.h rgestures.h
$(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
# Compile rglfw module
@@ -814,6 +828,7 @@ ifeq ($(ROOT),root)
cp --update raylib.h $(RAYLIB_H_INSTALL_PATH)/raylib.h
cp --update raymath.h $(RAYLIB_H_INSTALL_PATH)/raymath.h
cp --update rlgl.h $(RAYLIB_H_INSTALL_PATH)/rlgl.h
+ cp --update rcore.h $(RAYLIB_H_INSTALL_PATH)/rcore.h
@echo "raylib development files installed/updated!"
else
@echo "This function currently works on GNU/Linux systems. Add yours today (^;"
@@ -841,6 +856,7 @@ ifeq ($(ROOT),root)
rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/raylib.h
rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/raymath.h
rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/rlgl.h
+ rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/rcore.h
@echo "raylib development files removed!"
else
@echo "This function currently works on GNU/Linux systems. Add yours today (^;"
diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c
index 55706c591..3f5ac6c87 100644
--- a/src/platforms/rcore_android.c
+++ b/src/platforms/rcore_android.c
@@ -251,6 +251,7 @@ static const KeyboardKey mapKeycode[KEYCODE_MAP_SIZE] = {
//----------------------------------------------------------------------------------
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
void ClosePlatform(void); // Close platform
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func);
static void AndroidCommandCallback(struct android_app *app, int32_t cmd); // Process Android activity lifecycle commands
static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event); // Process Android inputs
@@ -1336,4 +1337,9 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
return 0;
}
+// Override an internal platform function with your own (PLATFORM_OFFSCREEN and PLATFORM_NONE only)
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func); {
+ TraceLog(LOG_WARNING, "OverrideInternalFunction called on unsupported platform");
+};
+
// EOF
diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c
index c6685846c..968611851 100644
--- a/src/platforms/rcore_desktop_glfw.c
+++ b/src/platforms/rcore_desktop_glfw.c
@@ -103,6 +103,7 @@ static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
void ClosePlatform(void); // Close platform
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func);
// Error callback event
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
@@ -1898,4 +1899,9 @@ static void JoystickCallback(int jid, int event)
}
}
+// Override an internal platform function with your own (PLATFORM_OFFSCREEN and PLATFORM_NONE only)
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func); {
+ TraceLog(LOG_WARNING, "OverrideInternalFunction called on unsupported platform");
+};
+
// EOF
diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c
index 64ab432e6..8fec55198 100644
--- a/src/platforms/rcore_desktop_rgfw.c
+++ b/src/platforms/rcore_desktop_rgfw.c
@@ -220,6 +220,7 @@ static const unsigned short keyMappingRGFW[] = {
//----------------------------------------------------------------------------------
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
bool InitGraphicsDevice(void); // Initialize graphics device
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func);
//----------------------------------------------------------------------------------
// Module Functions Declaration
@@ -1353,3 +1354,9 @@ static KeyboardKey ConvertScancodeToKey(u32 keycode)
return keyMappingRGFW[keycode];
}
+
+// Override an internal platform function with your own (PLATFORM_OFFSCREEN and PLATFORM_NONE only)
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func); {
+ TraceLog(LOG_WARNING, "OverrideInternalFunction called on unsupported platform");
+};
+
diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c
index 794f9e6a0..67b6a7dfa 100644
--- a/src/platforms/rcore_desktop_sdl.c
+++ b/src/platforms/rcore_desktop_sdl.c
@@ -225,6 +225,7 @@ static const int CursorsLUT[] = {
//----------------------------------------------------------------------------------
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
void ClosePlatform(void); // Close platform
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func);
static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode); // Help convert SDL scancodes to raylib key
@@ -1617,4 +1618,11 @@ static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode)
return KEY_NULL; // No equivalent key in Raylib
}
+
+
+// Override an internal platform function with your own (PLATFORM_OFFSCREEN and PLATFORM_NONE only)
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func); {
+ TraceLog(LOG_WARNING, "OverrideInternalFunction called on unsupported platform");
+};
+
// EOF
diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c
index 43dc19c71..9b7b7b3c5 100644
--- a/src/platforms/rcore_drm.c
+++ b/src/platforms/rcore_drm.c
@@ -219,6 +219,7 @@ static const short linuxToRaylibMap[KEYMAP_SIZE] = {
//----------------------------------------------------------------------------------
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
void ClosePlatform(void); // Close platform
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func);
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
static void InitKeyboard(void); // Initialize raw keyboard system
@@ -1938,4 +1939,9 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
return nearestIndex;
}
+// Override an internal platform function with your own (PLATFORM_OFFSCREEN and PLATFORM_NONE only)
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func); {
+ TraceLog(LOG_WARNING, "OverrideInternalFunction called on unsupported platform");
+};
+
// EOF
diff --git a/src/platforms/rcore_none.c b/src/platforms/rcore_none.c
new file mode 100644
index 000000000..f86c5bcb7
--- /dev/null
+++ b/src/platforms/rcore_none.c
@@ -0,0 +1,422 @@
+#include "rcore_none.h"
+#include
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+extern CoreData CORE; // Global CORE state context
+
+
+static PlatformData platform = { 0 }; // Platform specific data
+
+#define GEN_CALLBACK_BODY(fn_ret, ret_value, fn_name, named_args, args) \
+ fn_ret fn_name(LIST named_args) { \
+ if(internal##fn_name##Callback == NULL) {\
+ FUNCTION_MISSING_WARNING(fn_name) \
+ return ret_value; \
+ } else {\
+ return (*internal##fn_name##Callback)(LIST args); \
+ }\
+ }
+
+// Generate a callback that returns a void.
+#define GEN_CALLBACK_BODY_VOID(fn_name, named_args, args) \
+ void fn_name(LIST named_args) { \
+ if(internal##fn_name##Callback == NULL) {\
+ FUNCTION_MISSING_WARNING(fn_name) \
+ } else {\
+ (*internal##fn_name##Callback)(LIST args); \
+ }\
+ }
+
+// Generate any of the if/else statements in OverrideInternalFunction.
+#define GEN_CASE(fn_name) \
+ if (strcmp(funcName, #fn_name) == 0) { \
+ internal##fn_name##Callback = &(func-> fn_name); \
+ return; \
+ }
+
+// For the functions that have default behavior on PLATFORM_OFFSCREEN, check if the function exists
+// first.
+#define CHECK_AND_CALL(fn_name, args) \
+ if(internal##fn_name##Callback != NULL) {\
+ return (*internal##fn_name##Callback)(LIST args); \
+ }
+
+// For the functions that have default behavior on PLATFORM_OFFSCREEN, check if the function exists
+// first (void version).
+#define CHECK_AND_CALL_VOID(fn_name, args) \
+ if(internal##fn_name##Callback != NULL) {\
+ (*internal##fn_name##Callback)(LIST args); \
+ }
+
+GEN_CALLBACK_BODY_VOID(ClosePlatform, (void), ())
+GEN_CALLBACK_BODY_VOID(ToggleFullscreen, (void), ())
+GEN_CALLBACK_BODY_VOID(ToggleBorderlessWindowed, (void), ())
+GEN_CALLBACK_BODY_VOID(MaximizeWindow, (void), ())
+GEN_CALLBACK_BODY_VOID(MinimizeWindow, (void), ())
+GEN_CALLBACK_BODY_VOID(RestoreWindow, (void), ())
+GEN_CALLBACK_BODY_VOID(SetWindowIcon, (Image image), (image))
+GEN_CALLBACK_BODY_VOID(SetWindowIcons, (Image *images, int count), (images, count))
+GEN_CALLBACK_BODY_VOID(SetWindowTitle, (const char *title), (title))
+GEN_CALLBACK_BODY_VOID(SetWindowPosition, (int x, int y), (x,y))
+GEN_CALLBACK_BODY_VOID(SetWindowMonitor, (int monitor), (monitor))
+GEN_CALLBACK_BODY_VOID(SetWindowOpacity, (float opacity), (opacity))
+GEN_CALLBACK_BODY_VOID(SetWindowFocused, (void), ())
+GEN_CALLBACK_BODY_VOID(EnableCursor, (void), ())
+GEN_CALLBACK_BODY_VOID(DisableCursor, (void), ())
+GEN_CALLBACK_BODY_VOID(SwapScreenBuffer, (void), ())
+GEN_CALLBACK_BODY_VOID(SetGamepadVibration, (int gamepad, float leftMotor, float rightMotor), (gamepad,leftMotor,rightMotor))
+GEN_CALLBACK_BODY_VOID(SetMousePosition, (int x, int y), (x,y))
+GEN_CALLBACK_BODY_VOID(SetMouseCursor, (int cursor), (cursor))
+GEN_CALLBACK_BODY_VOID(PollInputEvents, (void), ())
+GEN_CALLBACK_BODY_VOID(SetClipboardText, (const char *text), (text))
+GEN_CALLBACK_BODY(int, 0, SetGamepadMappings, (const char *mappings), (mappings))
+GEN_CALLBACK_BODY(void *, NULL, GetWindowHandle, (void), ())
+GEN_CALLBACK_BODY(Vector2, Vector2Zero(), GetMonitorPosition, (int monitor), (monitor))
+GEN_CALLBACK_BODY(int, 0, GetMonitorWidth, (int monitor), (monitor))
+GEN_CALLBACK_BODY(int, 0, GetMonitorHeight, (int monitor), (monitor))
+GEN_CALLBACK_BODY(int, 0, GetMonitorPhysicalWidth, (int monitor), (monitor))
+GEN_CALLBACK_BODY(int, 0, GetMonitorPhysicalHeight, (int monitor), (monitor))
+GEN_CALLBACK_BODY(int, 0, GetMonitorRefreshRate, (int monitor), (monitor))
+GEN_CALLBACK_BODY(const char*, "", GetMonitorName, (int monitor), (monitor))
+GEN_CALLBACK_BODY(Vector2, Vector2Zero(), GetWindowPosition, (void), ())
+GEN_CALLBACK_BODY(Vector2, Vector2Zero(), GetWindowScaleDPI, (void), ())
+GEN_CALLBACK_BODY(const char *, "", GetClipboardText, (void), ())
+GEN_CALLBACK_BODY(const char *, "", GetKeyName, (int key), (key))
+GEN_CALLBACK_BODY(double, 0.0, GetTime, (void), ())
+GEN_CALLBACK_BODY_VOID(OpenURL, (const char *url), (url))
+
+// Override an internal platform function with your own (PLATFORM_OFFSCREEN and PLATFORM_NONE only).
+// Note that there is no responsibility here for the Raylib maintainers to keep a stable API for core functions
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func) {
+ GEN_CASE(InitPlatform)
+ GEN_CASE(ClosePlatform)
+ GEN_CASE(ToggleFullscreen)
+ GEN_CASE(ToggleBorderlessWindowed)
+ GEN_CASE(MaximizeWindow)
+ GEN_CASE(MinimizeWindow)
+ GEN_CASE(RestoreWindow)
+ GEN_CASE(SetWindowIcon)
+ GEN_CASE(SetWindowIcons)
+ GEN_CASE(SetWindowTitle)
+ GEN_CASE(SetWindowPosition)
+ GEN_CASE(SetWindowMonitor)
+ GEN_CASE(SetWindowOpacity)
+ GEN_CASE(SetWindowFocused)
+ GEN_CASE(EnableCursor)
+ GEN_CASE(DisableCursor)
+ GEN_CASE(SwapScreenBuffer)
+ GEN_CASE(SetGamepadVibration)
+ GEN_CASE(SetMousePosition)
+ GEN_CASE(SetMouseCursor)
+ GEN_CASE(PollInputEvents)
+ GEN_CASE(SetClipboardText)
+ GEN_CASE(SetGamepadMappings)
+ GEN_CASE(GetWindowHandle)
+ GEN_CASE(GetMonitorPosition)
+ GEN_CASE(GetMonitorWidth)
+ GEN_CASE(GetMonitorHeight)
+ GEN_CASE(GetMonitorPhysicalWidth)
+ GEN_CASE(GetMonitorPhysicalHeight)
+ GEN_CASE(GetMonitorRefreshRate)
+ GEN_CASE(GetMonitorName)
+ GEN_CASE(GetWindowPosition)
+ GEN_CASE(GetWindowScaleDPI)
+ GEN_CASE(GetClipboardText)
+ GEN_CASE(GetKeyName)
+ GEN_CASE(GetTime)
+
+ TraceLog(LOG_ERROR, "Unknown function name \"%s\", did not bind.",funcName);
+};
+
+CoreData * GetCore() {
+ return &CORE;
+}
+
+#ifdef PLATFORM_OFFSCREEN
+//
+int InitPlatform(void) {
+ CHECK_AND_CALL(InitPlatform, ());
+ CORE.Window.ready = true;
+ TRACELOG(LOG_WARNING, "InitPlatform was called but not overriden by the user");
+ return 0;
+}
+
+// Check if application should close
+// NOTE: By default, if KEY_ESCAPE pressed or window close icon clicked
+
+bool WindowShouldClose(void)
+{
+ CHECK_AND_CALL(WindowShouldClose, ());
+ if (CORE.Window.ready) return CORE.Window.shouldClose;
+ else return true;
+}
+
+// Set window configuration state using flags
+void SetWindowState(unsigned int flags)
+{
+ CHECK_AND_CALL_VOID(SetWindowState, (flags));
+ // Check previous state and requested state to apply required changes
+ // NOTE: In most cases the functions already change the flags internally
+
+ // State change: FLAG_VSYNC_HINT
+ if (((CORE.Window.flags & FLAG_VSYNC_HINT) != (flags & FLAG_VSYNC_HINT)) && ((flags & FLAG_VSYNC_HINT) > 0))
+ {
+ CORE.Window.flags |= FLAG_VSYNC_HINT;
+ }
+
+ // State change: FLAG_BORDERLESS_WINDOWED_MODE
+ // NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running
+ if (((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) != (flags & FLAG_BORDERLESS_WINDOWED_MODE)) && ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0))
+ {
+ ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function
+ }
+
+ // State change: FLAG_FULLSCREEN_MODE
+ if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) != (flags & FLAG_FULLSCREEN_MODE))
+ {
+ ToggleFullscreen(); // NOTE: Window state flag updated inside function
+ }
+
+ // State change: FLAG_WINDOW_RESIZABLE
+ if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) != (flags & FLAG_WINDOW_RESIZABLE)) && ((flags & FLAG_WINDOW_RESIZABLE) > 0))
+ {
+ CORE.Window.flags |= FLAG_WINDOW_RESIZABLE;
+ }
+
+ // State change: FLAG_WINDOW_UNDECORATED
+ if (((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) != (flags & FLAG_WINDOW_UNDECORATED)) && (flags & FLAG_WINDOW_UNDECORATED))
+ {
+ CORE.Window.flags |= FLAG_WINDOW_UNDECORATED;
+ }
+
+ // State change: FLAG_WINDOW_HIDDEN
+ if (((CORE.Window.flags & FLAG_WINDOW_HIDDEN) != (flags & FLAG_WINDOW_HIDDEN)) && ((flags & FLAG_WINDOW_HIDDEN) > 0))
+ {
+ CORE.Window.flags |= FLAG_WINDOW_HIDDEN;
+ }
+
+ // State change: FLAG_WINDOW_MINIMIZED
+ if (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) != (flags & FLAG_WINDOW_MINIMIZED)) && ((flags & FLAG_WINDOW_MINIMIZED) > 0))
+ {
+ //MinimizeWindow(); // NOTE: Window state flag updated inside function
+ }
+
+ // State change: FLAG_WINDOW_MAXIMIZED
+ if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) != (flags & FLAG_WINDOW_MAXIMIZED)) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0))
+ {
+ //MaximizeWindow(); // NOTE: Window state flag updated inside function
+ }
+
+ // State change: FLAG_WINDOW_UNFOCUSED
+ if (((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) != (flags & FLAG_WINDOW_UNFOCUSED)) && ((flags & FLAG_WINDOW_UNFOCUSED) > 0))
+ {
+ CORE.Window.flags |= FLAG_WINDOW_UNFOCUSED;
+ }
+
+ // State change: FLAG_WINDOW_TOPMOST
+ if (((CORE.Window.flags & FLAG_WINDOW_TOPMOST) != (flags & FLAG_WINDOW_TOPMOST)) && ((flags & FLAG_WINDOW_TOPMOST) > 0))
+ {
+ CORE.Window.flags |= FLAG_WINDOW_TOPMOST;
+ }
+
+ // State change: FLAG_WINDOW_ALWAYS_RUN
+ if (((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) != (flags & FLAG_WINDOW_ALWAYS_RUN)) && ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0))
+ {
+ CORE.Window.flags |= FLAG_WINDOW_ALWAYS_RUN;
+ }
+
+ // The following states can not be changed after window creation
+
+ // State change: FLAG_WINDOW_TRANSPARENT
+ if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) != (flags & FLAG_WINDOW_TRANSPARENT)) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0))
+ {
+ TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
+ }
+
+ // State change: FLAG_WINDOW_HIGHDPI
+ if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) != (flags & FLAG_WINDOW_HIGHDPI)) && ((flags & FLAG_WINDOW_HIGHDPI) > 0))
+ {
+ TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
+ }
+
+ // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
+ if (((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) != (flags & FLAG_WINDOW_MOUSE_PASSTHROUGH)) && ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0))
+ {
+ CORE.Window.flags |= FLAG_WINDOW_MOUSE_PASSTHROUGH;
+ }
+
+ // State change: FLAG_MSAA_4X_HINT
+ if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) != (flags & FLAG_MSAA_4X_HINT)) && ((flags & FLAG_MSAA_4X_HINT) > 0))
+ {
+ TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
+ }
+
+ // State change: FLAG_INTERLACED_HINT
+ if (((CORE.Window.flags & FLAG_INTERLACED_HINT) != (flags & FLAG_INTERLACED_HINT)) && ((flags & FLAG_INTERLACED_HINT) > 0))
+ {
+ TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
+ }
+}
+
+// Clear window configuration state flags
+void ClearWindowState(unsigned int flags)
+{
+ CHECK_AND_CALL_VOID(ClearWindowState, (flags));
+ // Check previous state and requested state to apply required changes
+ // NOTE: In most cases the functions already change the flags internally
+
+ // State change: FLAG_VSYNC_HINT
+ if (((CORE.Window.flags & FLAG_VSYNC_HINT) > 0) && ((flags & FLAG_VSYNC_HINT) > 0))
+ {
+ CORE.Window.flags &= ~FLAG_VSYNC_HINT;
+ }
+
+ // State change: FLAG_BORDERLESS_WINDOWED_MODE
+ // NOTE: This must be handled before FLAG_FULLSCREEN_MODE because ToggleBorderlessWindowed() needs to get some fullscreen values if fullscreen is running
+ if (((CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0) && ((flags & FLAG_BORDERLESS_WINDOWED_MODE) > 0))
+ {
+ ToggleBorderlessWindowed(); // NOTE: Window state flag updated inside function
+ }
+
+ // State change: FLAG_FULLSCREEN_MODE
+ if (((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) && ((flags & FLAG_FULLSCREEN_MODE) > 0))
+ {
+ ToggleFullscreen(); // NOTE: Window state flag updated inside function
+ }
+
+ // State change: FLAG_WINDOW_RESIZABLE
+ if (((CORE.Window.flags & FLAG_WINDOW_RESIZABLE) > 0) && ((flags & FLAG_WINDOW_RESIZABLE) > 0))
+ {
+ CORE.Window.flags &= ~FLAG_WINDOW_RESIZABLE;
+ }
+
+ // State change: FLAG_WINDOW_HIDDEN
+ if (((CORE.Window.flags & FLAG_WINDOW_HIDDEN) > 0) && ((flags & FLAG_WINDOW_HIDDEN) > 0))
+ {
+ CORE.Window.flags &= ~FLAG_WINDOW_HIDDEN;
+ }
+
+ // State change: FLAG_WINDOW_MINIMIZED
+ if (((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0) && ((flags & FLAG_WINDOW_MINIMIZED) > 0))
+ {
+ RestoreWindow(); // NOTE: Window state flag updated inside function
+ }
+
+ // State change: FLAG_WINDOW_MAXIMIZED
+ if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0))
+ {
+ RestoreWindow(); // NOTE: Window state flag updated inside function
+ }
+
+ // State change: FLAG_WINDOW_UNDECORATED
+ if (((CORE.Window.flags & FLAG_WINDOW_UNDECORATED) > 0) && ((flags & FLAG_WINDOW_UNDECORATED) > 0))
+ {
+ CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED;
+ }
+
+ // State change: FLAG_WINDOW_UNFOCUSED
+ if (((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) > 0) && ((flags & FLAG_WINDOW_UNFOCUSED) > 0))
+ {
+ CORE.Window.flags &= ~FLAG_WINDOW_UNFOCUSED;
+ }
+
+ // State change: FLAG_WINDOW_TOPMOST
+ if (((CORE.Window.flags & FLAG_WINDOW_TOPMOST) > 0) && ((flags & FLAG_WINDOW_TOPMOST) > 0))
+ {
+ CORE.Window.flags &= ~FLAG_WINDOW_TOPMOST;
+ }
+
+ // State change: FLAG_WINDOW_ALWAYS_RUN
+ if (((CORE.Window.flags & FLAG_WINDOW_ALWAYS_RUN) > 0) && ((flags & FLAG_WINDOW_ALWAYS_RUN) > 0))
+ {
+ CORE.Window.flags &= ~FLAG_WINDOW_ALWAYS_RUN;
+ }
+
+ // The following states can not be changed after window creation
+
+ // State change: FLAG_WINDOW_TRANSPARENT
+ if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0))
+ {
+ TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
+ }
+
+ // State change: FLAG_WINDOW_HIGHDPI
+ if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) && ((flags & FLAG_WINDOW_HIGHDPI) > 0))
+ {
+ TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
+ }
+
+ // State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
+ if (((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) && ((flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0))
+ {
+ CORE.Window.flags &= ~FLAG_WINDOW_MOUSE_PASSTHROUGH;
+ }
+
+ // State change: FLAG_MSAA_4X_HINT
+ if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) > 0) && ((flags & FLAG_MSAA_4X_HINT) > 0))
+ {
+ TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
+ }
+
+ // State change: FLAG_INTERLACED_HINT
+ if (((CORE.Window.flags & FLAG_INTERLACED_HINT) > 0) && ((flags & FLAG_INTERLACED_HINT) > 0))
+ {
+ TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
+ }
+}
+
+// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
+void SetWindowMinSize(int width, int height)
+{
+ CHECK_AND_CALL_VOID(SetWindowMinSize, (width, height));
+ CORE.Window.screenMin.width = width;
+ CORE.Window.screenMin.height = height;
+}
+
+// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE)
+void SetWindowMaxSize(int width, int height)
+{
+ CHECK_AND_CALL_VOID(SetWindowMaxSize, (width, height));
+ CORE.Window.screenMax.width = width;
+ CORE.Window.screenMax.height = height;
+}
+
+// Set window dimensions
+void SetWindowSize(int width, int height)
+{
+ CHECK_AND_CALL_VOID(SetWindowSize, (width, height));
+ CORE.Window.screen.width = width;
+ CORE.Window.screen.height = height;
+}
+
+// Get number of monitors
+int GetMonitorCount(void)
+{
+ CHECK_AND_CALL(GetMonitorCount, ());
+ return 1;
+}
+
+// Get number of monitors
+int GetCurrentMonitor(void)
+{
+ CHECK_AND_CALL(GetCurrentMonitor, ());
+ return 0;
+}
+
+// Show mouse cursor
+void ShowCursor(void)
+{
+ CHECK_AND_CALL_VOID(ShowCursor, ());
+ CORE.Input.Mouse.cursorHidden = false;
+}
+// Hides mouse cursor
+void HideCursor(void)
+{
+ CHECK_AND_CALL_VOID(HideCursor, ());
+ CORE.Input.Mouse.cursorHidden = true;
+}
+
+
+#endif
diff --git a/src/platforms/rcore_none.h b/src/platforms/rcore_none.h
new file mode 100644
index 000000000..5e15f57b9
--- /dev/null
+++ b/src/platforms/rcore_none.h
@@ -0,0 +1,188 @@
+/**********************************************************************************************
+*
+* rcore_none - Functions to manage window, graphics device and inputs
+*
+* PLATFORM: NONE
+*
+* LIMITATIONS:
+* - Limitation 01
+* - Limitation 02
+*
+* POSSIBLE IMPROVEMENTS:
+* - For OverrideInternalFunction, we should maybe consider hashing the input string
+* so that we can use a switch case? But to be fair this also isn't a function you should be running on loop.
+* - We could introduce a config flag to disable the if/else check if a function is set, letting the user
+* improve the performance at the cost of segfaults if a function pointer isn't set.
+*
+* ADDITIONAL NOTES:
+* - You still need a platform that has OpenGL, or a port of it, to use this.
+* - There is no responsibility for the maintainers of Raylib to keep a stable API here.
+*
+* LICENSE: zlib/libpng
+*
+* Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) and contributors
+*
+* This software is provided "as-is", without any express or implied warranty. In no event
+* will the authors be held liable for any damages arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose, including commercial
+* applications, and to alter it and redistribute it freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not claim that you
+* wrote the original software. If you use this software in a product, an acknowledgment
+* in the product documentation would be appreciated but is not required.
+*
+* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
+* as being the original software.
+*
+* 3. This notice may not be removed or altered from any source distribution.
+*
+**********************************************************************************************/
+
+#ifndef RCORE_NONE_H
+#define RCORE_NONE_H
+
+#include
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct {
+} PlatformData;
+
+
+//----------------------------------------------------------------------------------
+// Macros Declaration
+//----------------------------------------------------------------------------------
+// NOTE(IOI_XD):
+// Yes, macros suck. However, there is a right way to use them, I believe I have taken said precautions, and I believe it is worth it here because
+// it would make updating this file much easier.
+// That said, these are functions that will not have to be modified past when this is merged, except to rename/add them.
+
+// Macro that lets us put two vararg sections in one macro
+#define LIST(...) __VA_ARGS__
+
+// The code for warning the user that a function hasn't been overriden. On PLATFORM_NONE, this isn't emitted.
+#ifndef PLATFORM_OFFSCREEN
+#define FUNCTION_MISSING_WARNING(fn_name) TRACELOG(LOG_WARNING, #fn_name " was called but not overriden by the user");
+#else
+#define FUNCTION_MISSING_WARNING(fn_name)
+#endif
+
+// Generate a callback
+#define GEN_CALLBACK_HEAD(fn_ret, ret_value, fn_name, named_args, args) \
+ typedef fn_ret (*fn_name##Callback)(LIST named_args); \
+ static fn_name##Callback * internal##fn_name##Callback = NULL; \
+ fn_ret fn_name(LIST named_args);
+
+// Generate a callback that returns a void.
+#define GEN_CALLBACK_HEAD_VOID(fn_name, named_args, args) \
+ typedef void (*fn_name##Callback)(LIST named_args); \
+ static fn_name##Callback * internal##fn_name##Callback = NULL; \
+ void fn_name(LIST named_args);
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+// NOTE: Functions declaration is provided by raylib.h
+
+// We start with any functions that unambigiously must be overriden.
+GEN_CALLBACK_HEAD_VOID(ClosePlatform, (void), ())
+GEN_CALLBACK_HEAD_VOID(ToggleFullscreen, (void), ())
+GEN_CALLBACK_HEAD_VOID(ToggleBorderlessWindowed, (void), ())
+GEN_CALLBACK_HEAD_VOID(MaximizeWindow, (void), ())
+GEN_CALLBACK_HEAD_VOID(MinimizeWindow, (void), ())
+GEN_CALLBACK_HEAD_VOID(RestoreWindow, (void), ())
+GEN_CALLBACK_HEAD_VOID(SetWindowIcon, (Image image), (image))
+GEN_CALLBACK_HEAD_VOID(SetWindowIcons, (Image *images, int count), (images, count))
+GEN_CALLBACK_HEAD_VOID(SetWindowTitle, (const char *title), (title))
+GEN_CALLBACK_HEAD_VOID(SetWindowPosition, (int x, int y), (x,y))
+GEN_CALLBACK_HEAD_VOID(SetWindowMonitor, (int monitor), (monitor))
+GEN_CALLBACK_HEAD_VOID(SetWindowOpacity, (float opacity), (opacity))
+GEN_CALLBACK_HEAD_VOID(SetWindowFocused, (void), ())
+GEN_CALLBACK_HEAD_VOID(EnableCursor, (void), ())
+GEN_CALLBACK_HEAD_VOID(DisableCursor, (void), ())
+GEN_CALLBACK_HEAD_VOID(SwapScreenBuffer, (void), ())
+GEN_CALLBACK_HEAD_VOID(SetGamepadVibration, (int gamepad, float leftMotor, float rightMotor), (gamepad,leftMotor,rightMotor))
+GEN_CALLBACK_HEAD_VOID(SetMousePosition, (int x, int y), (x,y))
+GEN_CALLBACK_HEAD_VOID(SetMouseCursor, (int cursor), (cursor))
+GEN_CALLBACK_HEAD_VOID(PollInputEvents, (void), ())
+GEN_CALLBACK_HEAD_VOID(SetClipboardText, (const char *text), (text))
+GEN_CALLBACK_HEAD(int, 0, SetGamepadMappings, (const char *mappings), (mappings))
+GEN_CALLBACK_HEAD(void *, NULL, GetWindowHandle, (void), ())
+GEN_CALLBACK_HEAD(Vector2, Vector2Zero(), GetMonitorPosition, (int monitor), (monitor))
+GEN_CALLBACK_HEAD(int, 0, GetMonitorWidth, (int monitor), (monitor))
+GEN_CALLBACK_HEAD(int, 0, GetMonitorHeight, (int monitor), (monitor))
+GEN_CALLBACK_HEAD(int, 0, GetMonitorPhysicalWidth, (int monitor), (monitor))
+GEN_CALLBACK_HEAD(int, 0, GetMonitorPhysicalHeight, (int monitor), (monitor))
+GEN_CALLBACK_HEAD(int, 0, GetMonitorRefreshRate, (int monitor), (monitor))
+GEN_CALLBACK_HEAD(const char*, "", GetMonitorName, (int monitor), (monitor))
+GEN_CALLBACK_HEAD(Vector2, Vector2Zero(), GetWindowPosition, (void), ())
+GEN_CALLBACK_HEAD(Vector2, Vector2Zero(), GetWindowScaleDPI, (void), ())
+GEN_CALLBACK_HEAD(const char *, "", GetClipboardText, (void), ())
+GEN_CALLBACK_HEAD(const char *, "", GetKeyName, (int key), (key))
+GEN_CALLBACK_HEAD(double, 0.0, GetTime, (void), ())
+GEN_CALLBACK_HEAD_VOID(OpenURL, (const char *url), (url))
+
+// We then move on to functions that can be overriden, but on the offscreen platform, should have things set by default.
+GEN_CALLBACK_HEAD(int, 0, InitPlatform, (void), ())
+GEN_CALLBACK_HEAD(bool, true, WindowShouldClose, (void), ())
+GEN_CALLBACK_HEAD(int, 0, GetMonitorCount, (void), ())
+GEN_CALLBACK_HEAD(int, 0, GetCurrentMonitor, (void), ())
+GEN_CALLBACK_HEAD_VOID(ShowCursor, (void), ())
+GEN_CALLBACK_HEAD_VOID(HideCursor, (void), ())
+GEN_CALLBACK_HEAD_VOID(SetWindowState, (unsigned int flags), (flags))
+GEN_CALLBACK_HEAD_VOID(ClearWindowState, (unsigned int flags), (flags))
+GEN_CALLBACK_HEAD_VOID(SetWindowMinSize, (int width, int height), (width,height))
+GEN_CALLBACK_HEAD_VOID(SetWindowMaxSize, (int width, int height), (width,height))
+GEN_CALLBACK_HEAD_VOID(SetWindowSize, (int width, int height), (width,height))
+
+// Generate any of the fields for the OverridableFunctionPointer union.
+#define GEN_FIELD(fn_name) fn_name##Callback fn_name;
+
+// The avaliable functions you can pass to OverrideInternalFunction.
+// The fields are only accessible when compiling with PLATFORM_NONE or PLATFORM_OFFSCREEN
+union OverridableFunctionPointer {
+ GEN_FIELD(InitPlatform)
+ GEN_FIELD(ClosePlatform)
+ GEN_FIELD(ToggleFullscreen)
+ GEN_FIELD(ToggleBorderlessWindowed)
+ GEN_FIELD(MaximizeWindow)
+ GEN_FIELD(MinimizeWindow)
+ GEN_FIELD(RestoreWindow)
+ GEN_FIELD(SetWindowIcon)
+ GEN_FIELD(SetWindowIcons)
+ GEN_FIELD(SetWindowTitle)
+ GEN_FIELD(SetWindowPosition)
+ GEN_FIELD(SetWindowMonitor)
+ GEN_FIELD(SetWindowOpacity)
+ GEN_FIELD(SetWindowFocused)
+ GEN_FIELD(EnableCursor)
+ GEN_FIELD(DisableCursor)
+ GEN_FIELD(SwapScreenBuffer)
+ GEN_FIELD(SetGamepadVibration)
+ GEN_FIELD(SetMousePosition)
+ GEN_FIELD(SetMouseCursor)
+ GEN_FIELD(PollInputEvents)
+ GEN_FIELD(SetClipboardText)
+ GEN_FIELD(SetGamepadMappings)
+ GEN_FIELD(GetWindowHandle)
+ GEN_FIELD(GetMonitorPosition)
+ GEN_FIELD(GetMonitorWidth)
+ GEN_FIELD(GetMonitorHeight)
+ GEN_FIELD(GetMonitorPhysicalWidth)
+ GEN_FIELD(GetMonitorPhysicalHeight)
+ GEN_FIELD(GetMonitorRefreshRate)
+ GEN_FIELD(GetMonitorName)
+ GEN_FIELD(GetWindowPosition)
+ GEN_FIELD(GetWindowScaleDPI)
+ GEN_FIELD(GetClipboardText)
+ GEN_FIELD(GetKeyName)
+ GEN_FIELD(GetTime)
+};
+
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func);
+//CoreData * GetCore(); // Get and set variables of Raylib's core struct
+
+// EOF
+#endif
\ No newline at end of file
diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c
index 938f4ed7d..15ef04a48 100644
--- a/src/platforms/rcore_template.c
+++ b/src/platforms/rcore_template.c
@@ -73,6 +73,7 @@ static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
bool InitGraphicsDevice(void); // Initialize graphics device
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func);
//----------------------------------------------------------------------------------
// Module Functions Declaration
@@ -595,4 +596,9 @@ void ClosePlatform(void)
// TODO: De-initialize graphics, inputs and more
}
+// Override an internal platform function with your own (PLATFORM_OFFSCREEN and PLATFORM_NONE only)
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func); {
+ TraceLog(LOG_WARNING, "OverrideInternalFunction called on unsupported platform");
+};
+
// EOF
diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c
index ff7a92dbc..41ee4e573 100644
--- a/src/platforms/rcore_web.c
+++ b/src/platforms/rcore_web.c
@@ -107,6 +107,7 @@ Vector2 lockedMousePos = { 0 };
//----------------------------------------------------------------------------------
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
void ClosePlatform(void); // Close platform
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func);
// Error callback event
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
@@ -1729,4 +1730,9 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
return 1; // The event was consumed by the callback handler
}
+// Override an internal platform function with your own (PLATFORM_OFFSCREEN and PLATFORM_NONE only)
+void OverrideInternalFunction(const char * funcName, union OverridableFunctionPointer * func); {
+ TraceLog(LOG_WARNING, "OverrideInternalFunction called on unsupported platform");
+};
+
// EOF
diff --git a/src/rcore.c b/src/rcore.c
index 972d58600..b2b27ada6 100644
--- a/src/rcore.c
+++ b/src/rcore.c
@@ -515,6 +515,10 @@ const char *TextFormat(const char *text, ...); // Formatting of tex
#include "platforms/rcore_drm.c"
#elif defined(PLATFORM_ANDROID)
#include "platforms/rcore_android.c"
+#elif defined(PLATFORM_NONE)
+ #include "platforms/rcore_none.c"
+#elif defined(PLATFORM_OFFSCREEN)
+ #include "platforms/rcore_none.c"
#else
// TODO: Include your custom platform backend!
// i.e software rendering backend or console backend!
diff --git a/src/rmod.h b/src/rmod.h
new file mode 100644
index 000000000..211d8ae3e
--- /dev/null
+++ b/src/rmod.h
@@ -0,0 +1,11 @@
+#ifndef RMOD_H
+#define RMOD_H
+
+#ifdef PLATFORM_NONE
+#include "platforms/rcore_none.h"
+#endif
+#ifdef PLATFORM_OFFSCREEN
+#include "platforms/rcore_none.h"
+#endif
+
+#endif // RMOD_H
\ No newline at end of file