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) | models_loading_vox | ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) | | 92 | [models_loading_m3d](models/models_loading_m3d.c) | models_loading_m3d | ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) | | 93 | [models_orthographic_projection](models/models_orthographic_projection.c) | models_orthographic_projection | ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) | -| 94 | [models_point_rendering](models/models_point_rendering.c) | models_point_rendering | ⭐️⭐️☆☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) | -| 95 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | models_rlgl_solar_system | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | -| 96 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | models_yaw_pitch_roll | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) | -| 97 | [models_waving_cubes](models/models_waving_cubes.c) | models_waving_cubes | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) | -| 98 | [models_heightmap](models/models_heightmap.c) | models_heightmap | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | -| 99 | [models_skybox](models/models_skybox.c) | models_skybox | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) | +| 94 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | models_rlgl_solar_system | ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) | +| 95 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | models_yaw_pitch_roll | ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) | +| 96 | [models_waving_cubes](models/models_waving_cubes.c) | models_waving_cubes | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) | +| 97 | [models_heightmap](models/models_heightmap.c) | models_heightmap | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) | +| 98 | [models_skybox](models/models_skybox.c) | models_skybox | ⭐️⭐️☆☆ | 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) | shaders_basic_lighting | ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) | -| 101 | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) | -| 102 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | -| 103 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | shaders_custom_uniform | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 104 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | shaders_postprocessing | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | -| 105 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | shaders_palette_switch | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) | -| 106 | [shaders_raymarching](shaders/shaders_raymarching.c) | shaders_raymarching | ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) | -| 107 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | shaders_texture_drawing | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) | -| 108 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) | -| 109 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | -| 110 | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) | -| 111 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | shaders_eratosthenes | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) | -| 112 | [shaders_fog](shaders/shaders_fog.c) | shaders_fog | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 113 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 114 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) | -| 115 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) | -| 116 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 117 | [shaders_spotlight](shaders/shaders_spotlight.c) | shaders_spotlight | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | -| 118 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | shaders_deferred_render | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) | +| 99 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | shaders_basic_lighting | ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) | +| 100 | [shaders_model_shader](shaders/shaders_model_shader.c) | shaders_model_shader | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) | +| 101 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | shaders_shapes_textures | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) | +| 102 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | shaders_custom_uniform | ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 103 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | shaders_postprocessing | ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) | +| 104 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | shaders_palette_switch | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) | +| 105 | [shaders_raymarching](shaders/shaders_raymarching.c) | shaders_raymarching | ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) | +| 106 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | shaders_texture_drawing | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) | +| 107 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | shaders_texture_outline | ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) | +| 108 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | shaders_texture_waves | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) | +| 109 | [shaders_julia_set](shaders/shaders_julia_set.c) | shaders_julia_set | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) | +| 110 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | shaders_eratosthenes | ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) | +| 111 | [shaders_fog](shaders/shaders_fog.c) | shaders_fog | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 112 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | shaders_simple_mask | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 113 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | shaders_hot_reloading | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) | +| 114 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | shaders_mesh_instancing | ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) | +| 115 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | shaders_multi_sample2d | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 116 | [shaders_spotlight](shaders/shaders_spotlight.c) | shaders_spotlight | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) | +| 117 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | shaders_deferred_render | ⭐️⭐️⭐️⭐️ | 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) | audio_module_playing | ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) | -| 120 | [audio_music_stream](audio/audio_music_stream.c) | audio_music_stream | ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | -| 121 | [audio_raw_stream](audio/audio_raw_stream.c) | audio_raw_stream | ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) | -| 122 | [audio_sound_loading](audio/audio_sound_loading.c) | audio_sound_loading | ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) | +| 118 | [audio_module_playing](audio/audio_module_playing.c) | audio_module_playing | ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) | +| 119 | [audio_music_stream](audio/audio_music_stream.c) | audio_music_stream | ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) | +| 120 | [audio_raw_stream](audio/audio_raw_stream.c) | audio_raw_stream | ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) | +| 121 | [audio_sound_loading](audio/audio_sound_loading.c) | audio_sound_loading | ⭐️☆☆☆ | 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) | rlgl_standalone | ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) | -| 124 | [rlgl_compute_shader](others/rlgl_compute_shader.c) | rlgl_compute_shader | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) | -| 125 | [easings_testbed](others/easings_testbed.c) | easings_testbed | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) | -| 126 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | raylib_opengl_interop | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) | -| 127 | [embedded_files_loading](others/embedded_files_loading.c) | embedded_files_loading | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) | +| 122 | [rlgl_standalone](others/rlgl_standalone.c) | rlgl_standalone | ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) | +| 123 | [rlgl_compute_shader](others/rlgl_compute_shader.c) | rlgl_compute_shader | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) | +| 124 | [easings_testbed](others/easings_testbed.c) | easings_testbed | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) | +| 125 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | raylib_opengl_interop | ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) | +| 126 | [embedded_files_loading](others/embedded_files_loading.c) | embedded_files_loading | ⭐️⭐️☆☆ | 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