diff --git a/README.md b/README.md index f048de5..6f58a84 100644 --- a/README.md +++ b/README.md @@ -5,22 +5,22 @@ Bindings for [Vala](https://vala.dev/) to use the simple and easy to use graphics library [Raylib](https://github.com/raysan5/raylib). ## Description -Ralib VAPI currently supports the core module of Raylib using a C style API for ease of code porting. +Raylib VAPI currently supports the core module of Raylib using a C style API for ease of code porting. Some VAPI's will be released to follow a more [OOP design](https://en.wikipedia.org/wiki/Object-oriented_programming) as well if you wish to use them in a more traditional Vala style. ## Supported Modules -| Module | Supported | OOP Available | VAPI Name | Version | -|:-------:|:------------------:|:------------------:|:-----------:|:-------:| -| raylib | :heavy_check_mark: | :construction: | raylib.vapi | 5.0 | -| rlgl | :heavy_check_mark: | :x: | rlgl.vapi | 4.5 | -| raymath | :x: | :x: | | | -| raudio | :x: | :x: | | | -| raygui | :x: | :x: | | | -| rpng | :x: | :x: | | | -| rini | :heavy_check_mark: | :x: | rini.vapi | 1.0 | -| rres | :x: | :x: | | | +| Module | Supported | OOP Available | VAPI Name | Version | +|:-------:|:-------------------:|:-------------:|:------------:|:-------:| +| raylib | :heavy_check_mark: | :x: | raylib.vapi | 6.0 | +| rlgl | :heavy_check_mark: | :x: | rlgl.vapi | 6.0 | +| raymath | :heavy_check_mark: | :x: | raymath.vapi | 2.0 | +| raygui | :heavy_check_mark: | :x: | raygui.vapi | 5.0 | +| rpng | :x: | :x: | | | +| rres | :x: | :x: | | | +| rini | :heavy_check_mark: | :x: | rini.vapi | 3.0 | +| physac | :heavy_check_mark: | :x: | physac.vapi | 1.1 | ## Example ```vala @@ -47,16 +47,3 @@ public static int main (string[] args) { return 0; } ``` - -## Compiling Included Examples -```bash -cd examples - -meson build -C build - -cd build/ - -Camera3D/application # To run the 3D camera example - # or -SmoothPixel/application # To run the smooth pixel perfect example -``` diff --git a/examples/Core/BasicWindow/Main.vala b/examples/Core/BasicWindow/Main.vala new file mode 100644 index 0000000..c2a2959 --- /dev/null +++ b/examples/Core/BasicWindow/Main.vala @@ -0,0 +1,39 @@ +using Raylib; + +public static int main () { + // Initialization + //-------------------------------------------------------------------------------------- + const int SCREEN_WIDTH = 800; + const int SCREEN_HEIGHT = 450; + + init_window (SCREEN_WIDTH, SCREEN_HEIGHT, "Vala raylib [core] example - basic window"); + + set_target_fps (60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!window_should_close ()) { // Detect window close button or ESC key + // Update + //---------------------------------------------------------------------------------- + + // Update your variables here + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + begin_drawing (); + { + clear_background (RAYWHITE); + draw_text ("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); + } + end_drawing (); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + close_window (); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + return 0; +} diff --git a/examples/Physac/meson.build b/examples/Core/BasicWindow/meson.build similarity index 73% rename from examples/Physac/meson.build rename to examples/Core/BasicWindow/meson.build index 895a293..45326d5 100644 --- a/examples/Physac/meson.build +++ b/examples/Core/BasicWindow/meson.build @@ -1,7 +1,5 @@ executable ( - 'application', - + 'core-basic-window', 'Main.vala', - dependencies: project_dependency ) diff --git a/examples/Camera3D/Main.vala b/examples/Core/Camera3D/Main.vala similarity index 96% rename from examples/Camera3D/Main.vala rename to examples/Core/Camera3D/Main.vala index aabf1f0..7294171 100644 --- a/examples/Camera3D/Main.vala +++ b/examples/Core/Camera3D/Main.vala @@ -1,4 +1,5 @@ using Raylib; +using Raymath; public const int MAX_COLUMNS = 20; public const int SCREEN_WIDTH = 800; @@ -34,7 +35,7 @@ public static int main (string[] args) { clear_background (RAYWHITE); - begin_mode_3D (camera); + begin_mode_3d (camera); draw_plane ({ 0.0f, 0.0f, 0.0f }, { 32.0f, 32.0f }, { 200, 200, 200, 255 }); draw_cube ({ -16.0f, 2.5f, 0.0f }, 1.0f, 5.0f, 32.0f, BLUE); @@ -47,7 +48,7 @@ public static int main (string[] args) { draw_cube_wires (positions[i], 2.0f, heights[i], 2.0f, MAROON); } - end_mode_3D (); + end_mode_3d (); draw_rectangle ( 10, 10, 220, 70, fade (SKYBLUE, 0.5f)); draw_rectangle_lines ( 10, 10, 220, 70, BLUE); diff --git a/examples/Camera3D/meson.build b/examples/Core/Camera3D/meson.build similarity index 75% rename from examples/Camera3D/meson.build rename to examples/Core/Camera3D/meson.build index 895a293..746e474 100644 --- a/examples/Camera3D/meson.build +++ b/examples/Core/Camera3D/meson.build @@ -1,7 +1,5 @@ executable ( - 'application', - + 'core-camera-3d', 'Main.vala', - dependencies: project_dependency ) diff --git a/examples/SmoothPixel/Main.vala b/examples/Core/SmoothPixelPerfect/Main.vala similarity index 80% rename from examples/SmoothPixel/Main.vala rename to examples/Core/SmoothPixelPerfect/Main.vala index 82ef631..1628155 100644 --- a/examples/SmoothPixel/Main.vala +++ b/examples/Core/SmoothPixelPerfect/Main.vala @@ -1,4 +1,5 @@ using Raylib; +using Raymath; public const int SCREEN_WIDTH = 800; public const int SCREEN_HEIGHT = 450; @@ -24,7 +25,10 @@ public static int main () { Rectangle rec03 = { 80.0f, 65.0f, 15.0f, 25.0f }; Rectangle source_rectangle = { 0.0f, 0.0f, target.texture.width, -target.texture.height }; - Rectangle destination_rectangle = { -VIRTUAL_RATIO, -VIRTUAL_RATIO, SCREEN_WIDTH + (VIRTUAL_RATIO * 2), SCREEN_HEIGHT + (VIRTUAL_RATIO * 2) }; + Rectangle destination_rectangle = { -VIRTUAL_RATIO, + -VIRTUAL_RATIO, + SCREEN_WIDTH + (VIRTUAL_RATIO * 2), + SCREEN_HEIGHT + (VIRTUAL_RATIO * 2) }; Vector2 origin = { 0.0f, 0.0f }; @@ -56,25 +60,31 @@ public static int main () { screen_space_camera.target.y *= VIRTUAL_RATIO; begin_texture_mode (target); + { clear_background (RAYWHITE); - - begin_mode_2D (world_space_camera); + begin_mode_2d (world_space_camera); + { draw_rectangle_pro (rec01, origin, rotation, BLACK); - draw_rectangle_pro (rec02, origin, -rotation, RED); + draw_rectangle_pro (rec02, origin, - rotation, RED); draw_rectangle_pro (rec03, origin, rotation + 45.0f, BLUE); - end_mode_2D (); - end_texture_mode(); + } + end_mode_2d (); + } + end_texture_mode (); begin_drawing (); + { clear_background (RED); - - begin_mode_2D (screen_space_camera); + begin_mode_2d (screen_space_camera); + { draw_texture_pro (target.texture, source_rectangle, destination_rectangle, origin, 0.0f, WHITE); - end_mode_2D (); + } + end_mode_2d (); draw_text (@"Screen resolution: $(SCREEN_WIDTH)x$(SCREEN_HEIGHT)", 10, 10, 20, DARKBLUE); draw_text (@"World resolution: $(VIRTUAL_SCREEN_WIDTH)x$(VIRTUAL_SCREEN_HEIGHT)", 10, 40, 20, DARKGREEN); draw_fps ( get_screen_width () - 95, 10); + } end_drawing (); } diff --git a/examples/Core/SmoothPixelPerfect/meson.build b/examples/Core/SmoothPixelPerfect/meson.build new file mode 100644 index 0000000..cba14b6 --- /dev/null +++ b/examples/Core/SmoothPixelPerfect/meson.build @@ -0,0 +1,5 @@ +executable ( + 'core-smooth-pixel-perfect', + 'Main.vala', + dependencies: project_dependency +) diff --git a/examples/Physac/Demo/Main.vala b/examples/Physac/Demo/Main.vala new file mode 100644 index 0000000..bc3692f --- /dev/null +++ b/examples/Physac/Demo/Main.vala @@ -0,0 +1,111 @@ +using Raylib; +using Raymath; +using Physac; + +public static int main () { + // Initialization + //-------------------------------------------------------------------------------------- + const int SCREEN_WIDTH = 800; + const int SCREEN_HEIGHT = 450; + + set_config_flags (ConfigFlags.MSAA_4X_HINT); + init_window (SCREEN_WIDTH, SCREEN_HEIGHT, "Vala raylib [physac] example - physics demo"); + + // Physac logo drawing position + int logo_x = SCREEN_WIDTH - measure_text ("Physac", 30) - 10; + int logo_y = 15; + + Vector2 rectangle_body_pos = { SCREEN_WIDTH / 2.0f, SCREEN_HEIGHT }; + Vector2 circle_body_pos = { SCREEN_WIDTH / 2.0f, SCREEN_HEIGHT / 2.0f }; + + // Initialize physics and default physics bodies + init_physics (); + + // Create floor rectangle physics body + var floor = create_physics_body_rectangle (rectangle_body_pos, 500, 100, 10); + floor.enabled = false; // Disable body state to convert it to static (no dynamics, but collisions) + + // Create obstacle circle physics body + var circle = create_physics_body_circle (circle_body_pos, 45, 10); + circle.enabled = false; // Disable body state to convert it to static (no dynamics, but collisions) + + set_target_fps (60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!window_should_close ()) { // Detect window close button or ESC key + // Update + //---------------------------------------------------------------------------------- + update_physics (); // Update physics system + + if (is_key_pressed (KeyboardKey.R)) { // Reset physics system + reset_physics (); + floor = create_physics_body_rectangle (rectangle_body_pos, 500, 100, 10); + floor.enabled = false; + + circle = create_physics_body_circle (circle_body_pos, 45, 10); + circle.enabled = false; + } + + // Physics body creation inputs + if (is_mouse_button_pressed (MouseButton.LEFT)) { + create_physics_body_polygon (get_mouse_position (), get_random_value (20, 80), get_random_value (3, 8), 10); + } else if (is_mouse_button_pressed (MouseButton.RIGHT)) { + create_physics_body_circle (get_mouse_position (), get_random_value (10, 45), 10); + } + + // Destroy falling physics bodies + int bodies_count = get_physics_bodies_count (); + for (int i = bodies_count - 1; i >= 0; i--) { + var body = get_physics_body (i); + if (body != null && (body.position.y > SCREEN_HEIGHT * 2)) { + destroy_physics_body (body); + } + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + begin_drawing (); + + clear_background (BLACK); + + draw_fps (SCREEN_WIDTH - 90, SCREEN_HEIGHT - 30); + + // Draw created physics bodies + bodies_count = get_physics_bodies_count (); + for (int i = 0; i < bodies_count; i++) { + var body = get_physics_body (i); + if (body != null) { + int vertex_count = get_physics_shape_vertices_count (i); + for (int j = 0; j < vertex_count; j++) { + // Get physics bodies shape vertices to draw lines + // Note: get_physics_shape_vertex () already calculates rotation transformations + Vector2 vertex_a = get_physics_shape_vertex (body, j); + + int jj = (((j + 1) < vertex_count) ? (j + 1) : 0); // Get next vertex or first to close the shape + Vector2 vertex_b = get_physics_shape_vertex (body, jj); + + draw_line_vector (vertex_a, vertex_b, GREEN); // Draw a line between two vertex positions + } + } + } + + draw_text ("Left mouse button to create a polygon", 10, 10, 10, WHITE); + draw_text ("Right mouse button to create a circle", 10, 25, 10, WHITE); + draw_text ("Press 'R' to reset example", 10, 40, 10, WHITE); + + draw_text ("Physac", logo_x, logo_y, 30, WHITE); + draw_text ("Powered by", logo_x + 50, logo_y - 7, 10, WHITE); + + end_drawing (); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + close_physics (); // Unitialize physics + close_window (); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + return 0; +} diff --git a/examples/SmoothPixel/meson.build b/examples/Physac/Demo/meson.build similarity index 76% rename from examples/SmoothPixel/meson.build rename to examples/Physac/Demo/meson.build index 895a293..08a2698 100644 --- a/examples/SmoothPixel/meson.build +++ b/examples/Physac/Demo/meson.build @@ -1,7 +1,5 @@ executable ( - 'application', - + 'physac-demo', 'Main.vala', - dependencies: project_dependency ) diff --git a/examples/Physac/Main.vala b/examples/Physac/Main.vala deleted file mode 100644 index 0b0c35a..0000000 --- a/examples/Physac/Main.vala +++ /dev/null @@ -1,43 +0,0 @@ -using Raylib; -using Physac; - -public const int WINDOW_WIDTH = 800; -public const int WINDOW_HEIGHT = 450; - -public static int main (string[] args) { - init_window (WINDOW_WIDTH, WINDOW_HEIGHT, "raylib [core] example - basic window"); - - init_physics (); - - PhysicsBody floor = create_physics_body_rectangle ({ WINDOW_WIDTH / 2, WINDOW_HEIGHT }, 500.0f, 100.0f, 10); - floor.enabled = false; - - PhysicsBody circle = create_physics_body_circle ({ WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 }, 45.0f, 10.0f); - circle.enabled = false; - - set_target_fps (60); - - while (!window_should_close ()) { - int body_count = get_physics_bodies_count (); - - for (int i = body_count - 1; i >= 0; i--) { - PhysicsBody? body = get_physics_body (i); - - if ((body != null) && body.position.y > WINDOW_HEIGHT * 2) { - destroy_physics_body (body); - } - } - - begin_drawing (); - clear_background (RAYWHITE); - - draw_text ("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); - end_drawing (); - } - - close_physics (); - - close_window (); - - return 0; -} diff --git a/examples/RayGui/ControlsTestSuite/Main.vala b/examples/RayGui/ControlsTestSuite/Main.vala new file mode 100644 index 0000000..1c59389 --- /dev/null +++ b/examples/RayGui/ControlsTestSuite/Main.vala @@ -0,0 +1,349 @@ +using Raylib; +using Raymath; +using Raygui; + +public static int main () { + // Initialization + //-------------------------------------------------------------------------------------- + const int SCREEN_WIDTH = 960; + const int SCREEN_HEIGHT = 560; + + init_window (SCREEN_WIDTH, SCREEN_HEIGHT, "Vala raygui - controls test suite"); + set_exit_key (0); + + // GUI controls initialization + //---------------------------------------------------------------------------------- + bool force_squared_checked = false; + + int spinner_001_value = 0; + bool spinner_edit_mode = false; + + int value_box_002_value = 0; + bool value_box_edit_mode = false; + + string text_box_text = "Text box"; + bool text_box_edit_mode = false; + + string text_box_multi_text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " + + "incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud " + + "exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\nDuis aute " + + "irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " + + "pariatur." + + "\n\nThisisastringlongerthanexpectedwithoutspacestotestcharbreaksforthosecases," + + "checkingifworkingasexpected.\n\nExcepteur sint occaecat cupidatat non proident, " + + "sunt in culpa qui officia deserunt mollit anim id est laborum."; + bool text_box_multi_edit_mode = false; + + int visual_style_active = 0; + + int dropdown_box_000_active = 0; + bool dropdown_000_edit_mode = false; + + int dropdown_box_001_active = 0; + bool dropdown_001_edit_mode = false; + + int list_view_scroll_index = 0; + int list_view_active = -1; + + int list_view_ext_scroll_index = 0; + int list_view_ext_active = 2; + int list_view_ext_focus = -1; + string[] list_view_ext_list = { "This", "is", "a", "list view", "with", + "disable", "elements", "amazing!" }; + + int toggle_group_active = 0; + int toggle_slider_active = 0; + + Color color_picker_value = RED; + + float slider_value = 50.0f; + float slider_bar_value = 60; + float progress_value = 0.1f; + + Vector2 view_scroll = { 0, 0 }; + + float alpha_value = 0.5f; + + string status_bar_text = "This is a status bar"; + //---------------------------------------------------------------------------------- + + bool show_message_box = false; + + string text_input = ""; + string text_input_file_name = ""; + bool show_text_input_box = false; + float alpha = 1.0f; + + bool exit_window = false; + + set_target_fps (60); + //---------------------------------------------------------------------------------- + while (!exit_window) { + // Update + //---------------------------------------------------------------------------------- + exit_window = window_should_close (); + + if (is_key_pressed (KeyboardKey.ESCAPE)) { + show_message_box = !show_message_box; + } + + if (is_key_down (KeyboardKey.LEFT_CONTROL) && is_key_pressed (KeyboardKey.S)) { + show_text_input_box = !show_text_input_box; + } + + if (is_file_dropped ()) { + FilePathList dropped_files = load_dropped_files (); + if ((dropped_files.paths.length > 0) && is_file_extension (dropped_files.paths[0], ".rgs")) { + gui_load_style (dropped_files.paths[0]); + } + unload_dropped_files (dropped_files);// Clear internal buffers + } + + //alpha -= 0.002f; + if (alpha < 0.0f) { alpha = 0.0f; } + if (is_key_pressed (KeyboardKey.SPACE)) { alpha = 1.0f; } + + gui_set_alpha (alpha); + + //progress_value += 0.002f; + if (is_key_pressed (KeyboardKey.LEFT)) { + progress_value -= 0.1f; + } else if (is_key_pressed (KeyboardKey.RIGHT)) { + progress_value += 0.1f; + } + progress_value = Raymath.clamp (progress_value, 0.0f, 1.0f); + + gui_load_style_default (); + begin_drawing (); + { + var bg_color_style = gui_get_style (Control.DEFAULT, + (ControlProperty) DefaultProperty.BACKGROUND_COLOR); + clear_background (get_color (bg_color_style)); + + // First GUI column + // Checkbox + gui_check_box ({ 25, 108, 15, 15 }, "FORCE CHECK!", ref force_squared_checked); + + // Spinner box + gui_set_style (Control.TEXT_BOX, ControlProperty.TEXT_ALIGNMENT, (int) TextAlignment.CENTER); + var res = gui_spinner ({ 25, 135, 125, 30 }, null, ref spinner_001_value, 0, 100, spinner_edit_mode); + if (res == 1) { + spinner_edit_mode = !spinner_edit_mode; + } + // Value box + res = gui_value_box ({ 25, 175, 125, 30 }, null, ref value_box_002_value, 0, 100, value_box_edit_mode); + if (res == 1) { + value_box_edit_mode = !value_box_edit_mode; + } + + // Text box + gui_set_style (Control.TEXT_BOX, ControlProperty.TEXT_ALIGNMENT, (int) TextAlignment.LEFT); + res = gui_text_box ({ 25, 215, 125, 30 }, text_box_text, 64, text_box_edit_mode); + if (res == 1) { + text_box_edit_mode = !text_box_edit_mode; + } + + // Button + gui_set_style (Control.TEXT_BOX, ControlProperty.TEXT_ALIGNMENT, (int) TextAlignment.CENTER); + res = gui_button ({ 25, 255, 125, 30 }, gui_icon_text (IconName.FILE_SAVE, "Save File")); + if (res == 1) { + show_text_input_box = true; + } + + // Button states + gui_group_box ({ 25, 310, 125, 150 }, "STATES"); + //lock (); + gui_set_state (State.NORMAL); + gui_button ({ 30, 320, 115, 30 }, "NORMAL"); + gui_set_state (State.FOCUSED); + gui_button ({ 30, 355, 115, 30 }, "FOCUSED"); + gui_set_state (State.PRESSED); + gui_button ({ 30, 390, 115, 30 }, "#15#PRESSED"); + gui_set_state (State.DISABLED); + gui_button ({ 30, 425, 115, 30 }, "DISABLED"); + gui_set_state (State.NORMAL); + //unlock (); + + // Combo Box + gui_combo_box ({ 25, 480, 125, 30 }, + "default;Jungle;Lavanda;Dark;Bluish;Cyber;Terminal;Candy;" + + "Cherry;Ashes;Enefete;Sunny;Amber;Genesis", + ref visual_style_active); + + // NOTE: GuiDropdownBox must draw after any other control that can be covered on unfolding + if (dropdown_000_edit_mode || dropdown_001_edit_mode) { + gui_unlock (); + } + if (show_text_input_box) { + gui_lock (); // Stay locked + } + + // Dropdown box 001 + gui_set_style (Control.DROPDOWN_BOX, ControlProperty.TEXT_PADDING, 4); + gui_set_style (Control.DROPDOWN_BOX, ControlProperty.TEXT_ALIGNMENT, TextAlignment.LEFT); + res = gui_dropdown_box ({ 25, 65, 125, 30 }, + "#01#ONE;#02#TWO;#03#THREE;#04#FOUR", + ref dropdown_box_001_active, + dropdown_001_edit_mode); + if (res == 1) { + dropdown_001_edit_mode = !dropdown_001_edit_mode; + } + + // Dropdown box 000 + gui_set_style (Control.DROPDOWN_BOX, ControlProperty.TEXT_PADDING, 0); + gui_set_style (Control.DROPDOWN_BOX, ControlProperty.TEXT_ALIGNMENT, TextAlignment.CENTER); + res = gui_dropdown_box ({ 25, 25, 125, 30 }, + "ONE;TWO;THREE", + ref dropdown_box_000_active, + dropdown_000_edit_mode); + if (res == 1) { + dropdown_000_edit_mode = !dropdown_000_edit_mode; + } + + // Second GUI column + // List view + //gui_set_style (Control.LIST_VIEW, ControlProperty.LIST_ITEMS_BORDER_NORMAL, 1); + gui_list_view ({165, 25, 140, 124}, + "Charmander;Bulbasaur;#18#Squirtel;Pikachu;Eevee;Pidgey", + ref list_view_scroll_index, + ref list_view_active); + // List view extended + gui_list_view_ext ({ 165, 162, 140, 184 }, + list_view_ext_list, + ref list_view_ext_scroll_index, + ref list_view_ext_active, ref list_view_ext_focus); + //gui_set_style (Control.LIST_VIEW, ControlProperty.LIST_ITEMS_BORDER_NORMAL, 0); + + // Toggle group + gui_toggle_group ({ 165, 360, 140, 24 }, + "#1#ONE\n#3#TWO\n#8#THREE\n#23#", + ref toggle_group_active); + + // Toggle Slider + gui_set_style (Control.SLIDER, (ControlProperty) SliderProperty.SLIDER_PADDING, 2); + gui_toggle_slider ({ 165, 480, 140, 30 }, "ON;OFF", ref toggle_slider_active); + gui_set_style (Control.SLIDER, (ControlProperty) SliderProperty.SLIDER_PADDING, 0); + + // Color bar + gui_color_bar_alpha ({ 320, 490, 200, 30 }, null, ref alpha_value); + + // Third GUI column + // Panel + gui_set_style (Control.DEFAULT, ControlProperty.TEXT_ALIGNMENT, TextAlignment.CENTER); + gui_panel ({ 320, 25, 225, 140 }, "Panel Info"); + // Color picker + gui_color_picker ({ 320, 185, 196, 192 }, null, ref color_picker_value); + + // Slider + gui_slider ({ 355, 400, 165, 20 }, + "TEST", + text_format ("%2.2f", slider_value), + ref slider_value, + -50, + 100); + // Slider bar + gui_slider_bar ({ 320, 430, 200, 20 }, + null, + text_format ("%i", (int)slider_bar_value), + ref slider_bar_value, + 0, + 100); + + // Progress bar + gui_progress_bar ({ 320, 460, 200, 20 }, + null, + text_format ("%i%%", (int) (progress_value * 100)), + ref progress_value, + 0.0f, + 1.0f); + + // Scroll panel + // NOTE: View rectangle could be used to perform some scissor test + Rectangle view = { 0 }; + gui_scroll_panel ({ 560, 25, 102, 354 }, + null, + { 560, 25, 300, 1200 }, + ref view_scroll, + ref view); + + Vector2 mouse_cell = { 0 }; + gui_grid ({ 560, 25 + 180 + 195, 100, 120 }, null, 20, 3, ref mouse_cell); + + gui_set_style (Control.DEFAULT, + (ControlProperty) DefaultProperty.TEXT_ALIGNMENT_VERTICAL, + TextAlignmentVertical.TOP); + gui_set_style (Control.DEFAULT, + (ControlProperty) DefaultProperty.TEXT_WRAP_MODE, + TextWrapMode.WORD); + res = gui_text_box ({ 678, 25, 258, 492 }, text_box_multi_text, 1024, text_box_multi_edit_mode); + if (res == 1) { + text_box_multi_edit_mode = !text_box_multi_edit_mode; + } + gui_set_style (Control.DEFAULT, + (ControlProperty) DefaultProperty.TEXT_ALIGNMENT_VERTICAL, + TextAlignmentVertical.MIDDLE); + gui_set_style (Control.DEFAULT, + (ControlProperty) DefaultProperty.TEXT_WRAP_MODE, + TextWrapMode.NONE); + + gui_set_style (Control.DEFAULT, ControlProperty.TEXT_ALIGNMENT, TextAlignment.LEFT); + gui_status_bar ({ 0, (float) get_screen_height () - 20, (float) get_screen_width (), 20 }, + status_bar_text); + gui_set_style (Control.DEFAULT, ControlProperty.TEXT_ALIGNMENT, TextAlignment.CENTER); + + // Elements outside columns + if (show_message_box) { + draw_rectangle (0, 0, get_screen_width (), get_screen_height (), color_alpha (RAYWHITE, 0.8f)); + Rectangle msg_box_rect = { (float) get_screen_width () / 2 - 125, + (float) get_screen_height () / 2 - 50, + 250, + 100 }; + int result = gui_message_box (msg_box_rect, + gui_icon_text (IconName.EXIT, "Close Window"), + "Do you really want to exit?", + "Yes;No"); + if ((result == 0) || (result == 2)) { + show_message_box = false; + } else if (result == 1) { + exit_window = true; + } + } + + // Text input box + if (show_text_input_box) { + gui_unlock (); + + draw_rectangle (0, 0, get_screen_width (), get_screen_height (), color_alpha (RAYWHITE, 0.8f)); + Rectangle input_box_rect = { (float) get_screen_width () / 2 - 125, + (float) get_screen_height () / 2 - 50, + 250, + 150 }; + int result = gui_text_input_box (input_box_rect, + gui_icon_text (IconName.FILE_SAVE, "Save file as:"), + "Introduce output file name:", + "Ok;Cancel", + text_input, + 255, null); + + if (result == 1) { + text_input_file_name = text_input; + if (is_file_name_valid (text_input_file_name)) { + status_bar_text = "(Dummy message) File saved as: " + text_input_file_name; + } else { + status_bar_text = "(Dummy message) Couldn't save file: "; + } + text_input = ""; + } + + if ((result == 0) || (result == 1) || (result == 2)) { + show_text_input_box = false; + text_input = ""; + } + + } + } + end_drawing (); + } + + return 0; +} diff --git a/examples/RayGui/ControlsTestSuite/meson.build b/examples/RayGui/ControlsTestSuite/meson.build new file mode 100644 index 0000000..691fee2 --- /dev/null +++ b/examples/RayGui/ControlsTestSuite/meson.build @@ -0,0 +1,5 @@ +executable ( + 'raygui-controls-test-suite', + 'Main.vala', + dependencies: project_dependency +) diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000..d4874aa --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,5 @@ +subdir('Core/Camera3D') +subdir('Core/BasicWindow') +subdir('Core/SmoothPixelPerfect') +subdir('Physac/Demo') +subdir('RayGui/ControlsTestSuite') diff --git a/include/physac.h b/include/physac.h new file mode 100644 index 0000000..3ab427a --- /dev/null +++ b/include/physac.h @@ -0,0 +1,1987 @@ +/********************************************************************************************** +* +* Physac v1.1 - 2D Physics library for videogames +* +* DESCRIPTION: +* +* Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop +* to simulate physics. A physics step contains the following phases: get collision information, +* apply dynamics, collision solving and position correction. It uses a very simple struct for physic +* bodies with a position vector to be used in any 3D rendering API. +* +* CONFIGURATION: +* +* #define PHYSAC_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. +* +* #define PHYSAC_DEBUG +* Show debug traces log messages about physic bodies creation/destruction, physic system errors, +* some calculations results and NULL reference exceptions. +* +* #define PHYSAC_AVOID_TIMMING_SYSTEM +* Disables internal timming system, used by UpdatePhysics() to launch timmed physic steps, +* it allows just running UpdatePhysics() automatically on a separate thread at a desired time step. +* In case physics steps update needs to be controlled by user with a custom timming mechanism, +* just define this flag and the internal timming mechanism will be avoided, in that case, +* timming libraries are neither required by the module. +* +* #define PHYSAC_MALLOC() +* #define PHYSAC_CALLOC() +* #define PHYSAC_FREE() +* You can define your own malloc/free implementation replacing stdlib.h malloc()/free() functions. +* Otherwise it will include stdlib.h and use the C standard library malloc()/free() function. +* +* COMPILATION: +* +* Use the following code to compile with GCC: +* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static -lraylib -lopengl32 -lgdi32 -lwinmm -std=c99 +* +* VERSIONS HISTORY: +* 1.1 (20-Jan-2021) @raysan5: Library general revision +* Removed threading system (up to the user) +* Support MSVC C++ compilation using CLITERAL() +* Review DEBUG mechanism for TRACELOG() and all TRACELOG() messages +* Review internal variables/functions naming for consistency +* Allow option to avoid internal timming system, to allow app manage the steps +* 1.0 (12-Jun-2017) First release of the library +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2016-2022 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#if !defined(PHYSAC_H) +#define PHYSAC_H + +// Function specifiers in case library is build/used as a shared library (Windows) +// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll +#if defined(_WIN32) + #if defined(BUILD_LIBTYPE_SHARED) + #define PHYSACDEF __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) + #elif defined(USE_LIBTYPE_SHARED) + #define PHYSACDEF __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) + #endif +#endif + +#ifndef PHYSACDEF + #define PHYSACDEF // We are building or using physac as a static library +#endif + +// Allow custom memory allocators +#ifndef PHYSAC_MALLOC + #define PHYSAC_MALLOC(size) malloc(size) +#endif +#ifndef PHYSAC_CALLOC + #define PHYSAC_CALLOC(size, n) calloc(size, n) +#endif +#ifndef PHYSAC_FREE + #define PHYSAC_FREE(ptr) free(ptr) +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define PHYSAC_MAX_BODIES 64 // Maximum number of physic bodies supported +#define PHYSAC_MAX_MANIFOLDS 4096 // Maximum number of physic bodies interactions (64x64) +#define PHYSAC_MAX_VERTICES 24 // Maximum number of vertex for polygons shapes +#define PHYSAC_DEFAULT_CIRCLE_VERTICES 24 // Default number of vertices for circle shapes + +#define PHYSAC_COLLISION_ITERATIONS 100 +#define PHYSAC_PENETRATION_ALLOWANCE 0.05f +#define PHYSAC_PENETRATION_CORRECTION 0.4f + +#define PHYSAC_PI 3.14159265358979323846f +#define PHYSAC_DEG2RAD (PHYSAC_PI/180.0f) + +//---------------------------------------------------------------------------------- +// Data Types Structure Definition +//---------------------------------------------------------------------------------- +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L + #include +#endif + +typedef enum PhysicsShapeType { PHYSICS_CIRCLE = 0, PHYSICS_POLYGON } PhysicsShapeType; + +// Previously defined to be used in PhysicsShape struct as circular dependencies +typedef struct PhysicsBodyData *PhysicsBody; + +#if !defined(RL_VECTOR2_TYPE) +// Vector2 type +typedef struct Vector2 { + float x; + float y; +} Vector2; +#endif + +// Matrix2x2 type (used for polygon shape rotation matrix) +typedef struct Matrix2x2 { + float m00; + float m01; + float m10; + float m11; +} Matrix2x2; + +typedef struct PhysicsVertexData { + unsigned int vertexCount; // Vertex count (positions and normals) + Vector2 positions[PHYSAC_MAX_VERTICES]; // Vertex positions vectors + Vector2 normals[PHYSAC_MAX_VERTICES]; // Vertex normals vectors +} PhysicsVertexData; + +typedef struct PhysicsShape { + PhysicsShapeType type; // Shape type (circle or polygon) + PhysicsBody body; // Shape physics body data pointer + PhysicsVertexData vertexData; // Shape vertices data (used for polygon shapes) + float radius; // Shape radius (used for circle shapes) + Matrix2x2 transform; // Vertices transform matrix 2x2 +} PhysicsShape; + +typedef struct PhysicsBodyData { + unsigned int id; // Unique identifier + bool enabled; // Enabled dynamics state (collisions are calculated anyway) + Vector2 position; // Physics body shape pivot + Vector2 velocity; // Current linear velocity applied to position + Vector2 force; // Current linear force (reset to 0 every step) + float angularVelocity; // Current angular velocity applied to orient + float torque; // Current angular force (reset to 0 every step) + float orient; // Rotation in radians + float inertia; // Moment of inertia + float inverseInertia; // Inverse value of inertia + float mass; // Physics body mass + float inverseMass; // Inverse value of mass + float staticFriction; // Friction when the body has not movement (0 to 1) + float dynamicFriction; // Friction when the body has movement (0 to 1) + float restitution; // Restitution coefficient of the body (0 to 1) + bool useGravity; // Apply gravity force to dynamics + bool isGrounded; // Physics grounded on other body state + bool freezeOrient; // Physics rotation constraint + PhysicsShape shape; // Physics body shape information (type, radius, vertices, transform) +} PhysicsBodyData; + +typedef struct PhysicsManifoldData { + unsigned int id; // Unique identifier + PhysicsBody bodyA; // Manifold first physics body reference + PhysicsBody bodyB; // Manifold second physics body reference + float penetration; // Depth of penetration from collision + Vector2 normal; // Normal direction vector from 'a' to 'b' + Vector2 contacts[2]; // Points of contact during collision + unsigned int contactsCount; // Current collision number of contacts + float restitution; // Mixed restitution during collision + float dynamicFriction; // Mixed dynamic friction during collision + float staticFriction; // Mixed static friction during collision +} PhysicsManifoldData, *PhysicsManifold; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif +// Physics system management +PHYSACDEF void InitPhysics(void); // Initializes physics system +PHYSACDEF void UpdatePhysics(void); // Update physics system +PHYSACDEF void ResetPhysics(void); // Reset physics system (global variables) +PHYSACDEF void ClosePhysics(void); // Close physics system and unload used memory +PHYSACDEF void SetPhysicsTimeStep(double delta); // Sets physics fixed time step in milliseconds. 1.666666 by default +PHYSACDEF void SetPhysicsGravity(float x, float y); // Sets physics global gravity force + +// Physic body creation/destroy +PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density); // Creates a new circle physics body with generic parameters +PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density); // Creates a new rectangle physics body with generic parameters +PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density); // Creates a new polygon physics body with generic parameters +PHYSACDEF void DestroyPhysicsBody(PhysicsBody body); // Destroy a physics body + +// Physic body forces +PHYSACDEF void PhysicsAddForce(PhysicsBody body, Vector2 force); // Adds a force to a physics body +PHYSACDEF void PhysicsAddTorque(PhysicsBody body, float amount); // Adds an angular force to a physics body +PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force); // Shatters a polygon shape physics body to little physics bodies with explosion force +PHYSACDEF void SetPhysicsBodyRotation(PhysicsBody body, float radians); // Sets physics body shape transform based on radians parameter + +// Query physics info +PHYSACDEF PhysicsBody GetPhysicsBody(int index); // Returns a physics body of the bodies pool at a specific index +PHYSACDEF int GetPhysicsBodiesCount(void); // Returns the current amount of created physics bodies +PHYSACDEF int GetPhysicsShapeType(int index); // Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) +PHYSACDEF int GetPhysicsShapeVerticesCount(int index); // Returns the amount of vertices of a physics body shape +PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex); // Returns transformed position of a body shape (body position + vertex transformed position) +#if defined(__cplusplus) +} +#endif + +#endif // PHYSAC_H + +/*********************************************************************************** +* +* PHYSAC IMPLEMENTATION +* +************************************************************************************/ + +#if defined(PHYSAC_IMPLEMENTATION) + +// Support TRACELOG macros +#if defined(PHYSAC_DEBUG) + #include // Required for: printf() + #define TRACELOG(...) printf(__VA_ARGS__) +#else + #define TRACELOG(...) (void)0; +#endif + +#include // Required for: malloc(), calloc(), free() +#include // Required for: cosf(), sinf(), fabs(), sqrtf() + +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) + // Time management functionality + #include // Required for: time(), clock_gettime() + #if defined(_WIN32) + #if defined(__cplusplus) + extern "C" { // Prevents name mangling of functions + #endif + // Functions required to query time on Windows + int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); + int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); + #if defined(__cplusplus) + } + #endif + #endif + #if defined(__linux__) || defined(__FreeBSD__) + #if _POSIX_C_SOURCE < 199309L + #undef _POSIX_C_SOURCE + #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. + #endif + #include // Required for: timespec + #endif + #if defined(__APPLE__) // macOS also defines __MACH__ + #include // Required for: mach_absolute_time() + #endif +#endif + +// NOTE: MSVC C++ compiler does not support compound literals (C99 feature) +// Plain structures in C++ (without constructors) can be initialized from { } initializers. +#if defined(__cplusplus) + #define CLITERAL(type) type +#else + #define CLITERAL(type) (type) +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define PHYSAC_MIN(a,b) (((a)<(b))?(a):(b)) +#define PHYSAC_MAX(a,b) (((a)>(b))?(a):(b)) +#define PHYSAC_FLT_MAX 3.402823466e+38f +#define PHYSAC_EPSILON 0.000001f +#define PHYSAC_K 1.0f/3.0f +#define PHYSAC_VECTOR_ZERO CLITERAL(Vector2){ 0.0f, 0.0f } + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static double deltaTime = 1.0/60.0/10.0 * 1000; // Delta time in milliseconds used for physics steps + +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) +// Time measure variables +static double baseClockTicks = 0.0; // Offset clock ticks for MONOTONIC clock +static unsigned long long int frequency = 0; // Hi-res clock frequency +static double startTime = 0.0; // Start time in milliseconds +static double currentTime = 0.0; // Current time in milliseconds +#endif + +// Physics system configuration +static PhysicsBody bodies[PHYSAC_MAX_BODIES]; // Physics bodies pointers array +static unsigned int physicsBodiesCount = 0; // Physics world current bodies counter +static PhysicsManifold contacts[PHYSAC_MAX_MANIFOLDS]; // Physics bodies pointers array +static unsigned int physicsManifoldsCount = 0; // Physics world current manifolds counter + +static Vector2 gravityForce = { 0.0f, 9.81f }; // Physics world gravity force + +// Utilities variables +static unsigned int usedMemory = 0; // Total allocated dynamic memory + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) +// Timming measure functions +static void InitTimerHiRes(void); // Initializes hi-resolution MONOTONIC timer +static unsigned long long int GetClockTicks(void); // Get hi-res MONOTONIC time measure in mseconds +static double GetCurrentTime(void); // Get current time measure in milliseconds +#endif + +static void UpdatePhysicsStep(void); // Update physics step (dynamics, collisions and position corrections) + +static int FindAvailableBodyIndex(); // Finds a valid index for a new physics body initialization +static int FindAvailableManifoldIndex(); // Finds a valid index for a new manifold initialization +static PhysicsVertexData CreateDefaultPolygon(float radius, int sides); // Creates a random polygon shape with max vertex distance from polygon pivot +static PhysicsVertexData CreateRectanglePolygon(Vector2 pos, Vector2 size); // Creates a rectangle polygon shape based on a min and max positions + +static void InitializePhysicsManifolds(PhysicsManifold manifold); // Initializes physics manifolds to solve collisions +static PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b); // Creates a new physics manifold to solve collision +static void DestroyPhysicsManifold(PhysicsManifold manifold); // Unitializes and destroys a physics manifold + +static void SolvePhysicsManifold(PhysicsManifold manifold); // Solves a created physics manifold between two physics bodies +static void SolveCircleToCircle(PhysicsManifold manifold); // Solves collision between two circle shape physics bodies +static void SolveCircleToPolygon(PhysicsManifold manifold); // Solves collision between a circle to a polygon shape physics bodies +static void SolvePolygonToCircle(PhysicsManifold manifold); // Solves collision between a polygon to a circle shape physics bodies +static void SolvePolygonToPolygon(PhysicsManifold manifold); // Solves collision between two polygons shape physics bodies +static void IntegratePhysicsForces(PhysicsBody body); // Integrates physics forces into velocity +static void IntegratePhysicsVelocity(PhysicsBody body); // Integrates physics velocity into position and forces +static void IntegratePhysicsImpulses(PhysicsManifold manifold); // Integrates physics collisions impulses to solve collisions +static void CorrectPhysicsPositions(PhysicsManifold manifold); // Corrects physics bodies positions based on manifolds collision information +static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, PhysicsShape inc, int index); // Finds two polygon shapes incident face +static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB); // Finds polygon shapes axis least penetration + +// Math required functions +static Vector2 MathVector2Product(Vector2 vector, float value); // Returns the product of a vector and a value +static float MathVector2CrossProduct(Vector2 v1, Vector2 v2); // Returns the cross product of two vectors +static float MathVector2SqrLen(Vector2 vector); // Returns the len square root of a vector +static float MathVector2DotProduct(Vector2 v1, Vector2 v2); // Returns the dot product of two vectors +static inline float MathVector2SqrDistance(Vector2 v1, Vector2 v2); // Returns the square root of distance between two vectors +static void MathVector2Normalize(Vector2 *vector); // Returns the normalized values of a vector +static Vector2 MathVector2Add(Vector2 v1, Vector2 v2); // Returns the sum of two given vectors +static Vector2 MathVector2Subtract(Vector2 v1, Vector2 v2); // Returns the subtract of two given vectors +static Matrix2x2 MathMatFromRadians(float radians); // Returns a matrix 2x2 from a given radians value +static inline Matrix2x2 MathMatTranspose(Matrix2x2 matrix); // Returns the transpose of a given matrix 2x2 +static inline Vector2 MathMatVector2Product(Matrix2x2 matrix, Vector2 vector); // Returns product between matrix 2x2 and vector +static int MathVector2Clip(Vector2 normal, Vector2 *faceA, Vector2 *faceB, float clip); // Returns clipping value based on a normal and two faces +static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3); // Returns the barycenter of a triangle given by 3 points + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Initializes physics values, pointers and creates physics loop thread +void InitPhysics(void) +{ +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) + // Initialize high resolution timer + InitTimerHiRes(); +#endif + + TRACELOG("[PHYSAC] Physics module initialized successfully\n"); +} + +// Sets physics global gravity force +void SetPhysicsGravity(float x, float y) +{ + gravityForce.x = x; + gravityForce.y = y; +} + +// Creates a new circle physics body with generic parameters +PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density) +{ + PhysicsBody body = CreatePhysicsBodyPolygon(pos, radius, PHYSAC_DEFAULT_CIRCLE_VERTICES, density); + return body; +} + +// Creates a new rectangle physics body with generic parameters +PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density) +{ + // NOTE: Make sure body data is initialized to 0 + PhysicsBody body = (PhysicsBody)PHYSAC_CALLOC(sizeof(PhysicsBodyData), 1); + usedMemory += sizeof(PhysicsBodyData); + + int id = FindAvailableBodyIndex(); + if (id != -1) + { + // Initialize new body with generic values + body->id = id; + body->enabled = true; + body->position = pos; + body->shape.type = PHYSICS_POLYGON; + body->shape.body = body; + body->shape.transform = MathMatFromRadians(0.0f); + body->shape.vertexData = CreateRectanglePolygon(pos, CLITERAL(Vector2){ width, height }); + + // Calculate centroid and moment of inertia + Vector2 center = { 0.0f, 0.0f }; + float area = 0.0f; + float inertia = 0.0f; + + for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) + { + // Triangle vertices, third vertex implied as (0, 0) + Vector2 p1 = body->shape.vertexData.positions[i]; + unsigned int nextIndex = (((i + 1) < body->shape.vertexData.vertexCount) ? (i + 1) : 0); + Vector2 p2 = body->shape.vertexData.positions[nextIndex]; + + float D = MathVector2CrossProduct(p1, p2); + float triangleArea = D/2; + + area += triangleArea; + + // Use area to weight the centroid average, not just vertex position + center.x += triangleArea*PHYSAC_K*(p1.x + p2.x); + center.y += triangleArea*PHYSAC_K*(p1.y + p2.y); + + float intx2 = p1.x*p1.x + p2.x*p1.x + p2.x*p2.x; + float inty2 = p1.y*p1.y + p2.y*p1.y + p2.y*p2.y; + inertia += (0.25f*PHYSAC_K*D)*(intx2 + inty2); + } + + center.x *= 1.0f/area; + center.y *= 1.0f/area; + + // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space) + // Note: this is not really necessary + for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) + { + body->shape.vertexData.positions[i].x -= center.x; + body->shape.vertexData.positions[i].y -= center.y; + } + + body->mass = density*area; + body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f); + body->inertia = density*inertia; + body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f); + body->staticFriction = 0.4f; + body->dynamicFriction = 0.2f; + body->restitution = 0.0f; + body->useGravity = true; + body->isGrounded = false; + body->freezeOrient = false; + + // Add new body to bodies pointers array and update bodies count + bodies[physicsBodiesCount] = body; + physicsBodiesCount++; + + TRACELOG("[PHYSAC] Physic body created successfully (id: %i)\n", body->id); + } + else TRACELOG("[PHYSAC] Physic body could not be created, PHYSAC_MAX_BODIES reached\n"); + + return body; +} + +// Creates a new polygon physics body with generic parameters +PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density) +{ + PhysicsBody body = (PhysicsBody)PHYSAC_MALLOC(sizeof(PhysicsBodyData)); + usedMemory += sizeof(PhysicsBodyData); + + int id = FindAvailableBodyIndex(); + if (id != -1) + { + // Initialize new body with generic values + body->id = id; + body->enabled = true; + body->position = pos; + body->velocity = PHYSAC_VECTOR_ZERO; + body->force = PHYSAC_VECTOR_ZERO; + body->angularVelocity = 0.0f; + body->torque = 0.0f; + body->orient = 0.0f; + body->shape.type = PHYSICS_POLYGON; + body->shape.body = body; + body->shape.transform = MathMatFromRadians(0.0f); + body->shape.vertexData = CreateDefaultPolygon(radius, sides); + + // Calculate centroid and moment of inertia + Vector2 center = { 0.0f, 0.0f }; + float area = 0.0f; + float inertia = 0.0f; + + for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) + { + // Triangle vertices, third vertex implied as (0, 0) + Vector2 position1 = body->shape.vertexData.positions[i]; + unsigned int nextIndex = (((i + 1) < body->shape.vertexData.vertexCount) ? (i + 1) : 0); + Vector2 position2 = body->shape.vertexData.positions[nextIndex]; + + float cross = MathVector2CrossProduct(position1, position2); + float triangleArea = cross/2; + + area += triangleArea; + + // Use area to weight the centroid average, not just vertex position + center.x += triangleArea*PHYSAC_K*(position1.x + position2.x); + center.y += triangleArea*PHYSAC_K*(position1.y + position2.y); + + float intx2 = position1.x*position1.x + position2.x*position1.x + position2.x*position2.x; + float inty2 = position1.y*position1.y + position2.y*position1.y + position2.y*position2.y; + inertia += (0.25f*PHYSAC_K*cross)*(intx2 + inty2); + } + + center.x *= 1.0f/area; + center.y *= 1.0f/area; + + // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space) + // Note: this is not really necessary + for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) + { + body->shape.vertexData.positions[i].x -= center.x; + body->shape.vertexData.positions[i].y -= center.y; + } + + body->mass = density*area; + body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f); + body->inertia = density*inertia; + body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f); + body->staticFriction = 0.4f; + body->dynamicFriction = 0.2f; + body->restitution = 0.0f; + body->useGravity = true; + body->isGrounded = false; + body->freezeOrient = false; + + // Add new body to bodies pointers array and update bodies count + bodies[physicsBodiesCount] = body; + physicsBodiesCount++; + + TRACELOG("[PHYSAC] Physic body created successfully (id: %i)\n", body->id); + } + else TRACELOG("[PHYSAC] Physics body could not be created, PHYSAC_MAX_BODIES reached\n"); + + return body; +} + +// Adds a force to a physics body +void PhysicsAddForce(PhysicsBody body, Vector2 force) +{ + if (body != NULL) body->force = MathVector2Add(body->force, force); +} + +// Adds an angular force to a physics body +void PhysicsAddTorque(PhysicsBody body, float amount) +{ + if (body != NULL) body->torque += amount; +} + +// Shatters a polygon shape physics body to little physics bodies with explosion force +void PhysicsShatter(PhysicsBody body, Vector2 position, float force) +{ + if (body != NULL) + { + if (body->shape.type == PHYSICS_POLYGON) + { + PhysicsVertexData vertexData = body->shape.vertexData; + bool collision = false; + + for (unsigned int i = 0; i < vertexData.vertexCount; i++) + { + Vector2 positionA = body->position; + Vector2 positionB = MathMatVector2Product(body->shape.transform, MathVector2Add(body->position, vertexData.positions[i])); + unsigned int nextIndex = (((i + 1) < vertexData.vertexCount) ? (i + 1) : 0); + Vector2 positionC = MathMatVector2Product(body->shape.transform, MathVector2Add(body->position, vertexData.positions[nextIndex])); + + // Check collision between each triangle + float alpha = ((positionB.y - positionC.y)*(position.x - positionC.x) + (positionC.x - positionB.x)*(position.y - positionC.y))/ + ((positionB.y - positionC.y)*(positionA.x - positionC.x) + (positionC.x - positionB.x)*(positionA.y - positionC.y)); + + float beta = ((positionC.y - positionA.y)*(position.x - positionC.x) + (positionA.x - positionC.x)*(position.y - positionC.y))/ + ((positionB.y - positionC.y)*(positionA.x - positionC.x) + (positionC.x - positionB.x)*(positionA.y - positionC.y)); + + float gamma = 1.0f - alpha - beta; + + if ((alpha > 0.0f) && (beta > 0.0f) & (gamma > 0.0f)) + { + collision = true; + break; + } + } + + if (collision) + { + int count = vertexData.vertexCount; + Vector2 bodyPos = body->position; + Vector2 *vertices = (Vector2 *)PHYSAC_MALLOC(sizeof(Vector2)*count); + Matrix2x2 trans = body->shape.transform; + for (int i = 0; i < count; i++) vertices[i] = vertexData.positions[i]; + + // Destroy shattered physics body + DestroyPhysicsBody(body); + + for (int i = 0; i < count; i++) + { + int nextIndex = (((i + 1) < count) ? (i + 1) : 0); + Vector2 center = MathTriangleBarycenter(vertices[i], vertices[nextIndex], PHYSAC_VECTOR_ZERO); + center = MathVector2Add(bodyPos, center); + Vector2 offset = MathVector2Subtract(center, bodyPos); + + PhysicsBody body = CreatePhysicsBodyPolygon(center, 10, 3, 10); // Create polygon physics body with relevant values + + PhysicsVertexData vertexData = { 0 }; + vertexData.vertexCount = 3; + + vertexData.positions[0] = MathVector2Subtract(vertices[i], offset); + vertexData.positions[1] = MathVector2Subtract(vertices[nextIndex], offset); + vertexData.positions[2] = MathVector2Subtract(position, center); + + // Separate vertices to avoid unnecessary physics collisions + vertexData.positions[0].x *= 0.95f; + vertexData.positions[0].y *= 0.95f; + vertexData.positions[1].x *= 0.95f; + vertexData.positions[1].y *= 0.95f; + vertexData.positions[2].x *= 0.95f; + vertexData.positions[2].y *= 0.95f; + + // Calculate polygon faces normals + for (unsigned int j = 0; j < vertexData.vertexCount; j++) + { + unsigned int nextVertex = (((j + 1) < vertexData.vertexCount) ? (j + 1) : 0); + Vector2 face = MathVector2Subtract(vertexData.positions[nextVertex], vertexData.positions[j]); + + vertexData.normals[j] = CLITERAL(Vector2){ face.y, -face.x }; + MathVector2Normalize(&vertexData.normals[j]); + } + + // Apply computed vertex data to new physics body shape + body->shape.vertexData = vertexData; + body->shape.transform = trans; + + // Calculate centroid and moment of inertia + center = PHYSAC_VECTOR_ZERO; + float area = 0.0f; + float inertia = 0.0f; + + for (unsigned int j = 0; j < body->shape.vertexData.vertexCount; j++) + { + // Triangle vertices, third vertex implied as (0, 0) + Vector2 p1 = body->shape.vertexData.positions[j]; + unsigned int nextVertex = (((j + 1) < body->shape.vertexData.vertexCount) ? (j + 1) : 0); + Vector2 p2 = body->shape.vertexData.positions[nextVertex]; + + float D = MathVector2CrossProduct(p1, p2); + float triangleArea = D/2; + + area += triangleArea; + + // Use area to weight the centroid average, not just vertex position + center.x += triangleArea*PHYSAC_K*(p1.x + p2.x); + center.y += triangleArea*PHYSAC_K*(p1.y + p2.y); + + float intx2 = p1.x*p1.x + p2.x*p1.x + p2.x*p2.x; + float inty2 = p1.y*p1.y + p2.y*p1.y + p2.y*p2.y; + inertia += (0.25f*PHYSAC_K*D)*(intx2 + inty2); + } + + center.x *= 1.0f/area; + center.y *= 1.0f/area; + + body->mass = area; + body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f); + body->inertia = inertia; + body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f); + + // Calculate explosion force direction + Vector2 pointA = body->position; + Vector2 pointB = MathVector2Subtract(vertexData.positions[1], vertexData.positions[0]); + pointB.x /= 2.0f; + pointB.y /= 2.0f; + Vector2 forceDirection = MathVector2Subtract(MathVector2Add(pointA, MathVector2Add(vertexData.positions[0], pointB)), body->position); + MathVector2Normalize(&forceDirection); + forceDirection.x *= force; + forceDirection.y *= force; + + // Apply force to new physics body + PhysicsAddForce(body, forceDirection); + } + + PHYSAC_FREE(vertices); + } + } + } + else TRACELOG("[PHYSAC] WARNING: PhysicsShatter: NULL physic body\n"); +} + +// Returns the current amount of created physics bodies +int GetPhysicsBodiesCount(void) +{ + return physicsBodiesCount; +} + +// Returns a physics body of the bodies pool at a specific index +PhysicsBody GetPhysicsBody(int index) +{ + PhysicsBody body = NULL; + + if (index < (int)physicsBodiesCount) + { + body = bodies[index]; + + if (body == NULL) TRACELOG("[PHYSAC] WARNING: GetPhysicsBody: NULL physic body\n"); + } + else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); + + return body; +} + +// Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) +int GetPhysicsShapeType(int index) +{ + int result = -1; + + if (index < (int)physicsBodiesCount) + { + PhysicsBody body = bodies[index]; + + if (body != NULL) result = body->shape.type; + else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeType: NULL physic body\n"); + } + else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); + + return result; +} + +// Returns the amount of vertices of a physics body shape +int GetPhysicsShapeVerticesCount(int index) +{ + int result = 0; + + if (index < (int)physicsBodiesCount) + { + PhysicsBody body = bodies[index]; + + if (body != NULL) + { + switch (body->shape.type) + { + case PHYSICS_CIRCLE: result = PHYSAC_DEFAULT_CIRCLE_VERTICES; break; + case PHYSICS_POLYGON: result = body->shape.vertexData.vertexCount; break; + default: break; + } + } + else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeVerticesCount: NULL physic body\n"); + } + else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); + + return result; +} + +// Returns transformed position of a body shape (body position + vertex transformed position) +Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex) +{ + Vector2 position = { 0.0f, 0.0f }; + + if (body != NULL) + { + switch (body->shape.type) + { + case PHYSICS_CIRCLE: + { + position.x = body->position.x + cosf(360.0f/PHYSAC_DEFAULT_CIRCLE_VERTICES*vertex*PHYSAC_DEG2RAD)*body->shape.radius; + position.y = body->position.y + sinf(360.0f/PHYSAC_DEFAULT_CIRCLE_VERTICES*vertex*PHYSAC_DEG2RAD)*body->shape.radius; + } break; + case PHYSICS_POLYGON: + { + PhysicsVertexData vertexData = body->shape.vertexData; + position = MathVector2Add(body->position, MathMatVector2Product(body->shape.transform, vertexData.positions[vertex])); + } break; + default: break; + } + } + else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeVertex: NULL physic body\n"); + + return position; +} + +// Sets physics body shape transform based on radians parameter +void SetPhysicsBodyRotation(PhysicsBody body, float radians) +{ + if (body != NULL) + { + body->orient = radians; + + if (body->shape.type == PHYSICS_POLYGON) body->shape.transform = MathMatFromRadians(radians); + } +} + +// Unitializes and destroys a physics body +void DestroyPhysicsBody(PhysicsBody body) +{ + if (body != NULL) + { + int id = body->id; + int index = -1; + + for (unsigned int i = 0; i < physicsBodiesCount; i++) + { + if (bodies[i]->id == id) + { + index = i; + break; + } + } + + if (index == -1) + { + TRACELOG("[PHYSAC] WARNING: Requested body (id: %i) can not be found\n", id); + return; // Prevent access to index -1 + } + + // Free body allocated memory + PHYSAC_FREE(body); + usedMemory -= sizeof(PhysicsBodyData); + bodies[index] = NULL; + + // Reorder physics bodies pointers array and its catched index + for (unsigned int i = index; i < physicsBodiesCount; i++) + { + if ((i + 1) < physicsBodiesCount) bodies[i] = bodies[i + 1]; + } + + // Update physics bodies count + physicsBodiesCount--; + + TRACELOG("[PHYSAC] Physic body destroyed successfully (id: %i)\n", id); + } + else TRACELOG("[PHYSAC] WARNING: DestroyPhysicsBody: NULL physic body\n"); +} + +// Destroys created physics bodies and manifolds and resets global values +void ResetPhysics(void) +{ + if (physicsBodiesCount > 0) + { + // Unitialize physics bodies dynamic memory allocations + for (int i = physicsBodiesCount - 1; i >= 0; i--) + { + PhysicsBody body = bodies[i]; + + if (body != NULL) + { + PHYSAC_FREE(body); + bodies[i] = NULL; + usedMemory -= sizeof(PhysicsBodyData); + } + } + + physicsBodiesCount = 0; + } + + if (physicsManifoldsCount > 0) + { + // Unitialize physics manifolds dynamic memory allocations + for (int i = physicsManifoldsCount - 1; i >= 0; i--) + { + PhysicsManifold manifold = contacts[i]; + + if (manifold != NULL) + { + PHYSAC_FREE(manifold); + contacts[i] = NULL; + usedMemory -= sizeof(PhysicsManifoldData); + } + } + + physicsManifoldsCount = 0; + } + + TRACELOG("[PHYSAC] Physics module reseted successfully\n"); +} + +// Unitializes physics pointers and exits physics loop thread +void ClosePhysics(void) +{ + // Unitialize physics manifolds dynamic memory allocations + if (physicsManifoldsCount > 0) + { + for (int i = physicsManifoldsCount - 1; i >= 0; i--) DestroyPhysicsManifold(contacts[i]); + } + + // Unitialize physics bodies dynamic memory allocations + if (physicsBodiesCount > 0) + { + for (int i = physicsBodiesCount - 1; i >= 0; i--) DestroyPhysicsBody(bodies[i]); + } + + // Trace log info + if ((physicsBodiesCount > 0) || (usedMemory != 0)) + { + TRACELOG("[PHYSAC] WARNING: Physics module closed with unallocated bodies (BODIES: %i, MEMORY: %i bytes)\n", physicsBodiesCount, usedMemory); + } + else if ((physicsManifoldsCount > 0) || (usedMemory != 0)) + { + TRACELOG("[PHYSAC] WARNING: Pysics module closed with unallocated manifolds (MANIFOLDS: %i, MEMORY: %i bytes)\n", physicsManifoldsCount, usedMemory); + } + else TRACELOG("[PHYSAC] Physics module closed successfully\n"); +} + +// Update physics system +// Physics steps are launched at a fixed time step if enabled +void UpdatePhysics(void) +{ +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) + static double deltaTimeAccumulator = 0.0; + + // Calculate current time (ms) + currentTime = GetCurrentTime(); + + // Calculate current delta time (ms) + const double delta = currentTime - startTime; + + // Store the time elapsed since the last frame began + deltaTimeAccumulator += delta; + + // Fixed time stepping loop + while (deltaTimeAccumulator >= deltaTime) + { + UpdatePhysicsStep(); + deltaTimeAccumulator -= deltaTime; + } + + // Record the starting of this frame + startTime = currentTime; +#else + UpdatePhysicsStep(); +#endif +} + +void SetPhysicsTimeStep(double delta) +{ + deltaTime = delta; +} + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- +#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) +// Initializes hi-resolution MONOTONIC timer +static void InitTimerHiRes(void) +{ +#if defined(_WIN32) + QueryPerformanceFrequency((unsigned long long int *) &frequency); +#endif + +#if defined(__EMSCRIPTEN__) || defined(__linux__) + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) frequency = 1000000000; +#endif + +#if defined(__APPLE__) + mach_timebase_info_data_t timebase; + mach_timebase_info(&timebase); + frequency = (timebase.denom*1e9)/timebase.numer; +#endif + + baseClockTicks = (double)GetClockTicks(); // Get MONOTONIC clock time offset + startTime = GetCurrentTime(); // Get current time in milliseconds +} + +// Get hi-res MONOTONIC time measure in clock ticks +static unsigned long long int GetClockTicks(void) +{ + unsigned long long int value = 0; + +#if defined(_WIN32) + QueryPerformanceCounter((unsigned long long int *) &value); +#endif + +#if defined(__linux__) + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + value = (unsigned long long int)now.tv_sec*(unsigned long long int)1000000000 + (unsigned long long int)now.tv_nsec; +#endif + +#if defined(__APPLE__) + value = mach_absolute_time(); +#endif + + return value; +} + +// Get current time in milliseconds +static double GetCurrentTime(void) +{ + return (double)(GetClockTicks() - baseClockTicks)/frequency*1000; +} +#endif // !PHYSAC_AVOID_TIMMING_SYSTEM + +// Update physics step (dynamics, collisions and position corrections) +static void UpdatePhysicsStep(void) +{ + // Clear previous generated collisions information + for (int i = (int)physicsManifoldsCount - 1; i >= 0; i--) + { + PhysicsManifold manifold = contacts[i]; + if (manifold != NULL) DestroyPhysicsManifold(manifold); + } + + // Reset physics bodies grounded state + for (unsigned int i = 0; i < physicsBodiesCount; i++) + { + PhysicsBody body = bodies[i]; + body->isGrounded = false; + } + + // Generate new collision information + for (unsigned int i = 0; i < physicsBodiesCount; i++) + { + PhysicsBody bodyA = bodies[i]; + + if (bodyA != NULL) + { + for (unsigned int j = i + 1; j < physicsBodiesCount; j++) + { + PhysicsBody bodyB = bodies[j]; + + if (bodyB != NULL) + { + if ((bodyA->inverseMass == 0) && (bodyB->inverseMass == 0)) continue; + + PhysicsManifold manifold = CreatePhysicsManifold(bodyA, bodyB); + SolvePhysicsManifold(manifold); + + if (manifold->contactsCount > 0) + { + // Create a new manifold with same information as previously solved manifold and add it to the manifolds pool last slot + PhysicsManifold manifold = CreatePhysicsManifold(bodyA, bodyB); + manifold->penetration = manifold->penetration; + manifold->normal = manifold->normal; + manifold->contacts[0] = manifold->contacts[0]; + manifold->contacts[1] = manifold->contacts[1]; + manifold->contactsCount = manifold->contactsCount; + manifold->restitution = manifold->restitution; + manifold->dynamicFriction = manifold->dynamicFriction; + manifold->staticFriction = manifold->staticFriction; + } + } + } + } + } + + // Integrate forces to physics bodies + for (unsigned int i = 0; i < physicsBodiesCount; i++) + { + PhysicsBody body = bodies[i]; + if (body != NULL) IntegratePhysicsForces(body); + } + + // Initialize physics manifolds to solve collisions + for (unsigned int i = 0; i < physicsManifoldsCount; i++) + { + PhysicsManifold manifold = contacts[i]; + if (manifold != NULL) InitializePhysicsManifolds(manifold); + } + + // Integrate physics collisions impulses to solve collisions + for (unsigned int i = 0; i < PHYSAC_COLLISION_ITERATIONS; i++) + { + for (unsigned int j = 0; j < physicsManifoldsCount; j++) + { + PhysicsManifold manifold = contacts[i]; + if (manifold != NULL) IntegratePhysicsImpulses(manifold); + } + } + + // Integrate velocity to physics bodies + for (unsigned int i = 0; i < physicsBodiesCount; i++) + { + PhysicsBody body = bodies[i]; + if (body != NULL) IntegratePhysicsVelocity(body); + } + + // Correct physics bodies positions based on manifolds collision information + for (unsigned int i = 0; i < physicsManifoldsCount; i++) + { + PhysicsManifold manifold = contacts[i]; + if (manifold != NULL) CorrectPhysicsPositions(manifold); + } + + // Clear physics bodies forces + for (unsigned int i = 0; i < physicsBodiesCount; i++) + { + PhysicsBody body = bodies[i]; + if (body != NULL) + { + body->force = PHYSAC_VECTOR_ZERO; + body->torque = 0.0f; + } + } +} + +// Finds a valid index for a new physics body initialization +static int FindAvailableBodyIndex() +{ + int index = -1; + for (int i = 0; i < PHYSAC_MAX_BODIES; i++) + { + int currentId = i; + + // Check if current id already exist in other physics body + for (unsigned int k = 0; k < physicsBodiesCount; k++) + { + if (bodies[k]->id == currentId) + { + currentId++; + break; + } + } + + // If it is not used, use it as new physics body id + if (currentId == (int)i) + { + index = (int)i; + break; + } + } + + return index; +} + +// Creates a default polygon shape with max vertex distance from polygon pivot +static PhysicsVertexData CreateDefaultPolygon(float radius, int sides) +{ + PhysicsVertexData data = { 0 }; + data.vertexCount = sides; + + // Calculate polygon vertices positions + for (unsigned int i = 0; i < data.vertexCount; i++) + { + data.positions[i].x = (float)cosf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius; + data.positions[i].y = (float)sinf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius; + } + + // Calculate polygon faces normals + for (int i = 0; i < (int)data.vertexCount; i++) + { + int nextIndex = (((i + 1) < sides) ? (i + 1) : 0); + Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]); + + data.normals[i] = CLITERAL(Vector2){ face.y, -face.x }; + MathVector2Normalize(&data.normals[i]); + } + + return data; +} + +// Creates a rectangle polygon shape based on a min and max positions +static PhysicsVertexData CreateRectanglePolygon(Vector2 pos, Vector2 size) +{ + PhysicsVertexData data = { 0 }; + data.vertexCount = 4; + + // Calculate polygon vertices positions + data.positions[0] = CLITERAL(Vector2){ pos.x + size.x/2, pos.y - size.y/2 }; + data.positions[1] = CLITERAL(Vector2){ pos.x + size.x/2, pos.y + size.y/2 }; + data.positions[2] = CLITERAL(Vector2){ pos.x - size.x/2, pos.y + size.y/2 }; + data.positions[3] = CLITERAL(Vector2){ pos.x - size.x/2, pos.y - size.y/2 }; + + // Calculate polygon faces normals + for (unsigned int i = 0; i < data.vertexCount; i++) + { + int nextIndex = (((i + 1) < data.vertexCount) ? (i + 1) : 0); + Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]); + + data.normals[i] = CLITERAL(Vector2){ face.y, -face.x }; + MathVector2Normalize(&data.normals[i]); + } + + return data; +} + +// Finds a valid index for a new manifold initialization +static int FindAvailableManifoldIndex() +{ + int index = -1; + for (int i = 0; i < PHYSAC_MAX_MANIFOLDS; i++) + { + int currentId = i; + + // Check if current id already exist in other physics body + for (unsigned int k = 0; k < physicsManifoldsCount; k++) + { + if (contacts[k]->id == currentId) + { + currentId++; + break; + } + } + + // If it is not used, use it as new physics body id + if (currentId == i) + { + index = i; + break; + } + } + + return index; +} + +// Creates a new physics manifold to solve collision +static PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b) +{ + PhysicsManifold manifold = (PhysicsManifold)PHYSAC_MALLOC(sizeof(PhysicsManifoldData)); + usedMemory += sizeof(PhysicsManifoldData); + + int id = FindAvailableManifoldIndex(); + if (id != -1) + { + // Initialize new manifold with generic values + manifold->id = id; + manifold->bodyA = a; + manifold->bodyB = b; + manifold->penetration = 0; + manifold->normal = PHYSAC_VECTOR_ZERO; + manifold->contacts[0] = PHYSAC_VECTOR_ZERO; + manifold->contacts[1] = PHYSAC_VECTOR_ZERO; + manifold->contactsCount = 0; + manifold->restitution = 0.0f; + manifold->dynamicFriction = 0.0f; + manifold->staticFriction = 0.0f; + + // Add new body to bodies pointers array and update bodies count + contacts[physicsManifoldsCount] = manifold; + physicsManifoldsCount++; + } + else TRACELOG("[PHYSAC] Physic manifold could not be created, PHYSAC_MAX_MANIFOLDS reached\n"); + + return manifold; +} + +// Unitializes and destroys a physics manifold +static void DestroyPhysicsManifold(PhysicsManifold manifold) +{ + if (manifold != NULL) + { + int id = manifold->id; + int index = -1; + + for (unsigned int i = 0; i < physicsManifoldsCount; i++) + { + if (contacts[i]->id == id) + { + index = i; + break; + } + } + + if (index == -1) return; // Prevent access to index -1 + + // Free manifold allocated memory + PHYSAC_FREE(manifold); + usedMemory -= sizeof(PhysicsManifoldData); + contacts[index] = NULL; + + // Reorder physics manifolds pointers array and its catched index + for (unsigned int i = index; i < physicsManifoldsCount; i++) + { + if ((i + 1) < physicsManifoldsCount) contacts[i] = contacts[i + 1]; + } + + // Update physics manifolds count + physicsManifoldsCount--; + } + else TRACELOG("[PHYSAC] WARNING: DestroyPhysicsManifold: NULL physic manifold\n"); +} + +// Solves a created physics manifold between two physics bodies +static void SolvePhysicsManifold(PhysicsManifold manifold) +{ + switch (manifold->bodyA->shape.type) + { + case PHYSICS_CIRCLE: + { + switch (manifold->bodyB->shape.type) + { + case PHYSICS_CIRCLE: SolveCircleToCircle(manifold); break; + case PHYSICS_POLYGON: SolveCircleToPolygon(manifold); break; + default: break; + } + } break; + case PHYSICS_POLYGON: + { + switch (manifold->bodyB->shape.type) + { + case PHYSICS_CIRCLE: SolvePolygonToCircle(manifold); break; + case PHYSICS_POLYGON: SolvePolygonToPolygon(manifold); break; + default: break; + } + } break; + default: break; + } + + // Update physics body grounded state if normal direction is down and grounded state is not set yet in previous manifolds + if (!manifold->bodyB->isGrounded) manifold->bodyB->isGrounded = (manifold->normal.y < 0); +} + +// Solves collision between two circle shape physics bodies +static void SolveCircleToCircle(PhysicsManifold manifold) +{ + PhysicsBody bodyA = manifold->bodyA; + PhysicsBody bodyB = manifold->bodyB; + + if ((bodyA == NULL) || (bodyB == NULL)) return; + + // Calculate translational vector, which is normal + Vector2 normal = MathVector2Subtract(bodyB->position, bodyA->position); + + float distSqr = MathVector2SqrLen(normal); + float radius = bodyA->shape.radius + bodyB->shape.radius; + + // Check if circles are not in contact + if (distSqr >= radius*radius) + { + manifold->contactsCount = 0; + return; + } + + float distance = sqrtf(distSqr); + manifold->contactsCount = 1; + + if (distance == 0.0f) + { + manifold->penetration = bodyA->shape.radius; + manifold->normal = CLITERAL(Vector2){ 1.0f, 0.0f }; + manifold->contacts[0] = bodyA->position; + } + else + { + manifold->penetration = radius - distance; + manifold->normal = CLITERAL(Vector2){ normal.x/distance, normal.y/distance }; // Faster than using MathVector2Normalize() due to sqrt is already performed + manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y }; + } + + // Update physics body grounded state if normal direction is down + if (!bodyA->isGrounded) bodyA->isGrounded = (manifold->normal.y < 0); +} + +// Solves collision between a circle to a polygon shape physics bodies +static void SolveCircleToPolygon(PhysicsManifold manifold) +{ + PhysicsBody bodyA = manifold->bodyA; + PhysicsBody bodyB = manifold->bodyB; + + if ((bodyA == NULL) || (bodyB == NULL)) return; + + manifold->contactsCount = 0; + + // Transform circle center to polygon transform space + Vector2 center = bodyA->position; + center = MathMatVector2Product(MathMatTranspose(bodyB->shape.transform), MathVector2Subtract(center, bodyB->position)); + + // Find edge with minimum penetration + // It is the same concept as using support points in SolvePolygonToPolygon + float separation = -PHYSAC_FLT_MAX; + int faceNormal = 0; + PhysicsVertexData vertexData = bodyB->shape.vertexData; + + for (unsigned int i = 0; i < vertexData.vertexCount; i++) + { + float currentSeparation = MathVector2DotProduct(vertexData.normals[i], MathVector2Subtract(center, vertexData.positions[i])); + + if (currentSeparation > bodyA->shape.radius) return; + + if (currentSeparation > separation) + { + separation = currentSeparation; + faceNormal = i; + } + } + + // Grab face's vertices + Vector2 v1 = vertexData.positions[faceNormal]; + int nextIndex = (((faceNormal + 1) < (int)vertexData.vertexCount) ? (faceNormal + 1) : 0); + Vector2 v2 = vertexData.positions[nextIndex]; + + // Check to see if center is within polygon + if (separation < PHYSAC_EPSILON) + { + manifold->contactsCount = 1; + Vector2 normal = MathMatVector2Product(bodyB->shape.transform, vertexData.normals[faceNormal]); + manifold->normal = CLITERAL(Vector2){ -normal.x, -normal.y }; + manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y }; + manifold->penetration = bodyA->shape.radius; + return; + } + + // Determine which voronoi region of the edge center of circle lies within + float dot1 = MathVector2DotProduct(MathVector2Subtract(center, v1), MathVector2Subtract(v2, v1)); + float dot2 = MathVector2DotProduct(MathVector2Subtract(center, v2), MathVector2Subtract(v1, v2)); + manifold->penetration = bodyA->shape.radius - separation; + + if (dot1 <= 0.0f) // Closest to v1 + { + if (MathVector2SqrDistance(center, v1) > bodyA->shape.radius*bodyA->shape.radius) return; + + manifold->contactsCount = 1; + Vector2 normal = MathVector2Subtract(v1, center); + normal = MathMatVector2Product(bodyB->shape.transform, normal); + MathVector2Normalize(&normal); + manifold->normal = normal; + v1 = MathMatVector2Product(bodyB->shape.transform, v1); + v1 = MathVector2Add(v1, bodyB->position); + manifold->contacts[0] = v1; + } + else if (dot2 <= 0.0f) // Closest to v2 + { + if (MathVector2SqrDistance(center, v2) > bodyA->shape.radius*bodyA->shape.radius) return; + + manifold->contactsCount = 1; + Vector2 normal = MathVector2Subtract(v2, center); + v2 = MathMatVector2Product(bodyB->shape.transform, v2); + v2 = MathVector2Add(v2, bodyB->position); + manifold->contacts[0] = v2; + normal = MathMatVector2Product(bodyB->shape.transform, normal); + MathVector2Normalize(&normal); + manifold->normal = normal; + } + else // Closest to face + { + Vector2 normal = vertexData.normals[faceNormal]; + + if (MathVector2DotProduct(MathVector2Subtract(center, v1), normal) > bodyA->shape.radius) return; + + normal = MathMatVector2Product(bodyB->shape.transform, normal); + manifold->normal = CLITERAL(Vector2){ -normal.x, -normal.y }; + manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y }; + manifold->contactsCount = 1; + } +} + +// Solves collision between a polygon to a circle shape physics bodies +static void SolvePolygonToCircle(PhysicsManifold manifold) +{ + PhysicsBody bodyA = manifold->bodyA; + PhysicsBody bodyB = manifold->bodyB; + + if ((bodyA == NULL) || (bodyB == NULL)) return; + + manifold->bodyA = bodyB; + manifold->bodyB = bodyA; + SolveCircleToPolygon(manifold); + + manifold->normal.x *= -1.0f; + manifold->normal.y *= -1.0f; +} + +// Solves collision between two polygons shape physics bodies +static void SolvePolygonToPolygon(PhysicsManifold manifold) +{ + if ((manifold->bodyA == NULL) || (manifold->bodyB == NULL)) return; + + PhysicsShape bodyA = manifold->bodyA->shape; + PhysicsShape bodyB = manifold->bodyB->shape; + manifold->contactsCount = 0; + + // Check for separating axis with A shape's face planes + int faceA = 0; + float penetrationA = FindAxisLeastPenetration(&faceA, bodyA, bodyB); + if (penetrationA >= 0.0f) return; + + // Check for separating axis with B shape's face planes + int faceB = 0; + float penetrationB = FindAxisLeastPenetration(&faceB, bodyB, bodyA); + if (penetrationB >= 0.0f) return; + + int referenceIndex = 0; + bool flip = false; // Always point from A shape to B shape + + PhysicsShape refPoly; // Reference + PhysicsShape incPoly; // Incident + + // Determine which shape contains reference face + // Checking bias range for penetration + if (penetrationA >= (penetrationB*0.95f + penetrationA*0.01f)) + { + refPoly = bodyA; + incPoly = bodyB; + referenceIndex = faceA; + } + else + { + refPoly = bodyB; + incPoly = bodyA; + referenceIndex = faceB; + flip = true; + } + + // World space incident face + Vector2 incidentFace[2]; + FindIncidentFace(&incidentFace[0], &incidentFace[1], refPoly, incPoly, referenceIndex); + + // Setup reference face vertices + PhysicsVertexData refData = refPoly.vertexData; + Vector2 v1 = refData.positions[referenceIndex]; + referenceIndex = (((referenceIndex + 1) < (int)refData.vertexCount) ? (referenceIndex + 1) : 0); + Vector2 v2 = refData.positions[referenceIndex]; + + // Transform vertices to world space + v1 = MathMatVector2Product(refPoly.transform, v1); + v1 = MathVector2Add(v1, refPoly.body->position); + v2 = MathMatVector2Product(refPoly.transform, v2); + v2 = MathVector2Add(v2, refPoly.body->position); + + // Calculate reference face side normal in world space + Vector2 sidePlaneNormal = MathVector2Subtract(v2, v1); + MathVector2Normalize(&sidePlaneNormal); + + // Orthogonalize + Vector2 refFaceNormal = { sidePlaneNormal.y, -sidePlaneNormal.x }; + float refC = MathVector2DotProduct(refFaceNormal, v1); + float negSide = MathVector2DotProduct(sidePlaneNormal, v1)*-1; + float posSide = MathVector2DotProduct(sidePlaneNormal, v2); + + // MathVector2Clip incident face to reference face side planes (due to floating point error, possible to not have required points + if (MathVector2Clip(CLITERAL(Vector2){ -sidePlaneNormal.x, -sidePlaneNormal.y }, &incidentFace[0], &incidentFace[1], negSide) < 2) return; + if (MathVector2Clip(sidePlaneNormal, &incidentFace[0], &incidentFace[1], posSide) < 2) return; + + // Flip normal if required + manifold->normal = (flip ? CLITERAL(Vector2){ -refFaceNormal.x, -refFaceNormal.y } : refFaceNormal); + + // Keep points behind reference face + int currentPoint = 0; // MathVector2Clipped points behind reference face + float separation = MathVector2DotProduct(refFaceNormal, incidentFace[0]) - refC; + if (separation <= 0.0f) + { + manifold->contacts[currentPoint] = incidentFace[0]; + manifold->penetration = -separation; + currentPoint++; + } + else manifold->penetration = 0.0f; + + separation = MathVector2DotProduct(refFaceNormal, incidentFace[1]) - refC; + + if (separation <= 0.0f) + { + manifold->contacts[currentPoint] = incidentFace[1]; + manifold->penetration += -separation; + currentPoint++; + + // Calculate total penetration average + manifold->penetration /= currentPoint; + } + + manifold->contactsCount = currentPoint; +} + +// Integrates physics forces into velocity +static void IntegratePhysicsForces(PhysicsBody body) +{ + if ((body == NULL) || (body->inverseMass == 0.0f) || !body->enabled) return; + + body->velocity.x += (float)((body->force.x*body->inverseMass)*(deltaTime/2.0)); + body->velocity.y += (float)((body->force.y*body->inverseMass)*(deltaTime/2.0)); + + if (body->useGravity) + { + body->velocity.x += (float)(gravityForce.x*(deltaTime/1000/2.0)); + body->velocity.y += (float)(gravityForce.y*(deltaTime/1000/2.0)); + } + + if (!body->freezeOrient) body->angularVelocity += (float)(body->torque*body->inverseInertia*(deltaTime/2.0)); +} + +// Initializes physics manifolds to solve collisions +static void InitializePhysicsManifolds(PhysicsManifold manifold) +{ + PhysicsBody bodyA = manifold->bodyA; + PhysicsBody bodyB = manifold->bodyB; + + if ((bodyA == NULL) || (bodyB == NULL)) return; + + // Calculate average restitution, static and dynamic friction + manifold->restitution = sqrtf(bodyA->restitution*bodyB->restitution); + manifold->staticFriction = sqrtf(bodyA->staticFriction*bodyB->staticFriction); + manifold->dynamicFriction = sqrtf(bodyA->dynamicFriction*bodyB->dynamicFriction); + + for (unsigned int i = 0; i < manifold->contactsCount; i++) + { + // Caculate radius from center of mass to contact + Vector2 radiusA = MathVector2Subtract(manifold->contacts[i], bodyA->position); + Vector2 radiusB = MathVector2Subtract(manifold->contacts[i], bodyB->position); + + Vector2 crossA = MathVector2Product(radiusA, bodyA->angularVelocity); + Vector2 crossB = MathVector2Product(radiusB, bodyB->angularVelocity); + + Vector2 radiusV = { 0.0f, 0.0f }; + radiusV.x = bodyB->velocity.x + crossB.x - bodyA->velocity.x - crossA.x; + radiusV.y = bodyB->velocity.y + crossB.y - bodyA->velocity.y - crossA.y; + + // Determine if we should perform a resting collision or not; + // The idea is if the only thing moving this object is gravity, then the collision should be performed without any restitution + if (MathVector2SqrLen(radiusV) < (MathVector2SqrLen(CLITERAL(Vector2){ (float)(gravityForce.x*deltaTime/1000), (float)(gravityForce.y*deltaTime/1000) }) + PHYSAC_EPSILON)) manifold->restitution = 0; + } +} + +// Integrates physics collisions impulses to solve collisions +static void IntegratePhysicsImpulses(PhysicsManifold manifold) +{ + PhysicsBody bodyA = manifold->bodyA; + PhysicsBody bodyB = manifold->bodyB; + + if ((bodyA == NULL) || (bodyB == NULL)) return; + + // Early out and positional correct if both objects have infinite mass + if (fabs(bodyA->inverseMass + bodyB->inverseMass) <= PHYSAC_EPSILON) + { + bodyA->velocity = PHYSAC_VECTOR_ZERO; + bodyB->velocity = PHYSAC_VECTOR_ZERO; + return; + } + + for (unsigned int i = 0; i < manifold->contactsCount; i++) + { + // Calculate radius from center of mass to contact + Vector2 radiusA = MathVector2Subtract(manifold->contacts[i], bodyA->position); + Vector2 radiusB = MathVector2Subtract(manifold->contacts[i], bodyB->position); + + // Calculate relative velocity + Vector2 radiusV = { 0.0f, 0.0f }; + radiusV.x = bodyB->velocity.x + MathVector2Product(radiusB, bodyB->angularVelocity).x - bodyA->velocity.x - MathVector2Product(radiusA, bodyA->angularVelocity).x; + radiusV.y = bodyB->velocity.y + MathVector2Product(radiusB, bodyB->angularVelocity).y - bodyA->velocity.y - MathVector2Product(radiusA, bodyA->angularVelocity).y; + + // Relative velocity along the normal + float contactVelocity = MathVector2DotProduct(radiusV, manifold->normal); + + // Do not resolve if velocities are separating + if (contactVelocity > 0.0f) return; + + float raCrossN = MathVector2CrossProduct(radiusA, manifold->normal); + float rbCrossN = MathVector2CrossProduct(radiusB, manifold->normal); + + float inverseMassSum = bodyA->inverseMass + bodyB->inverseMass + (raCrossN*raCrossN)*bodyA->inverseInertia + (rbCrossN*rbCrossN)*bodyB->inverseInertia; + + // Calculate impulse scalar value + float impulse = -(1.0f + manifold->restitution)*contactVelocity; + impulse /= inverseMassSum; + impulse /= (float)manifold->contactsCount; + + // Apply impulse to each physics body + Vector2 impulseV = { manifold->normal.x*impulse, manifold->normal.y*impulse }; + + if (bodyA->enabled) + { + bodyA->velocity.x += bodyA->inverseMass*(-impulseV.x); + bodyA->velocity.y += bodyA->inverseMass*(-impulseV.y); + if (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathVector2CrossProduct(radiusA, CLITERAL(Vector2){ -impulseV.x, -impulseV.y }); + } + + if (bodyB->enabled) + { + bodyB->velocity.x += bodyB->inverseMass*(impulseV.x); + bodyB->velocity.y += bodyB->inverseMass*(impulseV.y); + if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathVector2CrossProduct(radiusB, impulseV); + } + + // Apply friction impulse to each physics body + radiusV.x = bodyB->velocity.x + MathVector2Product(radiusB, bodyB->angularVelocity).x - bodyA->velocity.x - MathVector2Product(radiusA, bodyA->angularVelocity).x; + radiusV.y = bodyB->velocity.y + MathVector2Product(radiusB, bodyB->angularVelocity).y - bodyA->velocity.y - MathVector2Product(radiusA, bodyA->angularVelocity).y; + + Vector2 tangent = { radiusV.x - (manifold->normal.x*MathVector2DotProduct(radiusV, manifold->normal)), radiusV.y - (manifold->normal.y*MathVector2DotProduct(radiusV, manifold->normal)) }; + MathVector2Normalize(&tangent); + + // Calculate impulse tangent magnitude + float impulseTangent = -MathVector2DotProduct(radiusV, tangent); + impulseTangent /= inverseMassSum; + impulseTangent /= (float)manifold->contactsCount; + + float absImpulseTangent = (float)fabs(impulseTangent); + + // Don't apply tiny friction impulses + if (absImpulseTangent <= PHYSAC_EPSILON) return; + + // Apply coulumb's law + Vector2 tangentImpulse = { 0.0f, 0.0f }; + if (absImpulseTangent < impulse*manifold->staticFriction) tangentImpulse = CLITERAL(Vector2){ tangent.x*impulseTangent, tangent.y*impulseTangent }; + else tangentImpulse = CLITERAL(Vector2){ tangent.x*-impulse*manifold->dynamicFriction, tangent.y*-impulse*manifold->dynamicFriction }; + + // Apply friction impulse + if (bodyA->enabled) + { + bodyA->velocity.x += bodyA->inverseMass*(-tangentImpulse.x); + bodyA->velocity.y += bodyA->inverseMass*(-tangentImpulse.y); + + if (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathVector2CrossProduct(radiusA, CLITERAL(Vector2){ -tangentImpulse.x, -tangentImpulse.y }); + } + + if (bodyB->enabled) + { + bodyB->velocity.x += bodyB->inverseMass*(tangentImpulse.x); + bodyB->velocity.y += bodyB->inverseMass*(tangentImpulse.y); + + if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathVector2CrossProduct(radiusB, tangentImpulse); + } + } +} + +// Integrates physics velocity into position and forces +static void IntegratePhysicsVelocity(PhysicsBody body) +{ + if ((body == NULL) ||!body->enabled) return; + + body->position.x += (float)(body->velocity.x*deltaTime); + body->position.y += (float)(body->velocity.y*deltaTime); + + if (!body->freezeOrient) body->orient += (float)(body->angularVelocity*deltaTime); + body->shape.transform = MathMatFromRadians(body->orient); + + IntegratePhysicsForces(body); +} + +// Corrects physics bodies positions based on manifolds collision information +static void CorrectPhysicsPositions(PhysicsManifold manifold) +{ + PhysicsBody bodyA = manifold->bodyA; + PhysicsBody bodyB = manifold->bodyB; + + if ((bodyA == NULL) || (bodyB == NULL)) return; + + Vector2 correction = { 0.0f, 0.0f }; + correction.x = (PHYSAC_MAX(manifold->penetration - PHYSAC_PENETRATION_ALLOWANCE, 0.0f)/(bodyA->inverseMass + bodyB->inverseMass))*manifold->normal.x*PHYSAC_PENETRATION_CORRECTION; + correction.y = (PHYSAC_MAX(manifold->penetration - PHYSAC_PENETRATION_ALLOWANCE, 0.0f)/(bodyA->inverseMass + bodyB->inverseMass))*manifold->normal.y*PHYSAC_PENETRATION_CORRECTION; + + if (bodyA->enabled) + { + bodyA->position.x -= correction.x*bodyA->inverseMass; + bodyA->position.y -= correction.y*bodyA->inverseMass; + } + + if (bodyB->enabled) + { + bodyB->position.x += correction.x*bodyB->inverseMass; + bodyB->position.y += correction.y*bodyB->inverseMass; + } +} + +// Returns the extreme point along a direction within a polygon +static Vector2 GetSupport(PhysicsShape shape, Vector2 dir) +{ + float bestProjection = -PHYSAC_FLT_MAX; + Vector2 bestVertex = { 0.0f, 0.0f }; + PhysicsVertexData data = shape.vertexData; + + for (unsigned int i = 0; i < data.vertexCount; i++) + { + Vector2 vertex = data.positions[i]; + float projection = MathVector2DotProduct(vertex, dir); + + if (projection > bestProjection) + { + bestVertex = vertex; + bestProjection = projection; + } + } + + return bestVertex; +} + +// Finds polygon shapes axis least penetration +static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB) +{ + float bestDistance = -PHYSAC_FLT_MAX; + int bestIndex = 0; + + PhysicsVertexData dataA = shapeA.vertexData; + //PhysicsVertexData dataB = shapeB.vertexData; + + for (unsigned int i = 0; i < dataA.vertexCount; i++) + { + // Retrieve a face normal from A shape + Vector2 normal = dataA.normals[i]; + Vector2 transNormal = MathMatVector2Product(shapeA.transform, normal); + + // Transform face normal into B shape's model space + Matrix2x2 buT = MathMatTranspose(shapeB.transform); + normal = MathMatVector2Product(buT, transNormal); + + // Retrieve support point from B shape along -n + Vector2 support = GetSupport(shapeB, CLITERAL(Vector2){ -normal.x, -normal.y }); + + // Retrieve vertex on face from A shape, transform into B shape's model space + Vector2 vertex = dataA.positions[i]; + vertex = MathMatVector2Product(shapeA.transform, vertex); + vertex = MathVector2Add(vertex, shapeA.body->position); + vertex = MathVector2Subtract(vertex, shapeB.body->position); + vertex = MathMatVector2Product(buT, vertex); + + // Compute penetration distance in B shape's model space + float distance = MathVector2DotProduct(normal, MathVector2Subtract(support, vertex)); + + // Store greatest distance + if (distance > bestDistance) + { + bestDistance = distance; + bestIndex = i; + } + } + + *faceIndex = bestIndex; + return bestDistance; +} + +// Finds two polygon shapes incident face +static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, PhysicsShape inc, int index) +{ + PhysicsVertexData refData = ref.vertexData; + PhysicsVertexData incData = inc.vertexData; + + Vector2 referenceNormal = refData.normals[index]; + + // Calculate normal in incident's frame of reference + referenceNormal = MathMatVector2Product(ref.transform, referenceNormal); // To world space + referenceNormal = MathMatVector2Product(MathMatTranspose(inc.transform), referenceNormal); // To incident's model space + + // Find most anti-normal face on polygon + int incidentFace = 0; + float minDot = PHYSAC_FLT_MAX; + + for (unsigned int i = 0; i < incData.vertexCount; i++) + { + float dot = MathVector2DotProduct(referenceNormal, incData.normals[i]); + + if (dot < minDot) + { + minDot = dot; + incidentFace = i; + } + } + + // Assign face vertices for incident face + *v0 = MathMatVector2Product(inc.transform, incData.positions[incidentFace]); + *v0 = MathVector2Add(*v0, inc.body->position); + incidentFace = (((incidentFace + 1) < (int)incData.vertexCount) ? (incidentFace + 1) : 0); + *v1 = MathMatVector2Product(inc.transform, incData.positions[incidentFace]); + *v1 = MathVector2Add(*v1, inc.body->position); +} + +// Returns clipping value based on a normal and two faces +static int MathVector2Clip(Vector2 normal, Vector2 *faceA, Vector2 *faceB, float clip) +{ + int sp = 0; + Vector2 out[2] = { *faceA, *faceB }; + + // Retrieve distances from each endpoint to the line + float distanceA = MathVector2DotProduct(normal, *faceA) - clip; + float distanceB = MathVector2DotProduct(normal, *faceB) - clip; + + // If negative (behind plane) + if (distanceA <= 0.0f) out[sp++] = *faceA; + if (distanceB <= 0.0f) out[sp++] = *faceB; + + // If the points are on different sides of the plane + if ((distanceA*distanceB) < 0.0f) + { + // Push intersection point + float alpha = distanceA/(distanceA - distanceB); + out[sp] = *faceA; + Vector2 delta = MathVector2Subtract(*faceB, *faceA); + delta.x *= alpha; + delta.y *= alpha; + out[sp] = MathVector2Add(out[sp], delta); + sp++; + } + + // Assign the new converted values + *faceA = out[0]; + *faceB = out[1]; + + return sp; +} + +// Returns the barycenter of a triangle given by 3 points +static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3) +{ + Vector2 result = { 0.0f, 0.0f }; + + result.x = (v1.x + v2.x + v3.x)/3; + result.y = (v1.y + v2.y + v3.y)/3; + + return result; +} + +// Returns the cross product of a vector and a value +static inline Vector2 MathVector2Product(Vector2 vector, float value) +{ + Vector2 result = { -value*vector.y, value*vector.x }; + return result; +} + +// Returns the cross product of two vectors +static inline float MathVector2CrossProduct(Vector2 v1, Vector2 v2) +{ + return (v1.x*v2.y - v1.y*v2.x); +} + +// Returns the len square root of a vector +static inline float MathVector2SqrLen(Vector2 vector) +{ + return (vector.x*vector.x + vector.y*vector.y); +} + +// Returns the dot product of two vectors +static inline float MathVector2DotProduct(Vector2 v1, Vector2 v2) +{ + return (v1.x*v2.x + v1.y*v2.y); +} + +// Returns the square root of distance between two vectors +static inline float MathVector2SqrDistance(Vector2 v1, Vector2 v2) +{ + Vector2 dir = MathVector2Subtract(v1, v2); + return MathVector2DotProduct(dir, dir); +} + +// Returns the normalized values of a vector +static void MathVector2Normalize(Vector2 *vector) +{ + float length, ilength; + + Vector2 aux = *vector; + length = sqrtf(aux.x*aux.x + aux.y*aux.y); + + if (length == 0) length = 1.0f; + + ilength = 1.0f/length; + + vector->x *= ilength; + vector->y *= ilength; +} + +// Returns the sum of two given vectors +static inline Vector2 MathVector2Add(Vector2 v1, Vector2 v2) +{ + Vector2 result = { v1.x + v2.x, v1.y + v2.y }; + return result; +} + +// Returns the subtract of two given vectors +static inline Vector2 MathVector2Subtract(Vector2 v1, Vector2 v2) +{ + Vector2 result = { v1.x - v2.x, v1.y - v2.y }; + return result; +} + +// Creates a matrix 2x2 from a given radians value +static Matrix2x2 MathMatFromRadians(float radians) +{ + float cos = cosf(radians); + float sin = sinf(radians); + + Matrix2x2 result = { cos, -sin, sin, cos }; + return result; +} + +// Returns the transpose of a given matrix 2x2 +static inline Matrix2x2 MathMatTranspose(Matrix2x2 matrix) +{ + Matrix2x2 result = { matrix.m00, matrix.m10, matrix.m01, matrix.m11 }; + return result; +} + +// Multiplies a vector by a matrix 2x2 +static inline Vector2 MathMatVector2Product(Matrix2x2 matrix, Vector2 vector) +{ + Vector2 result = { matrix.m00*vector.x + matrix.m01*vector.y, matrix.m10*vector.x + matrix.m11*vector.y }; + return result; +} + +#endif // PHYSAC_IMPLEMENTATION diff --git a/include/raygui.h b/include/raygui.h new file mode 100644 index 0000000..5efb524 --- /dev/null +++ b/include/raygui.h @@ -0,0 +1,6052 @@ +/******************************************************************************************* +* +* raygui v5.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 +* available as a standalone library, as long as input and drawing functions are provided +* +* FEATURES: +* - Immediate-mode gui, minimal retained data +* - +25 controls provided (basic and advanced) +* - Styling system for colors, font and metrics +* - Icons supported, embedded as a 1-bit icons pack +* - Standalone mode option (custom input/graphics backend) +* - Multiple support tools provided for raygui development +* +* POSSIBLE IMPROVEMENTS: +* - Better standalone mode API for easy plug of custom backends +* - Externalize required inputs, allow user easier customization +* +* LIMITATIONS: +* - No editable multi-line word-wraped text box supported +* - No auto-layout mechanism, up to the user to define controls position and size +* - Standalone mode requires library modification and some user work to plug another backend +* +* NOTES: +* - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for +* font atlas recs and glyphs, freeing that memory is (usually) up to the user, +* no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads +* by default any previously loaded font (texture, recs, glyphs) +* - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions +* +* CONTROLS PROVIDED: +* # Container/separators Controls +* - WindowBox --> StatusBar, Panel +* - GroupBox --> Line +* - Line +* - Panel --> StatusBar +* - ScrollPanel --> StatusBar +* - TabBar --> Button +* +* # Basic Controls +* - Label +* - LabelButton --> Label +* - Button +* - Toggle +* - ToggleGroup --> Toggle +* - ToggleSlider +* - CheckBox +* - ComboBox +* - DropdownBox +* - TextBox +* - ValueBox --> TextBox +* - Spinner --> Button, ValueBox +* - Slider +* - SliderBar --> Slider +* - ProgressBar +* - StatusBar +* - DummyRec +* - Grid +* +* # Advance Controls +* - ListView +* - ColorPicker --> ColorPanel, ColorBarHue +* - MessageBox --> Window, Label, Button +* - TextInputBox --> Window, Label, TextBox, Button +* +* It also provides a set of functions for styling the controls based on its properties (size, color) +* +* +* RAYGUI STYLE (guiStyle): +* raygui uses a global data array for all gui style properties (allocated on data segment by default), +* when a new style is loaded, it is loaded over the global style... but a default gui style could always be +* recovered with GuiLoadStyleDefault() function, that overwrites the current style to the default one +* +* The global style array size is fixed and depends on the number of controls and properties: +* +* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)]; +* +* guiStyle size is by default: 16*(16 + 8) = 384 int = 384*4 bytes = 1536 bytes = 1.5 KB +* +* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style +* used for all controls, when any of those base values is set, it is automatically populated to all +* controls, so, specific control values overwriting generic style should be set after base values +* +* After the first BASE properties set, the EXTENDED properties set is defined (by default guiStyle[16..23]), +* those properties are actually common to all controls and can not be overwritten individually (like BASE ones) +* Some of those properties are: TEXT_SIZE, TEXT_SPACING, LINE_COLOR, BACKGROUND_COLOR +* +* Custom control properties can be defined using the EXTENDED properties for each independent control. +* +* TOOL: rGuiStyler is a visual tool to customize raygui style: github.com/raysan5/rguistyler +* +* +* RAYGUI ICONS (guiIcons): +* raygui could use a global array containing icons data (allocated on data segment by default), +* a custom icons set could be loaded over this array using GuiLoadIcons(), but loaded icons set +* must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS will be loaded +* +* Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon +* requires 8 integers (16*16/32) to be stored in memory. +* +* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set +* +* The global icons array size is fixed and depends on the number of icons and size: +* +* static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS]; +* +* guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +* +* TOOL: rGuiIcons is a visual tool to customize/create raygui icons: github.com/raysan5/rguiicons +* +* RAYGUI LAYOUT: +* raygui currently does not provide an auto-layout mechanism like other libraries, +* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it +* +* TOOL: rGuiLayout is a visual tool to create raygui layouts: github.com/raysan5/rguilayout +* +* CONFIGURATION: +* #define RAYGUI_IMPLEMENTATION +* Generates the implementation of the library into the included file +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation +* +* #define RAYGUI_STANDALONE +* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined +* internally in the library and input management and drawing functions must be provided by +* the user (check library implementation for further details) +* +* #define RAYGUI_NO_ICONS +* Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB) +* +* #define RAYGUI_CUSTOM_ICONS +* Includes custom ricons.h header defining a set of custom icons, +* this file can be generated using rGuiIcons tool +* +* #define RAYGUI_DEBUG_RECS_BOUNDS +* Draw control bounds rectangles for debug +* +* #define RAYGUI_DEBUG_TEXT_BOUNDS +* Draw text bounds rectangles for debug +* +* VERSIONS HISTORY: +* 5.0 (xx-Mar-2026) ADDED: Support up to 32 controls (v500) +* 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: GuiLoadIconsFromMemory() +* ADDED: Multiple new icons +* ADDED: Macros for inputs customization, raylib decoupling +* REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties +* REMOVED: GuiSliderPro(), functionality was redundant +* REVIEWED: Controls using text labels to use LABEL properties +* REVIEWED: Replaced sprintf() by snprintf() for more safety +* 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: GuiProgressBar(), improved borders computing +* REVIEWED: GuiTextBox(), multiple improvements: autocursor and more +* REVIEWED: Functions descriptions, removed wrong return value reference +* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion +* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing +* +* 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() +* ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() +* ADDED: Multiple new icons, mostly compiler related +* ADDED: New DEFAULT properties: TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE +* ADDED: New enum values: GuiTextAlignment, GuiTextAlignmentVertical, GuiTextWrapMode +* ADDED: Support loading styles with custom font charset from external file +* REDESIGNED: GuiTextBox(), support mouse cursor positioning +* REDESIGNED: GuiDrawText(), support multiline and word-wrap modes (read only) +* REDESIGNED: GuiProgressBar() to be more visual, progress affects border color +* REDESIGNED: Global alpha consideration moved to GuiDrawRectangle() and GuiDrawText() +* REDESIGNED: GuiScrollPanel(), get parameters by reference and return result value +* REDESIGNED: GuiToggleGroup(), get parameters by reference and return result value +* REDESIGNED: GuiComboBox(), get parameters by reference and return result value +* REDESIGNED: GuiCheckBox(), get parameters by reference and return result value +* REDESIGNED: GuiSlider(), get parameters by reference and return result value +* REDESIGNED: GuiSliderBar(), get parameters by reference and return result value +* REDESIGNED: GuiProgressBar(), get parameters by reference and return result value +* REDESIGNED: GuiListView(), get parameters by reference and return result value +* REDESIGNED: GuiColorPicker(), get parameters by reference and return result value +* REDESIGNED: GuiColorPanel(), get parameters by reference and return result value +* REDESIGNED: GuiColorBarAlpha(), get parameters by reference and return result value +* REDESIGNED: GuiColorBarHue(), get parameters by reference and return result value +* REDESIGNED: GuiGrid(), get parameters by reference and return result value +* REDESIGNED: GuiGrid(), added extra parameter +* REDESIGNED: GuiListViewEx(), change parameters order +* REDESIGNED: All controls return result as int value +* REVIEWED: GuiScrollPanel() to avoid smallish scroll-bars +* REVIEWED: All examples and specially controls_test_suite +* RENAMED: gui_file_dialog module to gui_window_file_dialog +* UPDATED: All styles to include ISO-8859-15 charset (as much as possible) +* +* 3.6 (10-May-2023) ADDED: New icon: SAND_TIMER +* ADDED: GuiLoadStyleFromMemory() (binary only) +* REVIEWED: GuiScrollBar() horizontal movement key +* REVIEWED: GuiTextBox() crash on cursor movement +* REVIEWED: GuiTextBox(), additional inputs support +* REVIEWED: GuiLabelButton(), avoid text cut +* REVIEWED: GuiTextInputBox(), password input +* REVIEWED: Local GetCodepointNext(), aligned with raylib +* REDESIGNED: GuiSlider*()/GuiScrollBar() to support out-of-bounds +* +* 3.5 (20-Apr-2023) ADDED: GuiTabBar(), based on GuiToggle() +* ADDED: Helper functions to split text in separate lines +* ADDED: Multiple new icons, useful for code editing tools +* REMOVED: Unneeded icon editing functions +* REMOVED: GuiTextBoxMulti(), very limited and broken +* REMOVED: MeasureTextEx() dependency, logic directly implemented +* REMOVED: DrawTextEx() dependency, logic directly implemented +* REVIEWED: GuiScrollBar(), improve mouse-click behaviour +* REVIEWED: Library header info, more info, better organized +* REDESIGNED: GuiTextBox() to support cursor movement +* REDESIGNED: GuiDrawText() to divide drawing by lines +* +* 3.2 (22-May-2022) RENAMED: Some enum values, for unification, avoiding prefixes +* REMOVED: GuiScrollBar(), only internal +* REDESIGNED: GuiPanel() to support text parameter +* REDESIGNED: GuiScrollPanel() to support text parameter +* REDESIGNED: GuiColorPicker() to support text parameter +* REDESIGNED: GuiColorPanel() to support text parameter +* REDESIGNED: GuiColorBarAlpha() to support text parameter +* REDESIGNED: GuiColorBarHue() to support text parameter +* REDESIGNED: GuiTextInputBox() to support password +* +* 3.1 (12-Jan-2022) REVIEWED: Default style for consistency (aligned with rGuiLayout v2.5 tool) +* REVIEWED: GuiLoadStyle() to support compressed font atlas image data and unload previous textures +* REVIEWED: External icons usage logic +* REVIEWED: GuiLine() for centered alignment when including text +* RENAMED: Multiple controls properties definitions to prepend RAYGUI_ +* RENAMED: RICON_ references to RAYGUI_ICON_ for library consistency +* Projects updated and multiple tweaks +* +* 3.0 (04-Nov-2021) Integrated ricons data to avoid external file +* REDESIGNED: GuiTextBoxMulti() +* REMOVED: GuiImageButton*() +* Multiple minor tweaks and bugs corrected +* +* 2.9 (17-Mar-2021) REMOVED: Tooltip API +* 2.8 (03-May-2020) Centralized rectangles drawing to GuiDrawRectangle() +* 2.7 (20-Feb-2020) ADDED: Possible tooltips API +* 2.6 (09-Sep-2019) ADDED: GuiTextInputBox() +* REDESIGNED: GuiListView*(), GuiDropdownBox(), GuiSlider*(), GuiProgressBar(), GuiMessageBox() +* REVIEWED: GuiTextBox(), GuiSpinner(), GuiValueBox(), GuiLoadStyle() +* Replaced property INNER_PADDING by TEXT_PADDING, renamed some properties +* ADDED: 8 new custom styles ready to use +* Multiple minor tweaks and bugs corrected +* +* 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner() +* 2.3 (29-Apr-2019) ADDED: rIcons auxiliar library and support for it, multiple controls reviewed +* Refactor all controls drawing mechanism to use control state +* 2.2 (05-Feb-2019) ADDED: GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed RayGui*Ex() controls +* 2.1 (26-Dec-2018) REDESIGNED: GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string +* REDESIGNED: Style system (breaking change) +* 2.0 (08-Nov-2018) ADDED: Support controls guiLock and custom fonts +* REVIEWED: GuiComboBox(), GuiListView()... +* 1.9 (09-Oct-2018) REVIEWED: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()... +* 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout +* 1.5 (21-Jun-2017) Working in an improved styles system +* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones) +* 1.3 (12-Jun-2017) Complete redesign of style system +* 1.1 (01-Jun-2017) Complete review of the library +* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria +* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria +* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria +* +* DEPENDENCIES: +* raylib 5.6-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* +* STANDALONE MODE: +* By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled +* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs +* +* The following functions should be redefined for a custom backend: +* +* - Vector2 GetMousePosition(void); +* - float GetMouseWheelMove(void); +* - bool IsMouseButtonDown(int button); +* - bool IsMouseButtonPressed(int button); +* - bool IsMouseButtonReleased(int button); +* - bool IsKeyDown(int key); +* - bool IsKeyPressed(int key); +* - int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() +* +* - void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle() +* - void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() +* +* - Font GetFontDefault(void); // -- GuiLoadStyleDefault() +* - Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle() +* - Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image +* - void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization) +* - char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data +* - void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data +* - const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs +* - int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list +* - void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list +* - unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() +* +* CONTRIBUTORS: +* Ramon Santamaria: Supervision, review, redesign, update and maintenance +* Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019) +* Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018) +* Adria Arranz: Testing and implementation of additional controls (2018) +* Jordi Jorba: Testing and implementation of additional controls (2018) +* Albert Martos: Review and testing of the library (2015) +* Ian Eito: Review and testing of the library (2015) +* Kevin Gato: Initial implementation of basic components (2014) +* Daniel Nicolas: Initial implementation of basic components (2014) +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2014-2026 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RAYGUI_H +#define RAYGUI_H + +#define RAYGUI_VERSION_MAJOR 4 +#define RAYGUI_VERSION_MINOR 5 +#define RAYGUI_VERSION_PATCH 0 +#define RAYGUI_VERSION "5.0-dev" + +#if !defined(RAYGUI_STANDALONE) + #include "raylib.h" +#endif + +// Function specifiers in case library is build/used as a shared library (Windows) +// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll +#if defined(_WIN32) + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __declspec(dllexport) // Building the library as a Win32 shared library (.dll) + #elif defined(USE_LIBTYPE_SHARED) + #define RAYGUIAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) + #endif + #if !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #endif +#endif + +// Function specifiers definition +#ifndef RAYGUIAPI + #define RAYGUIAPI // Functions defined as 'extern' by default (implicit specifiers) +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Simple log system to avoid printf() calls if required +// NOTE: Avoiding those calls, also avoids const strings memory usage +#define RAYGUI_SUPPORT_LOG_INFO +#if defined(RAYGUI_SUPPORT_LOG_INFO) + #define RAYGUI_LOG(...) printf(__VA_ARGS__) +#else + #define RAYGUI_LOG(...) +#endif + +// Macros to define required UI inputs, including mapping to gamepad controls +// TODO: Define additionally required macros for missing inputs +#if !defined(GUI_BUTTON_DOWN) + #define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) +#endif +#if !defined(GUI_BUTTON_DOWN_ALT) + // Mapping to alternative button down pressed + #define GUI_BUTTON_DOWN_ALT (IsMouseButtonDown(MOUSE_RIGHT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_RIGHT)) +#endif +#if !defined(GUI_BUTTON_PRESSED) + #define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) +#endif +// TODO: WARNING: GuiTabBar() still requires IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) +#if !defined(GUI_BUTTON_RELEASED) + #define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) +#endif +#if !defined(GUI_SCROLL_DELTA) + // Mapping to scroll delta changes + // TODO: Review inconsistencies between platforms + #if defined(PLATFORM_WEB) + // NOTE: Gamepad axis triggers not detected on web platform + #define GUI_SCROLL_DELTA ((float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_TRIGGER_2) - (float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_TRIGGER_2)) + #else + #define GUI_SCROLL_DELTA (GetMouseWheelMove() + (GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_TRIGGER) + 1) - (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_TRIGGER) + 1)) + #endif +#endif +#if !defined(GUI_POINTER_POSITION) + #define GUI_POINTER_POSITION GetMousePosition() +#endif +#if !defined(GUI_KEY_DOWN) + #define GUI_KEY_DOWN(key) IsKeyDown(key) +#endif +#if !defined(GUI_KEY_PRESSED) + #define GUI_KEY_PRESSED(key) IsKeyPressed(key) +#endif +#if !defined(GUI_INPUT_KEY) + #define GUI_INPUT_KEY GetCharPressed() +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Some types are required for RAYGUI_STANDALONE usage +//---------------------------------------------------------------------------------- +#if defined(RAYGUI_STANDALONE) + #ifndef __cplusplus + // Boolean type + #ifndef true + typedef enum { false, true } bool; + #endif + #endif + + // Vector2 type + typedef struct Vector2 { + float x; + float y; + } Vector2; + + // Vector3 type // -- ConvertHSVtoRGB(), ConvertRGBtoHSV() + typedef struct Vector3 { + float x; + float y; + float z; + } Vector3; + + // Color type, RGBA (32bit) + typedef struct Color { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + } Color; + + // Rectangle type + typedef struct Rectangle { + float x; + float y; + float width; + float height; + } Rectangle; + + // TODO: Texture2D type is very coupled to raylib, required by Font type + // It should be redesigned to be provided by user + typedef struct Texture { + unsigned int id; // OpenGL texture id + int width; // Texture base width + int height; // Texture base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) + } Texture; + + // Texture2D, same as Texture + typedef Texture Texture2D; + + // Image, pixel data stored in CPU memory (RAM) + typedef struct Image { + void *data; // Image raw data + int width; // Image base width + int height; // Image base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) + } Image; + + // GlyphInfo, font characters glyphs info + typedef struct GlyphInfo { + int value; // Character value (Unicode) + int offsetX; // Character offset X when drawing + int offsetY; // Character offset Y when drawing + int advanceX; // Character advance position X + Image image; // Character image data + } GlyphInfo; + + // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() + // It should be redesigned to be provided by user + typedef struct Font { + int baseSize; // Base size (default chars height) + int glyphCount; // Number of glyph characters + int glyphPadding; // Padding around the glyph characters + Texture2D texture; // Texture atlas containing the glyphs + Rectangle *recs; // Rectangles in texture for the glyphs + GlyphInfo *glyphs; // Glyphs info data + } Font; +#endif + +// Style property +// NOTE: Used when exporting style as code for convenience +typedef struct GuiStyleProp { + unsigned short controlId; // Control identifier + unsigned short propertyId; // Property identifier + int propertyValue; // Property value +} GuiStyleProp; + +/* +// Controls text style -NOT USED- +// NOTE: Text style is defined by control +typedef struct GuiTextStyle { + unsigned int size; + int charSpacing; + int lineSpacing; + int alignmentH; + int alignmentV; + int padding; +} GuiTextStyle; +*/ + +// RayGui control state +typedef enum { + STATE_NORMAL = 0, + STATE_FOCUSED, + STATE_PRESSED, + STATE_DISABLED +} GuiState; + +// RayGui control text alignment +typedef enum { + TEXT_ALIGN_LEFT = 0, + TEXT_ALIGN_CENTER, + TEXT_ALIGN_RIGHT +} GuiTextAlignment; + +// RayGui control text alignment vertical +// NOTE: Text vertical position inside the text bounds +typedef enum { + TEXT_ALIGN_TOP = 0, + TEXT_ALIGN_MIDDLE, + TEXT_ALIGN_BOTTOM +} GuiTextAlignmentVertical; + +// RayGui control text wrap mode +// NOTE: Useful for multiline text +typedef enum { + TEXT_WRAP_NONE = 0, + TEXT_WRAP_CHAR, + TEXT_WRAP_WORD +} GuiTextWrapMode; + +// RayGui controls +typedef enum { + // Default -> populates to all controls when set + DEFAULT = 0, + + // Basic controls + LABEL, // Used also for: LABELBUTTON + BUTTON, + TOGGLE, // Used also for: TOGGLEGROUP + SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER + PROGRESSBAR, + CHECKBOX, + COMBOBOX, + DROPDOWNBOX, + TEXTBOX, // Used also for: TEXTBOXMULTI + VALUEBOX, + CONTROL11, + LISTVIEW, + COLORPICKER, + SCROLLBAR, + STATUSBAR +} GuiControl; + +// RayGui base properties for every control +// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) +typedef enum { + BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL + BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL + TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL + BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED + BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED + TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED + BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED + BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED + TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED + BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED + BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED + TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED + BORDER_WIDTH = 12, // Control border size, 0 for no border + //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls + //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls + //TEXT_LINE_SPACING, // Control text spacing between lines -> GLOBAL for all controls + TEXT_PADDING = 13, // Control text padding, not considering border + TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding) + //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls +} GuiControlProperty; + +// TODO: Which text styling properties should be global or per-control? +// At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while +// TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and +// should be configured by user as needed while defining the UI layout + +// RayGui extended properties depend on control +// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) +//---------------------------------------------------------------------------------- +// DEFAULT extended properties +// NOTE: Those properties are common to all controls or global +// WARNING: Only 8 slots vailable for those properties by default +typedef enum { + TEXT_SIZE = 16, // Text size (glyphs max height) + TEXT_SPACING, // Text spacing between glyphs + LINE_COLOR, // Line control color + BACKGROUND_COLOR, // Background color + TEXT_LINE_SPACING, // Text spacing between lines + TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) + TEXT_WRAP_MODE // Text wrap-mode inside text bounds + //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline + //TEXT_DECORATION_THICK // Text decoration line thickness +} GuiDefaultProperty; + +// Other possible text properties: +// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change +// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... + +// Label +//typedef enum { } GuiLabelProperty; + +// Button/Spinner +//typedef enum { } GuiButtonProperty; + +// Toggle/ToggleGroup +typedef enum { + GROUP_PADDING = 16, // ToggleGroup separation between toggles +} GuiToggleProperty; + +// Slider/SliderBar +typedef enum { + SLIDER_WIDTH = 16, // Slider size of internal bar + SLIDER_PADDING // Slider/SliderBar internal bar padding +} GuiSliderProperty; + +// ProgressBar +typedef enum { + PROGRESS_PADDING = 16, // ProgressBar internal padding + PROGRESS_SIDE, // ProgressBar increment side: 0-left->right, 1-right-left +} GuiProgressBarProperty; + +// ScrollBar +typedef enum { + ARROWS_SIZE = 16, // ScrollBar arrows size + ARROWS_VISIBLE, // ScrollBar arrows visible + SCROLL_SLIDER_PADDING, // ScrollBar slider internal padding + SCROLL_SLIDER_SIZE, // ScrollBar slider size + SCROLL_PADDING, // ScrollBar scroll padding from arrows + SCROLL_SPEED, // ScrollBar scrolling speed +} GuiScrollBarProperty; + +// CheckBox +typedef enum { + CHECK_PADDING = 16 // CheckBox internal check padding +} GuiCheckBoxProperty; + +// ComboBox +typedef enum { + COMBO_BUTTON_WIDTH = 16, // ComboBox right button width + COMBO_BUTTON_SPACING // ComboBox button separation +} GuiComboBoxProperty; + +// DropdownBox +typedef enum { + ARROW_PADDING = 16, // DropdownBox arrow separation from border and items + DROPDOWN_ITEMS_SPACING, // DropdownBox items separation + DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden + DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down) +} GuiDropdownBoxProperty; + +// TextBox/TextBoxMulti/ValueBox/Spinner +typedef enum { + TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable +} GuiTextBoxProperty; + +// ValueBox/Spinner +typedef enum { + SPINNER_BUTTON_WIDTH = 16, // Spinner left/right buttons width + SPINNER_BUTTON_SPACING, // Spinner buttons separation +} GuiValueBoxProperty; + +// Control11 +//typedef enum { } GuiControl11Property; + +// ListView +typedef enum { + LIST_ITEMS_HEIGHT = 16, // ListView items height + LIST_ITEMS_SPACING, // ListView items separation + SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) + SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) + LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state + LIST_ITEMS_BORDER_WIDTH // ListView items border width +} GuiListViewProperty; + +// ColorPicker +typedef enum { + COLOR_SELECTOR_SIZE = 16, + HUEBAR_WIDTH, // ColorPicker right hue bar width + HUEBAR_PADDING, // ColorPicker right hue bar separation from panel + HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height + HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow +} GuiColorPickerProperty; + +#define SCROLLBAR_LEFT_SIDE 0 +#define SCROLLBAR_RIGHT_SIDE 1 + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif + +// Global gui state control functions +RAYGUIAPI void GuiEnable(void); // Enable gui controls (global state) +RAYGUIAPI void GuiDisable(void); // Disable gui controls (global state) +RAYGUIAPI void GuiLock(void); // Lock gui controls (global state) +RAYGUIAPI void GuiUnlock(void); // Unlock gui controls (global state) +RAYGUIAPI bool GuiIsLocked(void); // Check if gui is locked (global state) +RAYGUIAPI void GuiSetAlpha(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f +RAYGUIAPI void GuiSetState(int state); // Set gui state (global state) +RAYGUIAPI int GuiGetState(void); // Get gui state (global state) + +// Font set/get functions +RAYGUIAPI void GuiSetFont(Font font); // Set gui custom font (global state) +RAYGUIAPI Font GuiGetFont(void); // Get gui custom font (global state) + +// Style set/get functions +RAYGUIAPI void GuiSetStyle(int control, int property, int value); // Set one style property +RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style property + +// Styles loading functions +RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) +RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style + +// Tooltips management functions +RAYGUIAPI void GuiEnableTooltip(void); // Enable gui tooltips (global state) +RAYGUIAPI void GuiDisableTooltip(void); // Disable gui tooltips (global state) +RAYGUIAPI void GuiSetTooltip(const char *tooltip); // Set tooltip string + +// Icons functionality +RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended (if supported) +#if !defined(RAYGUI_NO_ICONS) +RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size +RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer +RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data +RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position +#endif + +// Utility functions +RAYGUIAPI int GuiGetTextWidth(const char *text); // Get text width considering gui style and icon size (if required) + +// Controls +//---------------------------------------------------------------------------------------------------------- +// Container/separator controls, useful for controls organization +RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); // Window Box control, shows a window that can be closed +RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name +RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text +RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls +RAYGUIAPI int GuiTabBar(Rectangle bounds, char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1 +RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control + +// Basic controls set +RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control +RAYGUIAPI int GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked +RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, returns true when clicked +RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control +RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control +RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control +RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked); // Check Box control, returns true when active +RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control + +RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control +RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control +RAYGUIAPI int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers +RAYGUIAPI int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode); // Value box control for float values +RAYGUIAPI int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text + +RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control +RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control +RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control +RAYGUIAPI int GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text +RAYGUIAPI int GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders +RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control + +// Advance controls set +RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control +RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters +RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message +RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret +RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls) +RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control +RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control +RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control +RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls) +RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV() +//---------------------------------------------------------------------------------------------------------- + +#if !defined(RAYGUI_NO_ICONS) + +#if !defined(RAYGUI_CUSTOM_ICONS) +//---------------------------------------------------------------------------------- +// Icons enumeration +//---------------------------------------------------------------------------------- +typedef enum { + ICON_NONE = 0, + ICON_FOLDER_FILE_OPEN = 1, + ICON_FILE_SAVE_CLASSIC = 2, + ICON_FOLDER_OPEN = 3, + ICON_FOLDER_SAVE = 4, + ICON_FILE_OPEN = 5, + ICON_FILE_SAVE = 6, + ICON_FILE_EXPORT = 7, + ICON_FILE_ADD = 8, + ICON_FILE_DELETE = 9, + ICON_FILETYPE_TEXT = 10, + ICON_FILETYPE_AUDIO = 11, + ICON_FILETYPE_IMAGE = 12, + ICON_FILETYPE_PLAY = 13, + ICON_FILETYPE_VIDEO = 14, + ICON_FILETYPE_INFO = 15, + ICON_FILE_COPY = 16, + ICON_FILE_CUT = 17, + ICON_FILE_PASTE = 18, + ICON_CURSOR_HAND = 19, + ICON_CURSOR_POINTER = 20, + ICON_CURSOR_CLASSIC = 21, + ICON_PENCIL = 22, + ICON_PENCIL_BIG = 23, + ICON_BRUSH_CLASSIC = 24, + ICON_BRUSH_PAINTER = 25, + ICON_WATER_DROP = 26, + ICON_COLOR_PICKER = 27, + ICON_RUBBER = 28, + ICON_COLOR_BUCKET = 29, + ICON_TEXT_T = 30, + ICON_TEXT_A = 31, + ICON_SCALE = 32, + ICON_RESIZE = 33, + ICON_FILTER_POINT = 34, + ICON_FILTER_BILINEAR = 35, + ICON_CROP = 36, + ICON_CROP_ALPHA = 37, + ICON_SQUARE_TOGGLE = 38, + ICON_SYMMETRY = 39, + ICON_SYMMETRY_HORIZONTAL = 40, + ICON_SYMMETRY_VERTICAL = 41, + ICON_LENS = 42, + ICON_LENS_BIG = 43, + ICON_EYE_ON = 44, + ICON_EYE_OFF = 45, + ICON_FILTER_TOP = 46, + ICON_FILTER = 47, + ICON_TARGET_POINT = 48, + ICON_TARGET_SMALL = 49, + ICON_TARGET_BIG = 50, + ICON_TARGET_MOVE = 51, + ICON_CURSOR_MOVE = 52, + ICON_CURSOR_SCALE = 53, + ICON_CURSOR_SCALE_RIGHT = 54, + ICON_CURSOR_SCALE_LEFT = 55, + ICON_UNDO = 56, + ICON_REDO = 57, + ICON_REREDO = 58, + ICON_MUTATE = 59, + ICON_ROTATE = 60, + ICON_REPEAT = 61, + ICON_SHUFFLE = 62, + ICON_EMPTYBOX = 63, + ICON_TARGET = 64, + ICON_TARGET_SMALL_FILL = 65, + ICON_TARGET_BIG_FILL = 66, + ICON_TARGET_MOVE_FILL = 67, + ICON_CURSOR_MOVE_FILL = 68, + ICON_CURSOR_SCALE_FILL = 69, + ICON_CURSOR_SCALE_RIGHT_FILL = 70, + ICON_CURSOR_SCALE_LEFT_FILL = 71, + ICON_UNDO_FILL = 72, + ICON_REDO_FILL = 73, + ICON_REREDO_FILL = 74, + ICON_MUTATE_FILL = 75, + ICON_ROTATE_FILL = 76, + ICON_REPEAT_FILL = 77, + ICON_SHUFFLE_FILL = 78, + ICON_EMPTYBOX_SMALL = 79, + ICON_BOX = 80, + ICON_BOX_TOP = 81, + ICON_BOX_TOP_RIGHT = 82, + ICON_BOX_RIGHT = 83, + ICON_BOX_BOTTOM_RIGHT = 84, + ICON_BOX_BOTTOM = 85, + ICON_BOX_BOTTOM_LEFT = 86, + ICON_BOX_LEFT = 87, + ICON_BOX_TOP_LEFT = 88, + ICON_BOX_CENTER = 89, + ICON_BOX_CIRCLE_MASK = 90, + ICON_POT = 91, + ICON_ALPHA_MULTIPLY = 92, + ICON_ALPHA_CLEAR = 93, + ICON_DITHERING = 94, + ICON_MIPMAPS = 95, + ICON_BOX_GRID = 96, + ICON_GRID = 97, + ICON_BOX_CORNERS_SMALL = 98, + ICON_BOX_CORNERS_BIG = 99, + ICON_FOUR_BOXES = 100, + ICON_GRID_FILL = 101, + ICON_BOX_MULTISIZE = 102, + ICON_ZOOM_SMALL = 103, + ICON_ZOOM_MEDIUM = 104, + ICON_ZOOM_BIG = 105, + ICON_ZOOM_ALL = 106, + ICON_ZOOM_CENTER = 107, + ICON_BOX_DOTS_SMALL = 108, + ICON_BOX_DOTS_BIG = 109, + ICON_BOX_CONCENTRIC = 110, + ICON_BOX_GRID_BIG = 111, + ICON_OK_TICK = 112, + ICON_CROSS = 113, + ICON_ARROW_LEFT = 114, + ICON_ARROW_RIGHT = 115, + ICON_ARROW_DOWN = 116, + ICON_ARROW_UP = 117, + ICON_ARROW_LEFT_FILL = 118, + ICON_ARROW_RIGHT_FILL = 119, + ICON_ARROW_DOWN_FILL = 120, + ICON_ARROW_UP_FILL = 121, + ICON_AUDIO = 122, + ICON_FX = 123, + ICON_WAVE = 124, + ICON_WAVE_SINUS = 125, + ICON_WAVE_SQUARE = 126, + ICON_WAVE_TRIANGULAR = 127, + ICON_CROSS_SMALL = 128, + ICON_PLAYER_PREVIOUS = 129, + ICON_PLAYER_PLAY_BACK = 130, + ICON_PLAYER_PLAY = 131, + ICON_PLAYER_PAUSE = 132, + ICON_PLAYER_STOP = 133, + ICON_PLAYER_NEXT = 134, + ICON_PLAYER_RECORD = 135, + ICON_MAGNET = 136, + ICON_LOCK_CLOSE = 137, + ICON_LOCK_OPEN = 138, + ICON_CLOCK = 139, + ICON_TOOLS = 140, + ICON_GEAR = 141, + ICON_GEAR_BIG = 142, + ICON_BIN = 143, + ICON_HAND_POINTER = 144, + ICON_LASER = 145, + ICON_COIN = 146, + ICON_EXPLOSION = 147, + ICON_1UP = 148, + ICON_PLAYER = 149, + ICON_PLAYER_JUMP = 150, + ICON_KEY = 151, + ICON_DEMON = 152, + ICON_TEXT_POPUP = 153, + ICON_GEAR_EX = 154, + ICON_CRACK = 155, + ICON_CRACK_POINTS = 156, + ICON_STAR = 157, + ICON_DOOR = 158, + ICON_EXIT = 159, + ICON_MODE_2D = 160, + ICON_MODE_3D = 161, + ICON_CUBE = 162, + ICON_CUBE_FACE_TOP = 163, + ICON_CUBE_FACE_LEFT = 164, + ICON_CUBE_FACE_FRONT = 165, + ICON_CUBE_FACE_BOTTOM = 166, + ICON_CUBE_FACE_RIGHT = 167, + ICON_CUBE_FACE_BACK = 168, + ICON_CAMERA = 169, + ICON_SPECIAL = 170, + ICON_LINK_NET = 171, + ICON_LINK_BOXES = 172, + ICON_LINK_MULTI = 173, + ICON_LINK = 174, + ICON_LINK_BROKE = 175, + ICON_TEXT_NOTES = 176, + ICON_NOTEBOOK = 177, + ICON_SUITCASE = 178, + ICON_SUITCASE_ZIP = 179, + ICON_MAILBOX = 180, + ICON_MONITOR = 181, + ICON_PRINTER = 182, + ICON_PHOTO_CAMERA = 183, + ICON_PHOTO_CAMERA_FLASH = 184, + ICON_HOUSE = 185, + ICON_HEART = 186, + ICON_CORNER = 187, + ICON_VERTICAL_BARS = 188, + ICON_VERTICAL_BARS_FILL = 189, + ICON_LIFE_BARS = 190, + ICON_INFO = 191, + ICON_CROSSLINE = 192, + ICON_HELP = 193, + ICON_FILETYPE_ALPHA = 194, + ICON_FILETYPE_HOME = 195, + ICON_LAYERS_VISIBLE = 196, + ICON_LAYERS = 197, + ICON_WINDOW = 198, + ICON_HIDPI = 199, + ICON_FILETYPE_BINARY = 200, + ICON_HEX = 201, + ICON_SHIELD = 202, + ICON_FILE_NEW = 203, + ICON_FOLDER_ADD = 204, + ICON_ALARM = 205, + ICON_CPU = 206, + ICON_ROM = 207, + ICON_STEP_OVER = 208, + ICON_STEP_INTO = 209, + ICON_STEP_OUT = 210, + ICON_RESTART = 211, + ICON_BREAKPOINT_ON = 212, + ICON_BREAKPOINT_OFF = 213, + ICON_BURGER_MENU = 214, + ICON_CASE_SENSITIVE = 215, + ICON_REG_EXP = 216, + ICON_FOLDER = 217, + ICON_FILE = 218, + ICON_SAND_TIMER = 219, + ICON_WARNING = 220, + ICON_HELP_BOX = 221, + ICON_INFO_BOX = 222, + ICON_PRIORITY = 223, + ICON_LAYERS_ISO = 224, + ICON_LAYERS2 = 225, + ICON_MLAYERS = 226, + ICON_MAPS = 227, + ICON_HOT = 228, + ICON_LABEL = 229, + ICON_NAME_ID = 230, + ICON_SLICING = 231, + ICON_MANUAL_CONTROL = 232, + ICON_COLLISION = 233, + ICON_CIRCLE_ADD = 234, + ICON_CIRCLE_ADD_FILL = 235, + ICON_CIRCLE_WARNING = 236, + ICON_CIRCLE_WARNING_FILL = 237, + ICON_BOX_MORE = 238, + ICON_BOX_MORE_FILL = 239, + ICON_BOX_MINUS = 240, + ICON_BOX_MINUS_FILL = 241, + ICON_UNION = 242, + ICON_INTERSECTION = 243, + ICON_DIFFERENCE = 244, + ICON_SPHERE = 245, + ICON_CYLINDER = 246, + ICON_CONE = 247, + ICON_ELLIPSOID = 248, + ICON_CAPSULE = 249, + ICON_250 = 250, + ICON_251 = 251, + ICON_252 = 252, + ICON_253 = 253, + ICON_254 = 254, + ICON_255 = 255 +} GuiIconName; +#endif + +#endif + +#if defined(__cplusplus) +} // Prevents name mangling of functions +#endif + +#endif // RAYGUI_H + +/*********************************************************************************** +* +* RAYGUI IMPLEMENTATION +* +************************************************************************************/ + +#if defined(RAYGUI_IMPLEMENTATION) + +#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] +#include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() +#include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] +#include // Required for: roundf() [GuiColorPicker()] +#include // Required for: isspace() [GuiTextBox()] + +// Allow custom memory allocators +#if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE) + #if !defined(RAYGUI_MALLOC) || !defined(RAYGUI_CALLOC) || !defined(RAYGUI_FREE) + #error "RAYGUI: if RAYGUI_MALLOC, RAYGUI_CALLOC, or RAYGUI_FREE is customized, all three must be customized" + #endif +#else + #include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()] + + #define RAYGUI_MALLOC(sz) malloc(sz) + #define RAYGUI_CALLOC(n,sz) calloc(n,sz) + #define RAYGUI_FREE(p) free(p) +#endif + +#ifdef __cplusplus + #define RAYGUI_CLITERAL(name) name +#else + #define RAYGUI_CLITERAL(name) (name) +#endif + +// Check if two rectangles are equal, used to validate a slider bounds as an id +#ifndef CHECK_BOUNDS_ID + #define CHECK_BOUNDS_ID(src, dst) (((int)src.x == (int)dst.x) && ((int)src.y == (int)dst.y) && ((int)src.width == (int)dst.width) && ((int)src.height == (int)dst.height)) +#endif + +#if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) + +// Embedded icons, no external file provided +#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) +#define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons +#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id + +// Icons data is defined by bit array (every bit represents one pixel) +// Those arrays are stored as unsigned int data arrays, so, +// every array element defines 32 pixels (bits) of information +// One icon is defined by 8 int, (8 int*32 bit = 256 bit = 16*16 pixels) +// NOTE: Number of elemens depend on RAYGUI_ICON_SIZE (by default 16x16 pixels) +#define RAYGUI_ICON_DATA_ELEMENTS (RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32) + +//---------------------------------------------------------------------------------- +// Icons data for all gui possible icons (allocated on data segment by default) +// +// NOTE 1: Every icon is codified in binary form, using 1 bit per pixel, so, +// every 16x16 icon requires 8 integers (16*16/32) to be stored +// +// NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(), +// but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS +// +// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +//---------------------------------------------------------------------------------- +static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE + 0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // ICON_FOLDER_FILE_OPEN + 0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // ICON_FILE_SAVE_CLASSIC + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // ICON_FOLDER_OPEN + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // ICON_FOLDER_SAVE + 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // ICON_FILE_OPEN + 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // ICON_FILE_SAVE + 0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // ICON_FILE_EXPORT + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // ICON_FILE_ADD + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // ICON_FILE_DELETE + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_FILETYPE_TEXT + 0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // ICON_FILETYPE_AUDIO + 0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // ICON_FILETYPE_IMAGE + 0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PLAY + 0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // ICON_FILETYPE_VIDEO + 0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // ICON_FILETYPE_INFO + 0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // ICON_FILE_COPY + 0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // ICON_FILE_CUT + 0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // ICON_FILE_PASTE + 0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_CURSOR_HAND + 0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // ICON_CURSOR_POINTER + 0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // ICON_CURSOR_CLASSIC + 0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // ICON_PENCIL + 0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // ICON_PENCIL_BIG + 0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // ICON_BRUSH_CLASSIC + 0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // ICON_BRUSH_PAINTER + 0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // ICON_WATER_DROP + 0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // ICON_COLOR_PICKER + 0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // ICON_RUBBER + 0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // ICON_COLOR_BUCKET + 0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // ICON_TEXT_T + 0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // ICON_TEXT_A + 0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // ICON_SCALE + 0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // ICON_RESIZE + 0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_POINT + 0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_BILINEAR + 0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // ICON_CROP + 0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // ICON_CROP_ALPHA + 0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // ICON_SQUARE_TOGGLE + 0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // ICON_SYMMETRY + 0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // ICON_SYMMETRY_HORIZONTAL + 0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // ICON_SYMMETRY_VERTICAL + 0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // ICON_LENS + 0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // ICON_LENS_BIG + 0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // ICON_EYE_ON + 0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // ICON_EYE_OFF + 0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // ICON_FILTER_TOP + 0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // ICON_FILTER + 0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_POINT + 0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL + 0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG + 0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // ICON_TARGET_MOVE + 0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // ICON_CURSOR_MOVE + 0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // ICON_CURSOR_SCALE + 0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // ICON_CURSOR_SCALE_RIGHT + 0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // ICON_CURSOR_SCALE_LEFT + 0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO + 0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO + 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // ICON_REREDO + 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // ICON_MUTATE + 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // ICON_ROTATE + 0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // ICON_REPEAT + 0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // ICON_SHUFFLE + 0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // ICON_EMPTYBOX + 0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // ICON_TARGET + 0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL_FILL + 0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG_FILL + 0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // ICON_TARGET_MOVE_FILL + 0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // ICON_CURSOR_MOVE_FILL + 0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // ICON_CURSOR_SCALE_FILL + 0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // ICON_CURSOR_SCALE_RIGHT_FILL + 0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // ICON_CURSOR_SCALE_LEFT_FILL + 0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO_FILL + 0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO_FILL + 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // ICON_REREDO_FILL + 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // ICON_MUTATE_FILL + 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // ICON_ROTATE_FILL + 0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // ICON_REPEAT_FILL + 0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // ICON_SHUFFLE_FILL + 0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // ICON_EMPTYBOX_SMALL + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX + 0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP + 0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // ICON_BOX_BOTTOM_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // ICON_BOX_BOTTOM + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // ICON_BOX_BOTTOM_LEFT + 0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_LEFT + 0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_LEFT + 0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_CENTER + 0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // ICON_BOX_CIRCLE_MASK + 0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // ICON_POT + 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // ICON_ALPHA_MULTIPLY + 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // ICON_ALPHA_CLEAR + 0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // ICON_DITHERING + 0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // ICON_MIPMAPS + 0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // ICON_BOX_GRID + 0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // ICON_GRID + 0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // ICON_BOX_CORNERS_SMALL + 0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // ICON_BOX_CORNERS_BIG + 0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // ICON_FOUR_BOXES + 0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // ICON_GRID_FILL + 0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // ICON_BOX_MULTISIZE + 0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_SMALL + 0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_MEDIUM + 0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // ICON_ZOOM_BIG + 0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // ICON_ZOOM_ALL + 0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // ICON_ZOOM_CENTER + 0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // ICON_BOX_DOTS_SMALL + 0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // ICON_BOX_DOTS_BIG + 0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // ICON_BOX_CONCENTRIC + 0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // ICON_BOX_GRID_BIG + 0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // ICON_OK_TICK + 0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // ICON_CROSS + 0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // ICON_ARROW_LEFT + 0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // ICON_ARROW_RIGHT + 0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // ICON_ARROW_DOWN + 0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP + 0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // ICON_ARROW_LEFT_FILL + 0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // ICON_ARROW_RIGHT_FILL + 0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // ICON_ARROW_DOWN_FILL + 0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP_FILL + 0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // ICON_AUDIO + 0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // ICON_FX + 0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // ICON_WAVE + 0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // ICON_WAVE_SINUS + 0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // ICON_WAVE_SQUARE + 0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // ICON_WAVE_TRIANGULAR + 0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // ICON_CROSS_SMALL + 0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // ICON_PLAYER_PREVIOUS + 0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // ICON_PLAYER_PLAY_BACK + 0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // ICON_PLAYER_PLAY + 0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // ICON_PLAYER_PAUSE + 0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // ICON_PLAYER_STOP + 0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // ICON_PLAYER_NEXT + 0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // ICON_PLAYER_RECORD + 0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // ICON_MAGNET + 0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_CLOSE + 0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_OPEN + 0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // ICON_CLOCK + 0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // ICON_TOOLS + 0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // ICON_GEAR + 0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // ICON_GEAR_BIG + 0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // ICON_BIN + 0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // ICON_HAND_POINTER + 0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // ICON_LASER + 0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // ICON_COIN + 0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // ICON_EXPLOSION + 0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // ICON_1UP + 0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // ICON_PLAYER + 0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // ICON_PLAYER_JUMP + 0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // ICON_KEY + 0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // ICON_DEMON + 0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // ICON_TEXT_POPUP + 0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // ICON_GEAR_EX + 0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK + 0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK_POINTS + 0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // ICON_STAR + 0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // ICON_DOOR + 0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // ICON_EXIT + 0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // ICON_MODE_2D + 0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // ICON_MODE_3D + 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE + 0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_TOP + 0x7fe00000, 0x50386030, 0x47c2483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // ICON_CUBE_FACE_LEFT + 0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // ICON_CUBE_FACE_FRONT + 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3bf27be2, 0x0bfe1bfa, 0x000007fe, // ICON_CUBE_FACE_BOTTOM + 0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // ICON_CUBE_FACE_RIGHT + 0x7fe00000, 0x6fe85ff0, 0x781e77e4, 0x7be27be2, 0x7be27be2, 0x24127be2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_BACK + 0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // ICON_CAMERA + 0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // ICON_SPECIAL + 0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // ICON_LINK_NET + 0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // ICON_LINK_BOXES + 0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // ICON_LINK_MULTI + 0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // ICON_LINK + 0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // ICON_LINK_BROKE + 0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_TEXT_NOTES + 0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // ICON_NOTEBOOK + 0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // ICON_SUITCASE + 0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // ICON_SUITCASE_ZIP + 0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // ICON_MAILBOX + 0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // ICON_MONITOR + 0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // ICON_PRINTER + 0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA + 0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA_FLASH + 0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // ICON_HOUSE + 0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // ICON_HEART + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // ICON_CORNER + 0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // ICON_VERTICAL_BARS + 0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // ICON_VERTICAL_BARS_FILL + 0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // ICON_LIFE_BARS + 0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // ICON_INFO + 0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // ICON_CROSSLINE + 0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // ICON_HELP + 0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // ICON_FILETYPE_ALPHA + 0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // ICON_FILETYPE_HOME + 0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS_VISIBLE + 0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS + 0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_WINDOW + 0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // ICON_HIDPI + 0x3ff00000, 0x201c2010, 0x2a842e84, 0x2e842a84, 0x2ba42004, 0x2aa42aa4, 0x20042ba4, 0x00003ffc, // ICON_FILETYPE_BINARY + 0x00000000, 0x00000000, 0x00120012, 0x4a5e4bd2, 0x485233d2, 0x00004bd2, 0x00000000, 0x00000000, // ICON_HEX + 0x01800000, 0x381c0660, 0x23c42004, 0x23c42044, 0x13c82204, 0x08101008, 0x02400420, 0x00000180, // ICON_SHIELD + 0x007e0000, 0x20023fc2, 0x40227fe2, 0x400a403a, 0x400a400a, 0x400a400a, 0x4008400e, 0x00007ff8, // ICON_FILE_NEW + 0x00000000, 0x0042007e, 0x40027fc2, 0x44024002, 0x5f024402, 0x44024402, 0x7ffe4002, 0x00000000, // ICON_FOLDER_ADD + 0x44220000, 0x12482244, 0xf3cf0000, 0x14280420, 0x48122424, 0x08100810, 0x1ff81008, 0x03c00420, // ICON_ALARM + 0x0aa00000, 0x1ff80aa0, 0x1068700e, 0x1008706e, 0x1008700e, 0x1008700e, 0x0aa01ff8, 0x00000aa0, // ICON_CPU + 0x07e00000, 0x04201db8, 0x04a01c38, 0x04a01d38, 0x04a01d38, 0x04a01d38, 0x04201d38, 0x000007e0, // ICON_ROM + 0x00000000, 0x03c00000, 0x3c382ff0, 0x3c04380c, 0x01800000, 0x03c003c0, 0x00000180, 0x00000000, // ICON_STEP_OVER + 0x01800000, 0x01800180, 0x01800180, 0x03c007e0, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_INTO + 0x01800000, 0x07e003c0, 0x01800180, 0x01800180, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_OUT + 0x00000000, 0x0ff003c0, 0x181c1c34, 0x303c301c, 0x30003000, 0x1c301800, 0x03c00ff0, 0x00000000, // ICON_RESTART + 0x00000000, 0x00000000, 0x07e003c0, 0x0ff00ff0, 0x0ff00ff0, 0x03c007e0, 0x00000000, 0x00000000, // ICON_BREAKPOINT_ON + 0x00000000, 0x00000000, 0x042003c0, 0x08100810, 0x08100810, 0x03c00420, 0x00000000, 0x00000000, // ICON_BREAKPOINT_OFF + 0x00000000, 0x00000000, 0x1ff81ff8, 0x1ff80000, 0x00001ff8, 0x1ff81ff8, 0x00000000, 0x00000000, // ICON_BURGER_MENU + 0x00000000, 0x00000000, 0x00880070, 0x0c880088, 0x1e8810f8, 0x3e881288, 0x00000000, 0x00000000, // ICON_CASE_SENSITIVE + 0x00000000, 0x02000000, 0x07000a80, 0x07001fc0, 0x02000a80, 0x00300030, 0x00000000, 0x00000000, // ICON_REG_EXP + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_FOLDER + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x00003ffc, // ICON_FILE + 0x1ff00000, 0x20082008, 0x17d02fe8, 0x05400ba0, 0x09200540, 0x23881010, 0x2fe827c8, 0x00001ff0, // ICON_SAND_TIMER + 0x01800000, 0x02400240, 0x05a00420, 0x09900990, 0x11881188, 0x21842004, 0x40024182, 0x00003ffc, // ICON_WARNING + 0x7ffe0000, 0x4ff24002, 0x4c324ff2, 0x4f824c02, 0x41824f82, 0x41824002, 0x40024182, 0x00007ffe, // ICON_HELP_BOX + 0x7ffe0000, 0x41824002, 0x40024182, 0x41824182, 0x41824182, 0x41824182, 0x40024182, 0x00007ffe, // ICON_INFO_BOX + 0x01800000, 0x04200240, 0x10080810, 0x7bde2004, 0x0a500a50, 0x08500bd0, 0x08100850, 0x00000ff0, // ICON_PRIORITY + 0x01800000, 0x18180660, 0x80016006, 0x98196006, 0x99996666, 0x19986666, 0x01800660, 0x00000000, // ICON_LAYERS_ISO + 0x07fe0000, 0x1c020402, 0x74021402, 0x54025402, 0x54025402, 0x500857fe, 0x40205ff8, 0x00007fe0, // ICON_LAYERS2 + 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS + 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS + 0x04200000, 0x1cf00c60, 0x11f019f0, 0x0f3807b8, 0x1e3c0f3c, 0x1c1c1e1c, 0x1e3c1c1c, 0x00000f70, // ICON_HOT + 0x00000000, 0x20803f00, 0x2a202e40, 0x20082e10, 0x08021004, 0x02040402, 0x00900108, 0x00000060, // ICON_LABEL + 0x00000000, 0x042007e0, 0x47e27c3e, 0x4ffa4002, 0x47fa4002, 0x4ffa4002, 0x7ffe4002, 0x00000000, // ICON_NAME_ID + 0x7fe00000, 0x402e4020, 0x43ce5e0a, 0x40504078, 0x438e4078, 0x402e5e0a, 0x7fe04020, 0x00000000, // ICON_SLICING + 0x00000000, 0x40027ffe, 0x47c24002, 0x55425d42, 0x55725542, 0x50125552, 0x10105016, 0x00001ff0, // ICON_MANUAL_CONTROL + 0x7ffe0000, 0x43c24002, 0x48124422, 0x500a500a, 0x500a500a, 0x44224812, 0x400243c2, 0x00007ffe, // ICON_COLLISION + 0x03c00000, 0x10080c30, 0x21842184, 0x4ff24182, 0x41824ff2, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_ADD + 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x700e7e7e, 0x7e7e700e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_ADD_FILL + 0x03c00000, 0x10080c30, 0x21842184, 0x41824182, 0x40024182, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_WARNING + 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x7e7e7e7e, 0x7ffe7e7e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_WARNING_FILL + 0x00000000, 0x10041ffc, 0x10841004, 0x13e41084, 0x10841084, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MORE + 0x00000000, 0x1ffc1ffc, 0x1f7c1ffc, 0x1c1c1f7c, 0x1f7c1f7c, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MORE_FILL + 0x00000000, 0x1ffc1ffc, 0x1ffc1ffc, 0x1c1c1ffc, 0x1ffc1ffc, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS + 0x00000000, 0x10041ffc, 0x10041004, 0x13e41004, 0x10041004, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS_FILL + 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x55766eba, 0x55766eaa, 0x55606ffe, 0x55606aa0, 0x00007fe0, // ICON_UNION + 0x07fe0000, 0x04020402, 0x7fe20402, 0x456246a2, 0x456246a2, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_INTERSECTION + 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x4436442a, 0x4436442a, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_DIFFERENCE + 0x03c00000, 0x10080c30, 0x20042004, 0x60064002, 0x47e2581a, 0x20042004, 0x0c301008, 0x000003c0, // ICON_SPHERE + 0x03e00000, 0x08080410, 0x0c180808, 0x08080be8, 0x08080808, 0x08080808, 0x04100808, 0x000003e0, // ICON_CYLINDER + 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE + 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID + 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255 +}; + +// NOTE: A pointer to current icons array should be defined +static unsigned int *guiIconsPtr = guiIcons; + +#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS + +#ifndef RAYGUI_ICON_SIZE + #define RAYGUI_ICON_SIZE 0 +#endif + +// WARNING: Those values define the total size of the style data array, +// if changed, previous saved styles could become incompatible +#define RAYGUI_MAX_CONTROLS 16 // Maximum number of controls +#define RAYGUI_MAX_PROPS_BASE 16 // Maximum number of base properties +#define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties + +//---------------------------------------------------------------------------------- +// Module Types and Structures Definition +//---------------------------------------------------------------------------------- +// RayGui control property style color element +typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static GuiState guiState = STATE_NORMAL; // RayGui global state, if !STATE_NORMAL, forces defined state + +static Font guiFont = { 0 }; // RayGui current font (WARNING: highly coupled to raylib) +static bool guiLocked = false; // RayGui lock state (no inputs processed) +static float guiAlpha = 1.0f; // RayGui controls transparency + +static unsigned int guiIconScale = 1; // RayGui icon default scale (if icons enabled) + +static bool guiTooltip = false; // Tooltip enabled/disabled +static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) + +static bool guiControlExclusiveMode = false; // RayGui control exclusive mode (no inputs processed except current control) +static Rectangle guiControlExclusiveRec = { 0 }; // RayGui control exclusive bounds rectangle, used as an unique identifier + +static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*() +//static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking +static int autoCursorCounter = 0; // Frame counter for automatic repeated cursor movement on key-down (cooldown and delay) + +//---------------------------------------------------------------------------------- +// Style data array for all gui style properties (allocated on data segment by default) +// +// NOTE 1: First set of BASE properties are generic to all controls but could be individually +// overwritten per control, first set of EXTENDED properties are generic to all controls and +// can not be overwritten individually but custom EXTENDED properties can be used by control +// +// NOTE 2: A new style set could be loaded over this array using GuiLoadStyle(), +// but default gui style could always be recovered with GuiLoadStyleDefault() +// +// guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB +//---------------------------------------------------------------------------------- +static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)] = { 0 }; + +static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization + +//---------------------------------------------------------------------------------- +// Standalone Mode Functions Declaration +// +// NOTE: raygui depend on some raylib input and drawing functions +// To use raygui as standalone library, below functions must be defined by the user +//---------------------------------------------------------------------------------- +#if defined(RAYGUI_STANDALONE) + +#define KEY_RIGHT 262 +#define KEY_LEFT 263 +#define KEY_DOWN 264 +#define KEY_UP 265 +#define KEY_BACKSPACE 259 +#define KEY_ENTER 257 + +#define MOUSE_LEFT_BUTTON 0 + +// Input required functions +//------------------------------------------------------------------------------- +static Vector2 GetMousePosition(void); +static float GetMouseWheelMove(void); +static bool IsMouseButtonDown(int button); +static bool IsMouseButtonPressed(int button); +static bool IsMouseButtonReleased(int button); + +static bool IsKeyDown(int key); +static bool IsKeyPressed(int key); +static int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() +//------------------------------------------------------------------------------- + +// Drawing required functions +//------------------------------------------------------------------------------- +static void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle() +static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() +//------------------------------------------------------------------------------- + +// Text required functions +//------------------------------------------------------------------------------- +static Font GetFontDefault(void); // -- GuiLoadStyleDefault() +static Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle(), load font + +static Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image +static void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization) + +static char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data +static void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data + +static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs + +static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list +static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list + +static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() +//------------------------------------------------------------------------------- + +// raylib functions already implemented in raygui +//------------------------------------------------------------------------------- +static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +static int ColorToInt(Color color); // Returns hexadecimal value for a Color +static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle +static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' +static char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings +static int TextToInteger(const char *text); // Get integer value from text +static float TextToFloat(const char *text); // Get float value from text + +static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text +static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) + +static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient +//------------------------------------------------------------------------------- + +#endif // RAYGUI_STANDALONE + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- +static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) + +static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds +static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor + +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // RayGui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // RayGui draw rectangle using default raygui style + +static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings +static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB +static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV + +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() +static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position + +static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor + +//---------------------------------------------------------------------------------- +// RayGui Setup Functions Definition +//---------------------------------------------------------------------------------- +// Enable gui global state +// NOTE: Checking for STATE_DISABLED to avoid messing custom global state setups +void GuiEnable(void) { if (guiState == STATE_DISABLED) guiState = STATE_NORMAL; } + +// Disable gui global state +// NOTE: Checking for STATE_NORMAL to avoid messing custom global state setups +void GuiDisable(void) { if (guiState == STATE_NORMAL) guiState = STATE_DISABLED; } + +// Lock gui global state +void GuiLock(void) { guiLocked = true; } + +// Unlock gui global state +void GuiUnlock(void) { guiLocked = false; } + +// Check if gui is locked (global state) +bool GuiIsLocked(void) { return guiLocked; } + +// Set gui controls alpha global state +void GuiSetAlpha(float alpha) +{ + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + guiAlpha = alpha; +} + +// Set gui state (global state) +void GuiSetState(int state) { guiState = (GuiState)state; } + +// Get gui state (global state) +int GuiGetState(void) { return guiState; } + +// Set custom gui font +// NOTE: Font loading/unloading is external to raygui +void GuiSetFont(Font font) +{ + if (font.texture.id > 0) + { + // NOTE: If a font is tried to be set but default style has not been lazily loaded first, + // it will be overwritten, so default style loading needs to be forced first + if (!guiStyleLoaded) GuiLoadStyleDefault(); + + guiFont = font; + } +} + +// Get custom gui font +Font GuiGetFont(void) +{ + return guiFont; +} + +// Set control style property value +void GuiSetStyle(int control, int property, int value) +{ + if (!guiStyleLoaded) GuiLoadStyleDefault(); + guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; + + // Default properties are propagated to all controls + if ((control == 0) && (property < RAYGUI_MAX_PROPS_BASE)) + { + for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) guiStyle[i*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; + } +} + +// Get control style property value +int GuiGetStyle(int control, int property) +{ + if (!guiStyleLoaded) GuiLoadStyleDefault(); + return guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property]; +} + +//---------------------------------------------------------------------------------- +// RayGui Controls Functions Definition +//---------------------------------------------------------------------------------- + +// Window Box control +int GuiWindowBox(Rectangle bounds, const char *title) +{ + // Window title bar height (including borders) + // NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox() + #if !defined(RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT) + #define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24 + #endif + + #if !defined(RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT) + #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18 + #endif + + int result = 0; + //GuiState state = guiState; + + int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT; + int statusBorderWidth = GuiGetStyle(STATUSBAR, BORDER_WIDTH); + + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight }; + if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f; + + const float vPadding = statusBarHeight/2.0f - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT/2.0f; + Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - (float)statusBorderWidth, bounds.width, bounds.height - (float)statusBarHeight + (float)statusBorderWidth }; + Rectangle closeButtonRec = { statusBar.x + statusBar.width - (float)statusBorderWidth - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT - vPadding, + statusBar.y + vPadding, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT }; + + // Update control + //-------------------------------------------------------------------- + // NOTE: Logic is directly managed by button + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiPanel(windowPanel, NULL); // Draw window base + GuiStatusBar(statusBar, title); // Draw window header as status bar + + // Draw window close button + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + result = GuiButton(closeButtonRec, "x"); +#else + result = GuiButton(closeButtonRec, GuiIconText(ICON_CROSS_SMALL, NULL)); +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + //-------------------------------------------------------------------- + + return result; // Window close button clicked: result = 1 +} + +// Group Box control with text name +int GuiGroupBox(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_GROUPBOX_LINE_THICK) + #define RAYGUI_GROUPBOX_LINE_THICK 1 + #endif + + int result = 0; + GuiState state = guiState; + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + + GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text); + //-------------------------------------------------------------------- + + return result; +} + +// Line control +int GuiLine(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_LINE_MARGIN_TEXT) + #define RAYGUI_LINE_MARGIN_TEXT 12 + #endif + #if !defined(RAYGUI_LINE_TEXT_PADDING) + #define RAYGUI_LINE_TEXT_PADDING 4 + #endif + + int result = 0; + GuiState state = guiState; + + Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); + + // Draw control + //-------------------------------------------------------------------- + if (text == NULL) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, bounds.width, 1 }, 0, BLANK, color); + else + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = bounds.height; + textBounds.x = bounds.x + RAYGUI_LINE_MARGIN_TEXT; + textBounds.y = bounds.y; + + // Draw line with embedded text label: "--- text --------------" + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color); + GuiDrawText(text, textBounds, TEXT_ALIGN_LEFT, color); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + 12 + textBounds.width + 4, bounds.y + bounds.height/2, bounds.width - textBounds.width - RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color); + } + //-------------------------------------------------------------------- + + return result; +} + +// Panel control +int GuiPanel(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_PANEL_BORDER_WIDTH) + #define RAYGUI_PANEL_BORDER_WIDTH 1 + #endif + + int result = 0; + GuiState state = guiState; + + // Text will be drawn as a header bar (if provided) + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }; + if ((text != NULL) && (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f)) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f; + + if (text != NULL) + { + // Move panel bounds after the header bar + bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + } + + // Draw control + //-------------------------------------------------------------------- + if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + + GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)), + GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR))); + //-------------------------------------------------------------------- + + return result; +} + +// Tab Bar control +// NOTE: Using GuiToggle() for the TABS +int GuiTabBar(Rectangle bounds, char **text, int count, int *active) +{ + #define RAYGUI_TABBAR_ITEM_WIDTH 148 + + int result = -1; + //GuiState state = guiState; + + Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height }; + + if (*active < 0) *active = 0; + else if (*active > count - 1) *active = count - 1; + + int offsetX = 0; // Required in case tabs go out of screen + offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth(); + if (offsetX < 0) offsetX = 0; + + bool toggle = false; // Required for individual toggles + + // Draw control + //-------------------------------------------------------------------- + for (int i = 0; i < count; i++) + { + tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX; + + if (tabBounds.x < GetScreenWidth()) + { + // Draw tabs as toggle controls + int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); + int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TOGGLE, TEXT_PADDING, 8); + + if (i == (*active)) + { + toggle = true; + GuiToggle(tabBounds, text[i], &toggle); + } + else + { + toggle = false; + GuiToggle(tabBounds, text[i], &toggle); + if (toggle) *active = i; + } + + // Close tab with middle mouse button pressed + if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; + + GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); + + // Draw tab close button + // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i; +#else + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i; +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + } + } + + // Draw tab-bar bottom line + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL))); + //-------------------------------------------------------------------- + + return result; // Return as result the current TAB closing requested +} + +// Scroll Panel control +int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view) +{ + #define RAYGUI_MIN_SCROLLBAR_WIDTH 40 + #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 + #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 + + int result = 0; + GuiState state = guiState; + + Rectangle temp = { 0 }; + if (view == NULL) view = &temp; + + Vector2 scrollPos = { 0.0f, 0.0f }; + if (scroll != NULL) scrollPos = *scroll; + + // Text will be drawn as a header bar (if provided) + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }; + if (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f; + + if (text != NULL) + { + // Move panel bounds after the header bar + bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + 1; + } + + bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; + bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; + + // Recheck to account for the other scrollbar being visible + if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; + if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; + + int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; + int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; + Rectangle horizontalScrollBar = { + (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)horizontalScrollBarWidth + }; + Rectangle verticalScrollBar = { + (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), + (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)verticalScrollBarWidth, + (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Make sure scroll bars have a minimum width/height + if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH; + if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT; + + // Calculate view area (area without the scrollbars) + *view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? + RAYGUI_CLITERAL(Rectangle){ bounds.x + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth } : + RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth }; + + // Clip view area to the actual content size + if (view->width > content.width) view->width = content.width; + if (view->height > content.height) view->height = content.height; + + float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); + float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); + float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f; + float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + +#if defined(SUPPORT_SCROLLBAR_KEY_INPUT) + if (hasHorizontalScrollBar) + { + if (GUI_KEY_DOWN(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (GUI_KEY_DOWN(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + } + + if (hasVerticalScrollBar) + { + if (GUI_KEY_DOWN(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (GUI_KEY_DOWN(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + } +#endif + float scrollDelta = GUI_SCROLL_DELTA; + + // Set scrolling speed with mouse wheel based on ratio between bounds and content + Vector2 scrollSpeed = { content.width/bounds.width, content.height/bounds.height }; + if (scrollSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) scrollSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + if (scrollSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) scrollSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + + // Horizontal and vertical scrolling with mouse wheel + if (hasHorizontalScrollBar && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_LEFT_SHIFT))) scrollPos.x += scrollDelta*scrollSpeed.x; + else scrollPos.y += scrollDelta*scrollSpeed.y; // Vertical scroll + } + } + + // Normalize scroll values + if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin; + if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax; + if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin; + if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + + GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + + // Save size of the scrollbar slider + const int slider = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + + // Draw horizontal scrollbar if visible + if (hasHorizontalScrollBar) + { + // Change scrollbar slider size to show the diff in size between the content width and the widget width + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/(int)content.width)*((int)bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth))); + scrollPos.x = (float)-GuiScrollBar(horizontalScrollBar, (int)-scrollPos.x, (int)horizontalMin, (int)horizontalMax); + } + else scrollPos.x = 0.0f; + + // Draw vertical scrollbar if visible + if (hasVerticalScrollBar) + { + // Change scrollbar slider size to show the diff in size between the content height and the widget height + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/(int)content.height)*((int)bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth))); + scrollPos.y = (float)-GuiScrollBar(verticalScrollBar, (int)-scrollPos.y, (int)verticalMin, (int)verticalMax); + } + else scrollPos.y = 0.0f; + + // Draw detail corner rectangle if both scroll bars are visible + if (hasHorizontalScrollBar && hasVerticalScrollBar) + { + Rectangle corner = { (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) + 2) : (horizontalScrollBar.x + horizontalScrollBar.width + 2), verticalScrollBar.y + verticalScrollBar.height + 2, (float)horizontalScrollBarWidth - 4, (float)verticalScrollBarWidth - 4 }; + GuiDrawRectangle(corner, 0, BLANK, GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3)))); + } + + // Draw scrollbar lines depending on current state + GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK); + + // Set scrollbar slider size back to the way it was before + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider); + //-------------------------------------------------------------------- + + if (scroll != NULL) *scroll = scrollPos; + + return result; +} + +// Label control +int GuiLabel(Rectangle bounds, const char *text) +{ + int result = 0; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + //... + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Button control, returns true when clicked +int GuiButton(Rectangle bounds, const char *text) +{ + int result = 0; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = 1; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), GetColor(GuiGetStyle(BUTTON, BASE + (state*3)))); + GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), GetColor(GuiGetStyle(BUTTON, TEXT + (state*3)))); + + if (state == STATE_FOCUSED) GuiTooltip(bounds); + //------------------------------------------------------------------ + + return result; // Button pressed: result = 1 +} + +// Label button control +int GuiLabelButton(Rectangle bounds, const char *text) +{ + GuiState state = guiState; + bool pressed = false; + + // NOTE: Force bounds.width to be all text + float textWidth = (float)GuiGetTextWidth(text); + if ((bounds.width - 2*GuiGetStyle(LABEL, BORDER_WIDTH) - 2*GuiGetStyle(LABEL, TEXT_PADDING)) < textWidth) bounds.width = textWidth + 2*GuiGetStyle(LABEL, BORDER_WIDTH) + 2*GuiGetStyle(LABEL, TEXT_PADDING) + 2; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) pressed = true; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return pressed; +} + +// Toggle Button control +int GuiToggle(Rectangle bounds, const char *text, bool *active) +{ + int result = 0; + GuiState state = guiState; + + bool temp = false; + if (active == NULL) active = &temp; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check toggle button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else if (GUI_BUTTON_RELEASED) + { + state = STATE_NORMAL; + *active = !(*active); + } + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_NORMAL) + { + GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3)))), GetColor(GuiGetStyle(TOGGLE, ((*active)? BASE_COLOR_PRESSED : (BASE + state*3))))); + GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, ((*active)? TEXT_COLOR_PRESSED : (TEXT + state*3))))); + } + else + { + GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), GetColor(GuiGetStyle(TOGGLE, BASE + state*3))); + GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, TEXT + state*3))); + } + + if (state == STATE_FOCUSED) GuiTooltip(bounds); + //-------------------------------------------------------------------- + + return result; +} + +// Toggle Group control +int GuiToggleGroup(Rectangle bounds, const char *text, int *active) +{ + #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS) + #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32 + #endif + + int result = 0; + float initBoundsX = bounds.x; + + int temp = 0; + if (active == NULL) active = &temp; + + bool toggle = false; // Required for individual toggles + + // Get substrings items from text (items pointers) + int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 }; + int itemCount = 0; + char **items = GuiTextSplit(text, ';', &itemCount, rows); + + int prevRow = rows[0]; + + for (int i = 0; i < itemCount; i++) + { + if (prevRow != rows[i]) + { + bounds.x = initBoundsX; + bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); + prevRow = rows[i]; + } + + if (i == (*active)) + { + toggle = true; + GuiToggle(bounds, items[i], &toggle); + } + else + { + toggle = false; + GuiToggle(bounds, items[i], &toggle); + if (toggle) *active = i; + } + + bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + } + + return result; +} + +// Toggle Slider control extended +int GuiToggleSlider(Rectangle bounds, const char *text, int *active) +{ + int result = 0; + GuiState state = guiState; + + int temp = 0; + if (active == NULL) active = &temp; + + //bool toggle = false; // Required for individual toggles + + // Get substrings items from text (items pointers) + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + + Rectangle slider = { + 0, // Calculated later depending on the active toggle + bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), + (bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - (itemCount + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING))/itemCount, + bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else if (GUI_BUTTON_RELEASED) + { + state = STATE_PRESSED; + (*active)++; + result = 1; + } + else state = STATE_FOCUSED; + } + + if ((*active) && (state != STATE_FOCUSED)) state = STATE_PRESSED; + } + + if (*active >= itemCount) *active = 0; + slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + (state*3))), + GetColor(GuiGetStyle(TOGGLE, BASE_COLOR_NORMAL))); + + // Draw internal slider + if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_FOCUSED))); + else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + + // Draw text in slider + if (text != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(text); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = slider.x + slider.width/2 - textBounds.width/2; + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(items[*active], textBounds, GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + (state*3))), guiAlpha)); + } + //-------------------------------------------------------------------- + + return result; +} + +// Check Box control, returns 1 when state changed +int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) +{ + int result = 0; + GuiState state = guiState; + + bool temp = false; + if (checked == NULL) checked = &temp; + + Rectangle textBounds = { 0 }; + + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(CHECKBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + Rectangle totalBounds = { + (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT)? textBounds.x : bounds.x, + bounds.y, + bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING), + bounds.height, + }; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, totalBounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) + { + *checked = !(*checked); + result = 1; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), BLANK); + + if (*checked) + { + Rectangle check = { bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), + bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), + bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)), + bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)) }; + GuiDrawRectangle(check, 0, BLANK, GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3))); + } + + GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Combo Box control +int GuiComboBox(Rectangle bounds, const char *text, int *active) +{ + int result = 0; + GuiState state = guiState; + + int temp = 0; + if (active == NULL) active = &temp; + + bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING)); + + Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING), + (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height }; + + // Get substrings items from text (items pointers, lengths and count) + int itemCount = 0; + char **items = GuiTextSplit(text, ';', &itemCount, NULL); + + if (*active < 0) *active = 0; + else if (*active > (itemCount - 1)) *active = itemCount - 1; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (CheckCollisionPointRec(mousePoint, bounds) || + CheckCollisionPointRec(mousePoint, selector)) + { + if (GUI_BUTTON_PRESSED) + { + *active += 1; + if (*active >= itemCount) *active = 0; // Cyclic combobox + } + + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + // Draw combo box main + GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3)))); + GuiDrawText(items[*active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3)))); + + // Draw selector using a custom button + // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + GuiButton(selector, TextFormat("%i/%i", *active + 1, itemCount)); + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + //-------------------------------------------------------------------- + + return result; +} + +// Dropdown Box control +// NOTE: Returns mouse click +int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) +{ + int result = 0; + GuiState state = guiState; + + int temp = 0; + if (active == NULL) active = &temp; + + int itemSelected = *active; + int itemFocused = -1; + + int direction = 0; // Dropdown box open direction: down (default) + if (GuiGetStyle(DROPDOWNBOX, DROPDOWN_ROLL_UP) == 1) direction = 1; // Up + + // Get substrings items from text (items pointers, lengths and count) + int itemCount = 0; + char **items = GuiTextSplit(text, ';', &itemCount, NULL); + + Rectangle boundsOpen = bounds; + boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + if (direction == 1) boundsOpen.y -= itemCount*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)) + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING); + + Rectangle itemBounds = bounds; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (editMode) + { + state = STATE_PRESSED; + + // Check if mouse has been pressed or released outside limits + if (!CheckCollisionPointRec(mousePoint, boundsOpen)) + { + if (GUI_BUTTON_PRESSED || GUI_BUTTON_RELEASED) result = 1; + } + + // Check if already selected item has been pressed again + if (CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED) result = 1; + + // Check focused and selected item + for (int i = 0; i < itemCount; i++) + { + // Update item rectangle y position for next item + if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = i; + if (GUI_BUTTON_RELEASED) + { + itemSelected = i; + result = 1; // Item selected + } + break; + } + } + + itemBounds = bounds; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_PRESSED) + { + result = 1; + state = STATE_PRESSED; + } + else state = STATE_FOCUSED; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (editMode) GuiPanel(boundsOpen, NULL); + + GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3))); + GuiDrawText(items[itemSelected], GetTextBounds(DROPDOWNBOX, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3))); + + if (editMode) + { + // Draw visible items + for (int i = 0; i < itemCount; i++) + { + // Update item rectangle y position for next item + if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + + if (i == itemSelected) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED))); + GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED))); + } + else if (i == itemFocused) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED))); + GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED))); + } + else GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL))); + } + } + + if (!GuiGetStyle(DROPDOWNBOX, DROPDOWN_ARROW_HIDDEN)) + { + // Draw arrows (using icon if available) +#if defined(RAYGUI_NO_ICONS) + GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL +#endif + } + //-------------------------------------------------------------------- + + *active = itemSelected; + + // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item... + return result; // Mouse click: result = 1 +} + +// Text Box control +// NOTE: Returns true on ENTER pressed (useful for data validation) +int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) +{ + #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) + #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 20 // Frames to wait for autocursor movement + #endif + #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) + #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement + #endif + + int result = 0; + GuiState state = guiState; + + bool multiline = false; // TODO: Consider multiline text input + int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); + + Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); + int textLength = (text != NULL)? (int)strlen(text) : 0; // Get current text length + int thisCursorIndex = textBoxCursorIndex; + if (thisCursorIndex > textLength) thisCursorIndex = textLength; + int textWidth = GuiGetTextWidth(text) - GuiGetTextWidth(text + thisCursorIndex); + int textIndexOffset = 0; // Text index offset to start drawing in the box + + // Cursor rectangle + // NOTE: Position X value should be updated + Rectangle cursor = { + textBounds.x + textWidth + GuiGetStyle(DEFAULT, TEXT_SPACING), + textBounds.y + textBounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE), + 2, + (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2 + }; + + if (cursor.height >= bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; + if (cursor.y < (bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH))) cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH); + + // Mouse cursor rectangle + // NOTE: Initialized outside of screen + Rectangle mouseCursor = cursor; + mouseCursor.x = -1; + mouseCursor.width = 1; + + // Blink-cursor frame counter + //if (!autoCursorMode) blinkCursorFrameCounter++; + //else blinkCursorFrameCounter = 0; + + // Update control + //-------------------------------------------------------------------- + // WARNING: Text editing is only supported under certain conditions: + if ((state != STATE_DISABLED) && // Control not disabled + !GuiGetStyle(TEXTBOX, TEXT_READONLY) && // TextBox not on read-only mode + !guiLocked && // RayGui not locked + !guiControlExclusiveMode && // No gui slider on dragging + (wrapMode == TEXT_WRAP_NONE)) // No wrap mode + { + Vector2 mousePosition = GUI_POINTER_POSITION; + + if (editMode) + { + // GLOBAL: Auto-cursor movement logic + // NOTE: Keystrokes are handled repeatedly when button is held down for some time + if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; + else autoCursorCounter = 0; + + bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0); + + state = STATE_PRESSED; + + if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; + + // If text does not fit in the textbox and current cursor position is out of bounds, + // adding an index offset to text for drawing only what requires depending on cursor + while (textWidth >= textBounds.width) + { + int nextCodepointSize = 0; + GetCodepointNext(text + textIndexOffset, &nextCodepointSize); + + textIndexOffset += nextCodepointSize; + + textWidth = GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex); + } + + int codepoint = GUI_INPUT_KEY; // Get Unicode codepoint + if (multiline && GUI_KEY_PRESSED(KEY_ENTER)) codepoint = (int)'\n'; + + // Encode codepoint as UTF-8 + int codepointSize = 0; + const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize); + + // Handle text paste action + if (GUI_KEY_PRESSED(KEY_V) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + const char *pasteText = GetClipboardText(); + if (pasteText != NULL) + { + int pasteLength = 0; + int pasteCodepoint; + int pasteCodepointSize; + + // Count how many codepoints to copy, stopping at the first unwanted control character + while (true) + { + pasteCodepoint = GetCodepointNext(pasteText + pasteLength, &pasteCodepointSize); + if (textLength + pasteLength + pasteCodepointSize >= textSize) break; + if (!(multiline && (pasteCodepoint == (int)'\n')) && !(pasteCodepoint >= 32)) break; + pasteLength += pasteCodepointSize; + } + + if (pasteLength > 0) + { + // Move forward data from cursor position + for (int i = textLength + pasteLength; i > textBoxCursorIndex; i--) text[i] = text[i - pasteLength]; + + // Paste data in at cursor + for (int i = 0; i < pasteLength; i++) text[textBoxCursorIndex + i] = pasteText[i]; + + textBoxCursorIndex += pasteLength; + textLength += pasteLength; + text[textLength] = '\0'; + } + } + } + else if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize)) + { + // Adding codepoint to text, at current cursor position + + // Move forward data from cursor position + for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize]; + + // Add new codepoint in current cursor position + for (int i = 0; i < codepointSize; i++) text[textBoxCursorIndex + i] = charEncoded[i]; + + textBoxCursorIndex += codepointSize; + textLength += codepointSize; + + // Make sure text last character is EOL + text[textLength] = '\0'; + } + + // Move cursor to start + if ((textLength > 0) && GUI_KEY_PRESSED(KEY_HOME)) textBoxCursorIndex = 0; + + // Move cursor to end + if ((textLength > textBoxCursorIndex) && GUI_KEY_PRESSED(KEY_END)) textBoxCursorIndex = textLength; + + // Delete related codepoints from text, after current cursor position + if ((textLength > textBoxCursorIndex) && GUI_KEY_PRESSED(KEY_DELETE) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + int accCodepointSize = 0; + int nextCodepointSize; + int nextCodepoint; + + // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + bool puctuation = ispunct(nextCodepoint & 0xff); + while (offset < textLength) + { + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) + break; + offset += nextCodepointSize; + accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + // Check whitespace to delete (ASCII only) + while (offset < textLength) + { + if (!isspace(nextCodepoint & 0xff)) break; + + offset += nextCodepointSize; + accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + // Move text after cursor forward (including final null terminator) + for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i]; + + textLength -= accCodepointSize; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) + { + // Delete single codepoint from text, after current cursor position + + int nextCodepointSize = 0; + GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); + + // Move text after cursor forward (including final null terminator) + for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i]; + + textLength -= nextCodepointSize; + } + + // Delete related codepoints from text, before current cursor position + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + int accCodepointSize = 0; + int prevCodepointSize = 0; + int prevCodepoint = 0; + + // Check whitespace to delete (ASCII only) + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if (!isspace(prevCodepoint & 0xff)) break; + + offset -= prevCodepointSize; + accCodepointSize += prevCodepointSize; + } + + // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + bool puctuation = ispunct(prevCodepoint & 0xff); + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + + offset -= prevCodepointSize; + accCodepointSize += prevCodepointSize; + } + + // Move text after cursor forward (including final null terminator) + for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - accCodepointSize] = text[i]; + + textLength -= accCodepointSize; + textBoxCursorIndex -= accCodepointSize; + } + else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_BACKSPACE) || (GUI_KEY_DOWN(KEY_BACKSPACE) && autoCursorShouldTrigger))) + { + // Delete single codepoint from text, before current cursor position + + int prevCodepointSize = 0; + + GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); + + // Move text after cursor forward (including final null terminator) + for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - prevCodepointSize] = text[i]; + + textLength -= prevCodepointSize; + textBoxCursorIndex -= prevCodepointSize; + } + + // Move cursor position with keys + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_LEFT) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + //int accCodepointSize = 0; + int prevCodepointSize = 0; + int prevCodepoint = 0; + + // Check whitespace to skip (ASCII only) + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if (!isspace(prevCodepoint & 0xff)) break; + + offset -= prevCodepointSize; + //accCodepointSize += prevCodepointSize; + } + + // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + bool puctuation = ispunct(prevCodepoint & 0xff); + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + + offset -= prevCodepointSize; + //accCodepointSize += prevCodepointSize; + } + + textBoxCursorIndex = offset; + } + else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_LEFT) || (GUI_KEY_DOWN(KEY_LEFT) && autoCursorShouldTrigger))) + { + int prevCodepointSize = 0; + GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); + + textBoxCursorIndex -= prevCodepointSize; + } + else if ((textLength > textBoxCursorIndex) && GUI_KEY_PRESSED(KEY_RIGHT) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + //int accCodepointSize = 0; + int nextCodepointSize; + int nextCodepoint; + + // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + bool puctuation = ispunct(nextCodepoint & 0xff); + while (offset < textLength) + { + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; + + offset += nextCodepointSize; + //accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + // Check whitespace to skip (ASCII only) + while (offset < textLength) + { + if (!isspace(nextCodepoint & 0xff)) break; + + offset += nextCodepointSize; + //accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + textBoxCursorIndex = offset; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_RIGHT) || (GUI_KEY_DOWN(KEY_RIGHT) && autoCursorShouldTrigger))) + { + int nextCodepointSize = 0; + GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); + + textBoxCursorIndex += nextCodepointSize; + } + + // Move cursor position with mouse + if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text + { + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; + int codepointIndex = 0; + float glyphWidth = 0.0f; + float widthToMouseX = 0; + int mouseCursorIndex = 0; + + for (int i = textIndexOffset; i < textLength; i += codepointSize) + { + codepoint = GetCodepointNext(&text[i], &codepointSize); + codepointIndex = GetGlyphIndex(guiFont, codepoint); + + if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor); + else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor); + + if (mousePosition.x <= (textBounds.x + (widthToMouseX + glyphWidth/2))) + { + mouseCursor.x = textBounds.x + widthToMouseX; + mouseCursorIndex = i; + break; + } + + widthToMouseX += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + + // Check if mouse cursor is at the last position + int textEndWidth = GuiGetTextWidth(text + textIndexOffset); + if (GUI_POINTER_POSITION.x >= (textBounds.x + textEndWidth - glyphWidth/2)) + { + mouseCursor.x = textBounds.x + textEndWidth; + mouseCursorIndex = textLength; + } + + // Place cursor at required index on mouse click + if ((mouseCursor.x >= 0) && GUI_BUTTON_PRESSED) + { + cursor.x = mouseCursor.x; + textBoxCursorIndex = mouseCursorIndex; + } + } + else mouseCursor.x = -1; + + // Recalculate cursor position.y depending on textBoxCursorIndex + cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING); + //if (multiline) cursor.y = GetTextLines() + + // Finish text editing on ENTER or mouse click outside bounds + if ((!multiline && GUI_KEY_PRESSED(KEY_ENTER)) || + (!CheckCollisionPointRec(mousePosition, bounds) && GUI_BUTTON_PRESSED)) + { + textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index + autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes + result = 1; + } + } + else + { + if (CheckCollisionPointRec(mousePosition, bounds)) + { + state = STATE_FOCUSED; + + if (GUI_BUTTON_PRESSED) + { + textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text + autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes + result = 1; + } + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_PRESSED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED))); + } + else if (state == STATE_DISABLED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED))); + } + else GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), BLANK); + + // Draw text considering index offset if required + // NOTE: Text index offset depends on cursor position + GuiDrawText(text + textIndexOffset, textBounds, GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3)))); + + // Draw cursor + if (editMode && !GuiGetStyle(TEXTBOX, TEXT_READONLY)) + { + //if (autoCursorMode || ((blinkCursorFrameCounter/40)%2 == 0)) + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); + + // Draw mouse position cursor (if required) + if (mouseCursor.x >= 0) GuiDrawRectangle(mouseCursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); + } + else if (state == STATE_FOCUSED) GuiTooltip(bounds); + //-------------------------------------------------------------------- + + return result; // Mouse button pressed: result = 1 +} + +/* +// Text Box control with multiple lines and word-wrap +// NOTE: This text-box is readonly, no editing supported by default +bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) +{ + bool pressed = false; + + GuiSetStyle(TEXTBOX, TEXT_READONLY, 1); + GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // WARNING: If wrap mode enabled, text editing is not supported + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); + + // TODO: Implement methods to calculate cursor position properly + pressed = GuiTextBox(bounds, text, textSize, editMode); + + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); + GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE); + GuiSetStyle(TEXTBOX, TEXT_READONLY, 0); + + return pressed; +} +*/ + +// Spinner control, returns selected value +int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) +{ + int result = 1; + GuiState state = guiState; + + int tempValue = *value; + + Rectangle valueBoxBounds = { + bounds.x + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING), + bounds.y, + bounds.width - 2*(GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING)), bounds.height }; + Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height }; + Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.y, + (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height }; + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(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 = GUI_POINTER_POSITION; + + // Check spinner state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + } + } + +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(leftButtonBound, "<")) tempValue--; + if (GuiButton(rightButtonBound, ">")) tempValue++; +#else + if (GuiButton(leftButtonBound, GuiIconText(ICON_ARROW_LEFT_FILL, NULL))) tempValue--; + if (GuiButton(rightButtonBound, GuiIconText(ICON_ARROW_RIGHT_FILL, NULL))) tempValue++; +#endif + + if (!editMode) + { + if (tempValue < minValue) tempValue = minValue; + if (tempValue > maxValue) tempValue = maxValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + result = GuiValueBox(valueBoxBounds, NULL, &tempValue, minValue, maxValue, editMode); + + // Draw value selector custom buttons + // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(VALUEBOX, BORDER_WIDTH)); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + + // Draw text label if provided + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + *value = tempValue; + return result; +} + +// Value Box control, updates input text with numbers +// NOTE: Requires static variables: frameCounter +int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) +{ + #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) + #define RAYGUI_VALUEBOX_MAX_CHARS 32 + #endif + + int result = 0; + GuiState state = guiState; + + char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 }; + snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(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 = GUI_POINTER_POSITION; + bool valueHasChanged = false; + + if (editMode) + { + state = STATE_PRESSED; + + int keyCount = (int)strlen(textValue); + + // Add or remove minus symbol + if (GUI_KEY_PRESSED(KEY_MINUS)) + { + if (textValue[0] == '-') + { + for (int i = 0 ; i < keyCount; i++) textValue[i] = textValue[i + 1]; + + keyCount--; + valueHasChanged = true; + } + else if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) + { + if (keyCount == 0) + { + textValue[0] = '0'; + textValue[1] = '\0'; + keyCount++; + } + + for (int i = keyCount ; i > -1; i--) textValue[i + 1] = textValue[i]; + + textValue[0] = '-'; + keyCount++; + valueHasChanged = true; + } + } + + // Add new digit to text value + if ((keyCount >= 0) && (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) && (GuiGetTextWidth(textValue) < bounds.width)) + { + int key = GUI_INPUT_KEY; + + // Only allow keys in range [48..57] + if ((key >= 48) && (key <= 57)) + { + textValue[keyCount] = (char)key; + keyCount++; + valueHasChanged = true; + } + } + + // Delete text + if ((keyCount > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE)) + { + keyCount--; + textValue[keyCount] = '\0'; + valueHasChanged = true; + } + + if (valueHasChanged) *value = TextToInteger(textValue); + + // NOTE: Values are not clamped until user input finishes + //if (*value > maxValue) *value = maxValue; + //else if (*value < minValue) *value = minValue; + + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) + { + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + + result = 1; + } + } + else + { + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + if (GUI_BUTTON_PRESSED) 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 rectangle + if (editMode) + { + // NOTE: ValueBox internal text is always centered + Rectangle cursor = { bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1, + bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + 2, + 2, bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2 - 4 }; + if (cursor.height > bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); + } + + // Draw text label if provided + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Floating point Value Box control, updates input val_str with numbers +// NOTE: Requires static variables: frameCounter +int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) +{ + #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) + #define RAYGUI_VALUEBOX_MAX_CHARS 32 + #endif + + int result = 0; + GuiState state = guiState; + + //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; + //snprintf(textValue, sizeof(textValue), "%2.2f", *value); + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(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 = GUI_POINTER_POSITION; + + bool valueHasChanged = false; + + if (editMode) + { + state = STATE_PRESSED; + + int keyCount = (int)strlen(textValue); + + // Add or remove minus symbol + if (GUI_KEY_PRESSED(KEY_MINUS)) + { + if (textValue[0] == '-') + { + for (int i = 0; i < keyCount; i++) textValue[i] = textValue[i + 1]; + + keyCount--; + valueHasChanged = true; + } + else if (keyCount < (RAYGUI_VALUEBOX_MAX_CHARS - 1)) + { + if (keyCount == 0) + { + textValue[0] = '0'; + textValue[1] = '\0'; + keyCount++; + } + + for (int i = keyCount; i > -1; i--) textValue[i + 1] = textValue[i]; + + textValue[0] = '-'; + keyCount++; + valueHasChanged = true; + } + } + + // Only allow keys in range [48..57] + if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) + { + if (GuiGetTextWidth(textValue) < bounds.width) + { + int key = GUI_INPUT_KEY; + 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 (GUI_KEY_PRESSED(KEY_BACKSPACE)) + { + if (keyCount > 0) + { + keyCount--; + textValue[keyCount] = '\0'; + valueHasChanged = true; + } + } + + if (valueHasChanged) *value = TextToFloat(textValue); + + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = 1; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + if (GUI_BUTTON_PRESSED) 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 + GuiGetTextWidth(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 GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + int result = 0; + GuiState state = guiState; + + float temp = (maxValue - minValue)/2.0f; + if (value == NULL) value = &temp; + float oldValue = *value; + + int sliderWidth = GuiGetStyle(SLIDER, SLIDER_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) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + // Get equivalent value and slider position from mousePosition.x + *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + if (!CheckCollisionPointRec(mousePoint, slider)) + { + // Get equivalent value and slider position from mousePosition.x + *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue; + } + } + else state = STATE_FOCUSED; + } + + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + } + + // Control value change check + if (oldValue == *value) result = 0; + else result = 1; + + // Slider bar limits check + float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); + if (sliderWidth > 0) // Slider + { + slider.x += sliderValue; + slider.width = (float)sliderWidth; + if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH); + else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH); + } + else if (sliderWidth == 0) // SliderBar + { + slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); + slider.width = sliderValue; + if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED))); + + // Draw slider internal bar (depends on state) + if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED))); + else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED))); + else if (state == STATE_DISABLED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_DISABLED))); + + // Draw left/right text if provided + if (textLeft != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textLeft); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + + if (textRight != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textRight); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + //-------------------------------------------------------------------- + + return result; +} + +// Slider Bar control extended, returns selected value +int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + int result = 0; + int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); + GuiSetStyle(SLIDER, SLIDER_WIDTH, 0); + result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue); + GuiSetStyle(SLIDER, SLIDER_WIDTH, preSliderWidth); + + return result; +} + +// Progress Bar control extended, shows current progress value +int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + int result = 0; + GuiState state = guiState; + + float temp = (maxValue - minValue)/2.0f; + if (value == NULL) value = &temp; + + // Progress bar + Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), + bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0, + bounds.height - GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) -1 }; + + // Update control + //-------------------------------------------------------------------- + if (*value > maxValue) *value = maxValue; + + // WARNING: Working with floats could lead to rounding issues + if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)); + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_DISABLED) + { + GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), BLANK); + } + else + { + if (*value > minValue) + { + // Draw progress bar with colored border, more visual + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + } + else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + + if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1}, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + else + { + // Draw borders not yet reached by value + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y + bounds.height - 1, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + } + + // Draw slider internal progress bar (depends on state) + if (GuiGetStyle(PROGRESSBAR, PROGRESS_SIDE) == 0) // Left-->Right + { + GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED))); + } + else // Right-->Left + { + progress.x = bounds.x + bounds.width - progress.width - GuiGetStyle(PROGRESSBAR, BORDER_WIDTH); + GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED))); + } + } + + // Draw left/right text if provided + if (textLeft != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textLeft); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + + if (textRight != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textRight); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + //-------------------------------------------------------------------- + + return result; +} + +// Status Bar control +int GuiStatusBar(Rectangle bounds, const char *text) +{ + int result = 0; + GuiState state = guiState; + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3)))); + GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), GetColor(GuiGetStyle(STATUSBAR, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Dummy rectangle control, intended for placeholding +int GuiDummyRec(Rectangle bounds, const char *text) +{ + int result = 0; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED))); + GuiDrawText(text, GetTextBounds(DEFAULT, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(BUTTON, (state != STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED))); + //------------------------------------------------------------------ + + return result; +} + +// List View control +int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active) +{ + int result = 0; + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + + result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL); + + return result; +} + +// List View control with extended parameters +int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus) +{ + int result = 0; + GuiState state = guiState; + + int itemFocused = (focus == NULL)? -1 : *focus; + int itemSelected = (active == NULL)? -1 : *active; + + // Check if scroll bar is needed + bool useScrollBar = false; + if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING))*count > bounds.height) useScrollBar = true; + + // Define base item rectangle [0] + Rectangle itemBounds = { 0 }; + itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING); + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.height = (float)GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); + if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); + + // Get items on the list + int visibleItems = (int)bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + if (visibleItems > count) visibleItems = count; + + int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex; + if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0; + int endIndex = startIndex + visibleItems; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check mouse inside list view + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Check focused and selected item + for (int i = 0; i < visibleItems; i++) + { + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = startIndex + i; + if (GUI_BUTTON_PRESSED) + { + if (itemSelected == (startIndex + i)) itemSelected = -1; + else itemSelected = startIndex + i; + } + break; + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + } + + if (useScrollBar) + { + float scrollDelta = GUI_SCROLL_DELTA; + startIndex -= (int)scrollDelta; + + if (startIndex < 0) startIndex = 0; + else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; + + endIndex = startIndex + visibleItems; + if (endIndex > count) endIndex = count; + } + } + else itemFocused = -1; + + // Reset item rectangle y to [0] + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + + // Draw visible items + for (int i = 0; ((i < visibleItems) && (text != NULL)); i++) + { + if (GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL)) 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, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED))); + + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED))); + } + else + { + if (((startIndex + i) == itemSelected) && (active != NULL)) + { + // Draw item selected + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED))); + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED))); + } + else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: Items focused, despite not returned + { + // Draw item focused + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED))); + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED))); + } + else + { + // Draw item normal (no rectangle) + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL))); + } + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + } + + if (useScrollBar) + { + Rectangle scrollBarBounds = { + bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Calculate percentage of visible items and apply same percentage to scrollbar + float percentVisible = (float)(endIndex - startIndex)/count; + float sliderSize = bounds.height*percentVisible; + + int prevSliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); // Save default slider size + int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)sliderSize); // Change slider size + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed + + startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems); + + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, prevSliderSize); // Reset slider size to default + } + //-------------------------------------------------------------------- + + if (active != NULL) *active = itemSelected; + if (focus != NULL) *focus = itemFocused; + if (scrollIndex != NULL) *scrollIndex = startIndex; + + return result; +} + +// Color Panel control - Color (RGBA) variant +int GuiColorPanel(Rectangle bounds, const char *text, Color *color) +{ + int result = 0; + + Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; + Vector3 hsv = ConvertRGBtoHSV(vcolor); + Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv + + GuiColorPanelHSV(bounds, text, &hsv); + + // Check if the hsv was changed, only then change the color + // This is required, because the Color->HSV->Color conversion has precision errors + // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value + // Otherwise GuiColorPanel would often modify it's color without user input + // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check + if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z) + { + Vector3 rgb = ConvertHSVtoRGB(hsv); + + // NOTE: Vector3ToColor() only available on raylib 1.8.1 + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), + (unsigned char)(255.0f*rgb.y), + (unsigned char)(255.0f*rgb.z), + color->a }; + } + return result; +} + +// Color Bar Alpha control +// NOTE: Returns alpha value normalized [0..1] +int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) +{ + #if !defined(RAYGUI_COLORBARALPHA_CHECKED_SIZE) + #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10 + #endif + + int result = 0; + GuiState state = guiState; + Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, + (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), + (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), + (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + *alpha = (mousePoint.x - bounds.x)/bounds.width; + if (*alpha <= 0.0f) *alpha = 0.0f; + if (*alpha >= 1.0f) *alpha = 1.0f; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + *alpha = (mousePoint.x - bounds.x)/bounds.width; + if (*alpha <= 0.0f) *alpha = 0.0f; + if (*alpha >= 1.0f) *alpha = 1.0f; + //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2; + } + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + // Draw alpha bar: checked background + if (state != STATE_DISABLED) + { + int checksX = (int)bounds.width/RAYGUI_COLORBARALPHA_CHECKED_SIZE; + int checksY = (int)bounds.height/RAYGUI_COLORBARALPHA_CHECKED_SIZE; + + for (int x = 0; x < checksX; x++) + { + for (int y = 0; y < checksY; y++) + { + Rectangle check = { bounds.x + x*RAYGUI_COLORBARALPHA_CHECKED_SIZE, bounds.y + y*RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE }; + GuiDrawRectangle(check, 0, BLANK, ((x + y)%2)? Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f) : Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f)); + } + } + + DrawRectangleGradientEx(bounds, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha)); + } + else DrawRectangleGradientEx(bounds, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + + // Draw alpha bar: selector + GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3))); + //-------------------------------------------------------------------- + + return result; +} + +// Color Bar Hue control +// Returns hue value normalized [0..1] +// NOTE: Other similar bars (for reference): +// Color GuiColorBarSat() [WHITE->color] +// Color GuiColorBarValue() [BLACK->color], HSV/HSL +// float GuiColorBarLuminance() [BLACK->WHITE] +int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) +{ + int result = 0; + GuiState state = guiState; + Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + *hue = (mousePoint.y - bounds.y)*360/bounds.height; + if (*hue <= 0.0f) *hue = 0.0f; + if (*hue >= 359.0f) *hue = 359.0f; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + *hue = (mousePoint.y - bounds.y)*360/bounds.height; + if (*hue <= 0.0f) *hue = 0.0f; + if (*hue >= 359.0f) *hue = 359.0f; + + } + else state = STATE_FOCUSED; + + /*if (GUI_KEY_DOWN(KEY_UP)) + { + hue -= 2.0f; + if (hue <= 0.0f) hue = 0.0f; + } + else if (GUI_KEY_DOWN(KEY_DOWN)) + { + hue += 2.0f; + if (hue >= 360.0f) hue = 360.0f; + }*/ + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != STATE_DISABLED) + { + // Draw hue bar:color bars + // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + } + else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + + // Draw hue bar: selector + GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3))); + //-------------------------------------------------------------------- + + return result; +} + +// Color Picker control +// NOTE: It's divided in multiple controls: +// Color GuiColorPanel(Rectangle bounds, Color color) +// float GuiColorBarAlpha(Rectangle bounds, float alpha) +// float GuiColorBarHue(Rectangle bounds, float value) +// NOTE: bounds define GuiColorPanel() size +// NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead +int GuiColorPicker(Rectangle bounds, const char *text, Color *color) +{ + int result = 0; + + Color temp = { 200, 0, 0, 255 }; + if (color == NULL) color = &temp; + + GuiColorPanel(bounds, NULL, color); + + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; + + // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used + Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); + + GuiColorBarHue(boundsHue, NULL, &hsv.x); + + //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); + Vector3 rgb = ConvertHSVtoRGB(hsv); + + *color = RAYGUI_CLITERAL(Color){ (unsigned char)roundf(rgb.x*255.0f), (unsigned char)roundf(rgb.y*255.0f), (unsigned char)roundf(rgb.z*255.0f), (*color).a }; + + return result; +} + +// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering +// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB +// NOTE: It's divided in multiple controls: +// int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +// int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) +// float GuiColorBarHue(Rectangle bounds, float value) +// NOTE: bounds define GuiColorPanelHSV() size +int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +{ + int result = 0; + + Vector3 tempHsv = { 0 }; + + if (colorHsv == NULL) + { + const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f }; + tempHsv = ConvertRGBtoHSV(tempColor); + colorHsv = &tempHsv; + } + + GuiColorPanelHSV(bounds, NULL, colorHsv); + + const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + + GuiColorBarHue(boundsHue, NULL, &colorHsv->x); + + return result; +} + +// Color Panel control - HSV variant +int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +{ + int result = 0; + GuiState state = guiState; + Vector2 pickerSelector = { 0 }; + + const Color colWhite = { 255, 255, 255, 255 }; + const Color colBlack = { 0, 0, 0, 255 }; + + pickerSelector.x = bounds.x + (float)colorHsv->y*bounds.width; // HSV: Saturation + pickerSelector.y = bounds.y + (1.0f - (float)colorHsv->z)*bounds.height; // HSV: Value + + Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; + Vector3 rgbHue = ConvertHSVtoRGB(maxHue); + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), + (unsigned char)(255.0f*rgbHue.y), + (unsigned char)(255.0f*rgbHue.z), 255 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + 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 (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; + pickerSelector = mousePoint; + + // Calculate color from picker + Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; + + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y + + colorHsv->y = colorPick.x; + colorHsv->z = 1.0f - colorPick.y; + } + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != STATE_DISABLED) + { + DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha)); + DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0)); + + // Draw color picker: selector + Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) }; + GuiDrawRectangle(selector, 0, BLANK, colWhite); + } + else + { + DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha)); + } + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + //-------------------------------------------------------------------- + + return result; +} + +// Message Box control +int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons) +{ + #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT) + #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24 + #endif + #if !defined(RAYGUI_MESSAGEBOX_BUTTON_PADDING) + #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12 + #endif + + int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button + + int buttonCount = 0; + char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + Rectangle buttonBounds = { 0 }; + buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING; + buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; + buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; + + //int textWidth = GuiGetTextWidth(message) + 2; + + Rectangle textBounds = { 0 }; + textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + textBounds.width = bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*2; + textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; + + // Draw control + //-------------------------------------------------------------------- + if (GuiWindowBox(bounds, title)) result = 0; + + int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(textBounds, message); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); + + prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + for (int i = 0; i < buttonCount; i++) + { + if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); + } + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment); + //-------------------------------------------------------------------- + + return result; +} + +// Text Input Box control, ask for text +int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive) +{ + #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT) + #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24 + #endif + #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_PADDING) + #define RAYGUI_TEXTINPUTBOX_BUTTON_PADDING 12 + #endif + #if !defined(RAYGUI_TEXTINPUTBOX_HEIGHT) + #define RAYGUI_TEXTINPUTBOX_HEIGHT 26 + #endif + + // Used to enable text edit mode + // WARNING: No more than one GuiTextInputBox() should be open at the same time + static bool textEditMode = false; + + int result = -1; + + int buttonCount = 0; + char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + Rectangle buttonBounds = { 0 }; + buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + buttonBounds.width = (bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; + buttonBounds.height = RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT; + + int messageInputHeight = (int)bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - 2*RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + + Rectangle textBounds = { 0 }; + if (message != NULL) + { + int textSize = GuiGetTextWidth(message) + 2; + + textBounds.x = bounds.x + bounds.width/2 - textSize/2; + textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + textBounds.width = (float)textSize; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + } + + Rectangle textBoxBounds = { 0 }; + textBoxBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + textBoxBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - RAYGUI_TEXTINPUTBOX_HEIGHT/2; + if (message == NULL) textBoxBounds.y = bounds.y + 24 + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + else textBoxBounds.y += (messageInputHeight/2 + messageInputHeight/4); + textBoxBounds.width = bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*2; + textBoxBounds.height = RAYGUI_TEXTINPUTBOX_HEIGHT; + + // Draw control + //-------------------------------------------------------------------- + if (GuiWindowBox(bounds, title)) result = 0; + + // Draw message if available + if (message != NULL) + { + int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(textBounds, message); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); + } + + int prevTextBoxAlignment = GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT); + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + + if (secretViewActive != NULL) + { + static char stars[] = "****************"; + if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height }, + ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode; + + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive); + } + else + { + if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode; + } + + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, prevTextBoxAlignment); + + int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + for (int i = 0; i < buttonCount; i++) + { + if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); + } + + if (result >= 0) textEditMode = false; + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); + //-------------------------------------------------------------------- + + return result; // Result is the pressed button index +} + +// Grid control +// NOTE: Returns grid mouse-hover selected cell +// About drawing lines at subpixel spacing, simple put, not easy solution: +// REF: https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster +int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell) +{ + // Grid lines alpha amount + #if !defined(RAYGUI_GRID_ALPHA) + #define RAYGUI_GRID_ALPHA 0.15f + #endif + + int result = 0; + GuiState state = guiState; + + Vector2 mousePoint = GUI_POINTER_POSITION; + Vector2 currentMouseCell = { -1, -1 }; + + float spaceWidth = spacing/(float)subdivs; + int linesV = (int)(bounds.width/spaceWidth) + 1; + int linesH = (int)(bounds.height/spaceWidth) + 1; + + int color = GuiGetStyle(DEFAULT, LINE_COLOR); + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + // NOTE: Cell values must be the upper left of the cell the mouse is in + currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing); + currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing); + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_DISABLED) color = GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED); + + if (subdivs > 0) + { + // Draw vertical grid lines + for (int i = 0; i < linesV; i++) + { + Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height + 1 }; + GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); + } + + // Draw horizontal grid lines + for (int i = 0; i < linesH; i++) + { + Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width + 1, 1 }; + GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); + } + } + + if (mouseCell != NULL) *mouseCell = currentMouseCell; + return result; +} + +//---------------------------------------------------------------------------------- +// Tooltip management functions +// NOTE: Tooltips requires some global variables: tooltipPtr +//---------------------------------------------------------------------------------- +// Enable gui tooltips (global state) +void GuiEnableTooltip(void) { guiTooltip = true; } + +// Disable gui tooltips (global state) +void GuiDisableTooltip(void) { guiTooltip = false; } + +// Set tooltip string +void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; } + +//---------------------------------------------------------------------------------- +// Styles loading functions +//---------------------------------------------------------------------------------- + +// Load raygui style file (.rgs) +// NOTE: By default a binary file is expected, that file could contain a custom font, +// in that case, custom font image atlas is GRAY+ALPHA and pixel data can be compressed (DEFLATE) +void GuiLoadStyle(const char *fileName) +{ + #define MAX_LINE_BUFFER_SIZE 256 + + bool tryBinary = false; + if (!guiStyleLoaded) GuiLoadStyleDefault(); + + // Try reading the files as text file first + FILE *rgsFile = fopen(fileName, "rt"); + + if (rgsFile != NULL) + { + char buffer[MAX_LINE_BUFFER_SIZE] = { 0 }; + fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile); + + if (buffer[0] == '#') + { + int controlId = 0; + int propertyId = 0; + unsigned int propertyValue = 0; + + while (!feof(rgsFile)) + { + switch (buffer[0]) + { + case 'p': + { + // Style property: p + + sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue); + GuiSetStyle(controlId, propertyId, (int)propertyValue); + + } break; + case 'f': + { + // Style font: f + + int fontSize = 0; + char charmapFileName[256] = { 0 }; + char fontFileName[256] = { 0 }; + sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName); + + Font font = { 0 }; + int *codepoints = NULL; + int codepointCount = 0; + + if (charmapFileName[0] != '0') + { + // Load text data from file + // NOTE: Expected an UTF-8 array of codepoints, no separation + char *textData = LoadFileText(TextFormat("%s/%s", GetDirectoryPath(fileName), charmapFileName)); + codepoints = LoadCodepoints(textData, &codepointCount); + UnloadFileText(textData); + } + + if (fontFileName[0] != '\0') + { + // In case a font is already loaded and it is not default internal font, unload it + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + + if (codepointCount > 0) font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, codepoints, codepointCount); + else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); // Default to 95 standard codepoints + } + + // If font texture not properly loaded, revert to default font and size/spacing + if (font.texture.id == 0) + { + font = GetFontDefault(); + GuiSetStyle(DEFAULT, TEXT_SIZE, 10); + GuiSetStyle(DEFAULT, TEXT_SPACING, 1); + } + + UnloadCodepoints(codepoints); + + if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font); + + } break; + default: break; + } + + fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile); + } + } + else tryBinary = true; + + fclose(rgsFile); + } + + if (tryBinary) + { + rgsFile = fopen(fileName, "rb"); + + if (rgsFile != NULL) + { + fseek(rgsFile, 0, SEEK_END); + int fileDataSize = ftell(rgsFile); + fseek(rgsFile, 0, SEEK_SET); + + if (fileDataSize > 0) + { + unsigned char *fileData = (unsigned char *)RAYGUI_CALLOC(fileDataSize, sizeof(unsigned char)); + if (fileData != NULL) + { + fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile); + + GuiLoadStyleFromMemory(fileData, fileDataSize); + + RAYGUI_FREE(fileData); + } + } + + fclose(rgsFile); + } + } +} + +// Load style default over global style +void GuiLoadStyleDefault(void) +{ + // Setting this flag first to avoid cyclic function calls + // when calling GuiSetStyle() and GuiGetStyle() + guiStyleLoaded = true; + + // Initialize default LIGHT style property values + // WARNING: Default value are applied to all controls on set but + // they can be overwritten later on for every custom control + GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff); + GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff); + GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff); + GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff); + GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff); + GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff); + GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff); + GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff); + GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff); + GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff); + GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff); + GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff); + GuiSetStyle(DEFAULT, BORDER_WIDTH, 1); + GuiSetStyle(DEFAULT, TEXT_PADDING, 0); + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + // Initialize default extended property values + // NOTE: By default, extended property values are initialized to 0 + GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls + GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls + GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property + GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property + GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 5); // DEFAULT, pixels between lines, from bottom of first line to top of second + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds + + // Initialize control-specific property values + // NOTE: Those properties are in default list but require specific values by control type + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 2); + GuiSetStyle(SLIDER, TEXT_PADDING, 4); + GuiSetStyle(PROGRESSBAR, TEXT_PADDING, 4); + GuiSetStyle(CHECKBOX, TEXT_PADDING, 4); + GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT); + GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0); + GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiSetStyle(TEXTBOX, TEXT_PADDING, 4); + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(VALUEBOX, TEXT_PADDING, 0); + GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + + // Initialize extended property values + // NOTE: By default, extended property values are initialized to 0 + GuiSetStyle(TOGGLE, GROUP_PADDING, 2); + GuiSetStyle(SLIDER, SLIDER_WIDTH, 16); + GuiSetStyle(SLIDER, SLIDER_PADDING, 1); + GuiSetStyle(PROGRESSBAR, PROGRESS_PADDING, 1); + GuiSetStyle(CHECKBOX, CHECK_PADDING, 1); + GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 32); + GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2); + GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16); + GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2); + GuiSetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH, 24); + GuiSetStyle(VALUEBOX, SPINNER_BUTTON_SPACING, 2); + GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0); + GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0); + GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6); + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING, 0); + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, 16); + GuiSetStyle(SCROLLBAR, SCROLL_PADDING, 0); + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12); + GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28); + GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2); + GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH, 1); + GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12); + GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE); + GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8); + GuiSetStyle(COLORPICKER, HUEBAR_WIDTH, 16); + GuiSetStyle(COLORPICKER, HUEBAR_PADDING, 8); + GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT, 8); + GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW, 2); + + if (guiFont.texture.id != GetFontDefault().texture.id) + { + // Unload previous font texture + UnloadTexture(guiFont.texture); + RAYGUI_FREE(guiFont.recs); + RAYGUI_FREE(guiFont.glyphs); + guiFont.recs = NULL; + guiFont.glyphs = NULL; + + // Setup default raylib font + guiFont = GetFontDefault(); + + // NOTE: Default raylib font character 95 is a white square + Rectangle whiteChar = guiFont.recs[95]; + + // NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering + SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); + } +} + +// Get text with icon id prepended +// NOTE: Useful to add icons by name id (enum) instead of +// a number that can change between ricon versions +const char *GuiIconText(int iconId, const char *text) +{ +#if defined(RAYGUI_NO_ICONS) + return NULL; +#else + static char buffer[1024] = { 0 }; + static char iconBuffer[16] = { 0 }; + + if (text != NULL) + { + memset(buffer, 0, 1024); + snprintf(buffer, 1024, "#%03i#", iconId); + + for (int i = 5; i < 1024; i++) + { + buffer[i] = text[i - 5]; + if (text[i - 5] == '\0') break; + } + + return buffer; + } + else + { + snprintf(iconBuffer, 16, "#%03i#", iconId); + + return iconBuffer; + } +#endif +} + +#if !defined(RAYGUI_NO_ICONS) +// Get full icons data pointer +unsigned int *GuiGetIcons(void) { return guiIconsPtr; } + +// Load raygui icons file (.rgi) +// NOTE: In case nameIds are required, they can be requested with loadIconsName, +// they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH], +// WARNING: guiIconsName[]][] memory should be manually freed! +char **GuiLoadIcons(const char *fileName, bool loadIconsName) +{ + // Style File Structure (.rgi) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGI " + // 4 | 2 | short | Version: 100 + // 6 | 2 | short | reserved + + // 8 | 2 | short | Num icons (N) + // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S) + + // Icons name id (32 bytes per name id) + // foreach (icon) + // { + // 12+32*i | 32 | char | Icon NameId + // } + + // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) + // S*S pixels/32bit per unsigned int = K unsigned int per icon + // foreach (icon) + // { + // ... | K | unsigned int | Icon Data + // } + + FILE *rgiFile = fopen(fileName, "rb"); + + char **guiIconsName = NULL; + + if (rgiFile != NULL) + { + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + short iconCount = 0; + short iconSize = 0; + + fread(signature, 1, 4, rgiFile); + fread(&version, sizeof(short), 1, rgiFile); + fread(&reserved, sizeof(short), 1, rgiFile); + fread(&iconCount, sizeof(short), 1, rgiFile); + fread(&iconSize, sizeof(short), 1, rgiFile); + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'I') && + (signature[3] == ' ')) + { + if (loadIconsName) + { + guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); + for (int i = 0; i < iconCount; i++) + { + guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); + fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile); + } + } + else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR); + + // Read icons data directly over internal icons array + fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile); + } + + fclose(rgiFile); + } + + return guiIconsName; +} + +// Load icons from memory +// WARNING: Binary files only +char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName) +{ + unsigned char *fileDataPtr = (unsigned char *)fileData; + char **guiIconsName = NULL; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + short iconCount = 0; + short iconSize = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&iconCount, fileDataPtr + 4 + 2 + 2, sizeof(short)); + memcpy(&iconSize, fileDataPtr + 4 + 2 + 2 + 2, sizeof(short)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'I') && + (signature[3] == ' ')) + { + if (loadIconsName) + { + guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); + for (int i = 0; i < iconCount; i++) + { + guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); + memcpy(guiIconsName[i], fileDataPtr, RAYGUI_ICON_MAX_NAME_LENGTH); + fileDataPtr += RAYGUI_ICON_MAX_NAME_LENGTH; + } + } + else + { + // Skip icon name data if not required + fileDataPtr += iconCount*RAYGUI_ICON_MAX_NAME_LENGTH; + } + + int iconDataSize = iconCount*((int)iconSize*(int)iconSize/32)*(int)sizeof(unsigned int); + guiIconsPtr = (unsigned int *)RAYGUI_CALLOC(iconDataSize, 1); + + memcpy(guiIconsPtr, fileDataPtr, iconDataSize); + } + + return guiIconsName; +} + +// Draw selected icon using rectangles pixel-by-pixel +void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) +{ + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + { + for (int k = 0; k < 32; k++) + { + if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) + { + #if !defined(RAYGUI_STANDALONE) + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); + #endif + } + + if ((k == 15) || (k == 31)) y++; + } + } +} + +// Set icon drawing size +void GuiSetIconScale(int scale) +{ + if (scale >= 1) guiIconScale = scale; +} + +// Get text width considering gui style and icon size (if required) +int GuiGetTextWidth(const char *text) +{ + #if !defined(ICON_TEXT_PADDING) + #define ICON_TEXT_PADDING 4 + #endif + + Vector2 textSize = { 0 }; + int textIconOffset = 0; + + if ((text != NULL) && (text[0] != '\0')) + { + if (text[0] == '#') + { + for (int i = 1; (i < 5) && (text[i] != '\0'); i++) + { + if (text[i] == '#') + { + textIconOffset = i; + break; + } + } + } + + text += textIconOffset; + + // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly + float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + + // Custom MeasureText() implementation + if ((guiFont.texture.id > 0) && (text != NULL)) + { + // Get size in bytes of text, considering end of line and line break + int size = 0; + for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++) + { + if ((text[i] != '\0') && (text[i] != '\n')) size++; + else break; + } + + float scaleFactor = fontSize/(float)guiFont.baseSize; + textSize.y = (float)guiFont.baseSize*scaleFactor; + float glyphWidth = 0.0f; + + for (int i = 0, codepointSize = 0; i < size; i += codepointSize) + { + int codepoint = GetCodepointNext(&text[i], &codepointSize); + int codepointIndex = GetGlyphIndex(guiFont, codepoint); + + if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor); + else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor); + + textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + } + + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING); + } + + return (int)textSize.x; +} + +#endif // !RAYGUI_NO_ICONS + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- +// Load style from memory +// WARNING: Binary files only +static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) +{ + unsigned char *fileDataPtr = (unsigned char *)fileData; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + int propertyCount = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'S') && + (signature[3] == ' ')) + { + short controlId = 0; + short propertyId = 0; + unsigned int propertyValue = 0; + + for (int i = 0; i < propertyCount; i++) + { + memcpy(&controlId, fileDataPtr, sizeof(short)); + memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); + memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); + fileDataPtr += 8; + + if (controlId == 0) // DEFAULT control + { + // If a DEFAULT property is loaded, it is propagated to all controls + // NOTE: All DEFAULT properties should be defined first in the file + GuiSetStyle(0, (int)propertyId, propertyValue); + + if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); + } + else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); + } + + // Font loading is highly dependant on raylib API to load font data and image + +#if !defined(RAYGUI_STANDALONE) + // Load custom font if available + int fontDataSize = 0; + memcpy(&fontDataSize, fileDataPtr, sizeof(int)); + fileDataPtr += 4; + + if (fontDataSize > 0) + { + Font font = { 0 }; + int fontType = 0; // 0-Normal, 1-SDF + + memcpy(&font.baseSize, fileDataPtr, sizeof(int)); + memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); + memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + // Load font white rectangle + Rectangle fontWhiteRec = { 0 }; + memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); + fileDataPtr += 16; + + // Load font image parameters + int fontImageUncompSize = 0; + int fontImageCompSize = 0; + memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); + memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); + fileDataPtr += 8; + + Image imFont = { 0 }; + imFont.mipmaps = 1; + memcpy(&imFont.width, fileDataPtr, sizeof(int)); + memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); + memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) + { + // Compressed font atlas image data (DEFLATE), it requires DecompressData() + int dataUncompSize = 0; + unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); + memcpy(compData, fileDataPtr, fontImageCompSize); + fileDataPtr += fontImageCompSize; + + imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); + + // Security check, dataUncompSize must match the provided fontImageUncompSize + if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); + + RAYGUI_FREE(compData); + } + else + { + // Font atlas image data is not compressed + imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); + memcpy(imFont.data, fileDataPtr, fontImageUncompSize); + fileDataPtr += fontImageUncompSize; + } + + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + font.texture = LoadTextureFromImage(imFont); + + RAYGUI_FREE(imFont.data); + + // Validate font atlas texture was loaded correctly + if (font.texture.id != 0) + { + // Load font recs data + int recsDataSize = font.glyphCount*sizeof(Rectangle); + int recsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed recs data + memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) + { + // Recs data is compressed, uncompress it + unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); + + memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); + fileDataPtr += recsDataCompressedSize; + + int recsDataUncompSize = 0; + font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); + + RAYGUI_FREE(recsDataCompressed); + } + else + { + // Recs data is uncompressed + font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); + fileDataPtr += sizeof(Rectangle); + } + } + + // Load font glyphs info data + int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph + int glyphsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed glyphs data + memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + // Allocate required glyphs space to fill with data + font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); + + if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) + { + // Glyphs data is compressed, uncompress it + unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); + + memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); + fileDataPtr += glyphsDataCompressedSize; + + int glyphsDataUncompSize = 0; + unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); + + unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; + + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); + glyphsDataUncompPtr += 16; + } + + RAYGUI_FREE(glypsDataCompressed); + RAYGUI_FREE(glyphsDataUncomp); + } + else + { + // Glyphs data is uncompressed + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); + fileDataPtr += 16; + } + } + } + else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture + + GuiSetFont(font); + + // Set font texture source rectangle to be used as white texture to draw shapes + // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call + if ((fontWhiteRec.x > 0) && + (fontWhiteRec.y > 0) && + (fontWhiteRec.width > 0) && + (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); + } +#endif + } +} + +// Get text bounds considering control bounds +static Rectangle GetTextBounds(int control, Rectangle bounds) +{ + Rectangle textBounds = bounds; + + textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH); + textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, TEXT_PADDING); + textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); + textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); // NOTE: Text is processed line per line! + + // Depending on control, TEXT_PADDING and TEXT_ALIGNMENT properties could affect the text-bounds + switch (control) + { + case COMBOBOX: + case DROPDOWNBOX: + case LISTVIEW: + // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW + case SLIDER: + case CHECKBOX: + case VALUEBOX: + case CONTROL11: + // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER + default: + { + // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() + if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); + else textBounds.x += GuiGetStyle(control, TEXT_PADDING); + } + break; + } + + return textBounds; +} + +// Get text icon if provided and move text cursor +// NOTE: Up to #999# values supported for iconId +static const char *GetTextIcon(const char *text, int *iconId) +{ +#if !defined(RAYGUI_NO_ICONS) + *iconId = -1; + if (text[0] == '#') // Maybe it is stars with an icon, ending # must be found + { + char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' + + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) + { + iconValue[pos - 1] = text[pos]; + pos++; + } + + if (text[pos] == '#') + { + *iconId = TextToInteger(iconValue); + + // Move text pointer after icon + // WARNING: If only icon provided, it could point to EOL character: '\0' + if (*iconId >= 0) text += (pos + 1); + } + } +#endif + + return text; +} + +// Get text divided into lines (by line-breaks '\n') +// WARNING: It returns pointers to new lines but it does not add NULL ('\0') terminator! +static const char **GetTextLines(const char *text, int *count) +{ + #define RAYGUI_MAX_TEXT_LINES 128 + + static const char *lines[RAYGUI_MAX_TEXT_LINES] = { 0 }; + for (int i = 0; i < RAYGUI_MAX_TEXT_LINES; i++) lines[i] = NULL; // Init NULL pointers to substrings + + int textLength = (int)strlen(text); + + lines[0] = text; + *count = 1; + + for (int i = 0; (i < textLength) && (*count < RAYGUI_MAX_TEXT_LINES); i++) + { + if ((text[i] == '\n') && ((i + 1) < textLength)) + { + lines[*count] = &text[i + 1]; + *count += 1; + } + } + + return lines; +} + +// Get text width to next space for provided string +static float GetNextSpaceWidth(const char *text, int *nextSpaceIndex) +{ + float width = 0; + int codepointByteCount = 0; + int codepoint = 0; + int index = 0; + float glyphWidth = 0; + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; + + for (int i = 0; text[i] != '\0'; i++) + { + if (text[i] != ' ') + { + codepoint = GetCodepoint(&text[i], &codepointByteCount); + index = GetGlyphIndex(guiFont, codepoint); + glyphWidth = (guiFont.glyphs[index].advanceX == 0)? guiFont.recs[index].width*scaleFactor : guiFont.glyphs[index].advanceX*scaleFactor; + width += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + else + { + *nextSpaceIndex = i; + break; + } + } + + return width; +} + +// RayGui draw text using default font +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint) +{ + #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect + + #if !defined(ICON_TEXT_PADDING) + #define ICON_TEXT_PADDING 4 + #endif + + if ((text == NULL) || (text[0] == '\0')) return; // Security check + + // PROCEDURE: + // - Text is processed line per line + // - For every line, horizontal alignment is defined + // - For all text, vertical alignment is defined (multiline text only) + // - For every line, wordwrap mode is checked (useful for GuitextBox(), read-only) + + // Get text lines (using '\n' as delimiter) to be processed individually + // WARNING: GuiTextSplit() function can't be used now because it can have already been used + // before the GuiDrawText() call and its buffer is static, it would be overriden :( + int lineCount = 0; + const char **lines = GetTextLines(text, &lineCount); + + // Text style variables + //int alignment = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT); + int alignmentVertical = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL); + int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); // Wrap-mode only available in read-only mode, no for text editing + + // TODO: WARNING: This totalHeight is not valid for vertical alignment in case of word-wrap + float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + float posOffsetY = 0.0f; + + for (int i = 0; i < lineCount; i++) + { + int iconId = 0; + lines[i] = GetTextIcon(lines[i], &iconId); // Check text for icon and move cursor + + // Get text position depending on alignment and iconId + //--------------------------------------------------------------------------------- + Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; + float textBoundsWidthOffset = 0.0f; + + // NOTE: Get text size after icon has been processed + // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed? + int textSizeX = GuiGetTextWidth(lines[i]); + + // If text requires an icon, add size to measure + if (iconId >= 0) + { + textSizeX += RAYGUI_ICON_SIZE*guiIconScale; + + // WARNING: If only icon provided, text could be pointing to EOF character: '\0' +#if !defined(RAYGUI_NO_ICONS) + if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING; +#endif + } + + // Check guiTextAlign global variables + switch (alignment) + { + case TEXT_ALIGN_LEFT: textBoundsPosition.x = textBounds.x; break; + case TEXT_ALIGN_CENTER: textBoundsPosition.x = textBounds.x + textBounds.width/2 - textSizeX/2; break; + case TEXT_ALIGN_RIGHT: textBoundsPosition.x = textBounds.x + textBounds.width - textSizeX; break; + default: break; + } + + if (textSizeX > textBounds.width && (lines[i] != NULL) && (lines[i][0] != '\0')) textBoundsPosition.x = textBounds.x; + + switch (alignmentVertical) + { + // Only valid in case of wordWrap = 0; + case TEXT_ALIGN_TOP: textBoundsPosition.y = textBounds.y + posOffsetY; break; + case TEXT_ALIGN_MIDDLE: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break; + case TEXT_ALIGN_BOTTOM: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height - totalHeight + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break; + default: break; + } + + // NOTE: Make sure getting pixel-perfect coordinates, + // In case of decimals, it could result in text positioning artifacts + textBoundsPosition.x = (float)((int)textBoundsPosition.x); + textBoundsPosition.y = (float)((int)textBoundsPosition.y); + //--------------------------------------------------------------------------------- + + // Draw text (with icon if available) + //--------------------------------------------------------------------------------- +#if !defined(RAYGUI_NO_ICONS) + if (iconId >= 0) + { + // NOTE: Considering icon height, probably different than text size + GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); + textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + } +#endif + // Get size in bytes of text, + // considering end of line and line break + int lineSize = 0; + for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; + + int lastSpaceIndex = 0; + bool tempWrapCharMode = false; + + int textOffsetY = 0; + float textOffsetX = 0.0f; + float glyphWidth = 0; + + int ellipsisWidth = GuiGetTextWidth("..."); + bool textOverflow = false; + for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize) + { + int codepoint = GetCodepointNext(&lines[i][c], &codepointSize); + int index = GetGlyphIndex(guiFont, codepoint); + + // NOTE: Normally, exiting the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but all of the bad bytes need to be drawn using the '?' symbol, moving one byte + if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size + + // Get glyph width to check if it goes out of bounds + if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); + else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor; + + // Wrap mode text measuring, to validate if + // it can be drawn or a new line is required + if (wrapMode == TEXT_WRAP_CHAR) + { + // Jump to next line if current character reach end of the box limits + if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset) + { + textOffsetX = 0.0f; + textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + + if (tempWrapCharMode) // Wrap at char level when too long words + { + wrapMode = TEXT_WRAP_WORD; + tempWrapCharMode = false; + } + } + } + else if (wrapMode == TEXT_WRAP_WORD) + { + if (codepoint == 32) lastSpaceIndex = c; + + // Get width to next space in line + int nextSpaceIndex = 0; + float nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex); + + int nextSpaceIndex2 = 0; + float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2); + + if (nextWordSize > textBounds.width - textBoundsWidthOffset) + { + // Considering the case the next word is longer than bounds + tempWrapCharMode = true; + wrapMode = TEXT_WRAP_CHAR; + } + else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset) + { + textOffsetX = 0.0f; + textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + } + } + + if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint + else + { + // TODO: There are multiple types of spaces in Unicode, + // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html + if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph + { + if (wrapMode == TEXT_WRAP_NONE) + { + // Draw only required text glyphs fitting the textBounds.width + if (textSizeX > textBounds.width) + { + if (textOffsetX <= (textBounds.width - glyphWidth - textBoundsWidthOffset - ellipsisWidth)) + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + else if (!textOverflow) + { + textOverflow = true; + + for (int j = 0; j < ellipsisWidth; j += ellipsisWidth/3) + { + DrawTextCodepoint(guiFont, '.', RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX + j, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + } + else + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + { + // Draw only glyphs inside the bounds + if ((textBoundsPosition.y + textOffsetY) <= (textBounds.y + textBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE))) + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + } + + if (guiFont.glyphs[index].advanceX == 0) textOffsetX += ((float)guiFont.recs[index].width*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + else textOffsetX += ((float)guiFont.glyphs[index].advanceX*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + } + + if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)(GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + posOffsetY += (textOffsetY + GuiGetStyle(DEFAULT, TEXT_SIZE)); + //--------------------------------------------------------------------------------- + } + +#if defined(RAYGUI_DEBUG_TEXT_BOUNDS) + GuiDrawRectangle(textBounds, 0, WHITE, Fade(BLUE, 0.4f)); +#endif +} + +// RayGui draw rectangle using default raygui plain style with borders +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color) +{ + if (color.a > 0) + { + // Draw rectangle filled with color + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, GuiFade(color, guiAlpha)); + } + + if (borderWidth > 0) + { + // Draw rectangle border lines with color + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha)); + } + +#if defined(RAYGUI_DEBUG_RECS_BOUNDS) + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, Fade(RED, 0.4f)); +#endif +} + +// Draw tooltip using control bounds +static void GuiTooltip(Rectangle controlRec) +{ + if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) + { + Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + + if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); + + int lineCount = 0; + GetTextLines(guiTooltipPtr, &lineCount); // Only using the line count + if ((controlRec.y + controlRec.height + textSize.y + 4 + 8*lineCount) > GetScreenHeight()) + controlRec.y -= (controlRec.height + textSize.y + 4 + 8*lineCount); + + // TODO: Probably TEXT_LINE_SPACING should be considered on panel size instead of hardcoding 8.0f + GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, textSize.y + 8.0f*lineCount }, NULL); + + int textPadding = GuiGetStyle(LABEL, TEXT_PADDING); + int textAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_PADDING, 0); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, textSize.y + 8.0f*lineCount }, guiTooltipPtr); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment); + GuiSetStyle(LABEL, TEXT_PADDING, textPadding); + } +} + +// Split controls text into multiple strings +// Also check for multiple columns (required by GuiToggleGroup()) +static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow) +{ + // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) + // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, + // all used memory is static... it has some limitations: + // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS + // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE + // NOTE: Those definitions could be externally provided if required + + // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user + // textRow is an externally provided array of integers that stores row number for every splitted string + + #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) + #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 + #endif + #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 + #endif + + static char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data) + static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) + memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); + + result[0] = buffer; + int counter = 1; + + if (textRow != NULL) textRow[0] = 0; + + // Count how many substrings text contains and point to every one of them + for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) + { + buffer[i] = text[i]; + if (buffer[i] == '\0') break; + else if ((buffer[i] == delimiter) || (buffer[i] == '\n')) + { + result[counter] = buffer + i + 1; + + if (textRow != NULL) + { + if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1; + else textRow[counter] = textRow[counter - 1]; + } + + buffer[i] = '\0'; // Set an end of string at this point + + counter++; + if (counter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + } + } + + *count = counter; + + return result; +} + +// Convert color data from RGB to HSV +// NOTE: Color data should be passed normalized +static Vector3 ConvertRGBtoHSV(Vector3 rgb) +{ + Vector3 hsv = { 0 }; + float min = 0.0f; + float max = 0.0f; + float delta = 0.0f; + + min = (rgb.x < rgb.y)? rgb.x : rgb.y; + min = (min < rgb.z)? min : rgb.z; + + max = (rgb.x > rgb.y)? rgb.x : rgb.y; + max = (max > rgb.z)? max : rgb.z; + + hsv.z = max; // Value + delta = max - min; + + if (delta < 0.00001f) + { + hsv.y = 0.0f; + hsv.x = 0.0f; // Undefined, maybe NAN? + return hsv; + } + + if (max > 0.0f) + { + // NOTE: If max is 0, this divide would cause a crash + hsv.y = (delta/max); // Saturation + } + else + { + // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined + hsv.y = 0.0f; + hsv.x = 0.0f; // Undefined, maybe NAN? + return hsv; + } + + // NOTE: Comparing float values could not work properly + if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta + else + { + if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow + else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan + } + + hsv.x *= 60.0f; // Convert to degrees + + if (hsv.x < 0.0f) hsv.x += 360.0f; + + return hsv; +} + +// Convert color data from HSV to RGB +// NOTE: Color data should be passed normalized +static Vector3 ConvertHSVtoRGB(Vector3 hsv) +{ + Vector3 rgb = { 0 }; + float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f; + long i = 0; + + // NOTE: Comparing float values could not work properly + if (hsv.y <= 0.0f) + { + rgb.x = hsv.z; + rgb.y = hsv.z; + rgb.z = hsv.z; + return rgb; + } + + hh = hsv.x; + if (hh >= 360.0f) hh = 0.0f; + hh /= 60.0f; + + i = (long)hh; + ff = hh - i; + p = hsv.z*(1.0f - hsv.y); + q = hsv.z*(1.0f - (hsv.y*ff)); + t = hsv.z*(1.0f - (hsv.y*(1.0f - ff))); + + switch (i) + { + case 0: + { + rgb.x = hsv.z; + rgb.y = t; + rgb.z = p; + } break; + case 1: + { + rgb.x = q; + rgb.y = hsv.z; + rgb.z = p; + } break; + case 2: + { + rgb.x = p; + rgb.y = hsv.z; + rgb.z = t; + } break; + case 3: + { + rgb.x = p; + rgb.y = q; + rgb.z = hsv.z; + } break; + case 4: + { + rgb.x = t; + rgb.y = p; + rgb.z = hsv.z; + } break; + case 5: + default: + { + rgb.x = hsv.z; + rgb.y = p; + rgb.z = q; + } break; + } + + return rgb; +} + +// Scroll bar control (used by GuiScrollPanel()) +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) +{ + GuiState state = guiState; + + // Is the scrollbar horizontal or vertical? + bool isVertical = (bounds.width > bounds.height)? false : true; + + // The size (width or height depending on scrollbar type) of the spinner buttons + const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? + (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : + (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; + + // Arrow buttons [<] [>] [∧] [∨] + Rectangle arrowUpLeft = { 0 }; + Rectangle arrowDownRight = { 0 }; + + // Actual area of the scrollbar excluding the arrow buttons + Rectangle scrollbar = { 0 }; + + // Slider bar that moves --[///]----- + Rectangle slider = { 0 }; + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + + int valueRange = maxValue - minValue; + if (valueRange <= 0) valueRange = 1; + + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size + + // Calculate rectangles for all of the components + arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ + (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)spinnerSize, (float)spinnerSize }; + + if (isVertical) + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), + bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), + (float)sliderSize }; + } + else // horizontal + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), + bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + (float)sliderSize, + bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN && + !CheckCollisionPointRec(mousePoint, arrowUpLeft) && + !CheckCollisionPointRec(mousePoint, arrowDownRight)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Handle mouse wheel + float scrollDelta = GUI_SCROLL_DELTA; + if (scrollDelta != 0) value += (int)scrollDelta; + + // Handle mouse button down + if (GUI_BUTTON_PRESSED) + { + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + // Check arrows click + if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (!CheckCollisionPointRec(mousePoint, slider)) + { + // If click on scrollbar position but not on slider, place slider directly on that position + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + + state = STATE_PRESSED; + } + + // Keyboard control on mouse hover scrollbar + /* + if (isVertical) + { + if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; + else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; + } + else + { + if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; + else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; + } + */ + } + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background + + GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background + GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar + + // Draw arrows (using icon if available) + if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) + { +#if defined(RAYGUI_NO_ICONS) + GuiDrawText(isVertical? "^" : "<", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText(isVertical? "v" : ">", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(isVertical? "#121#" : "#118#", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL + GuiDrawText(isVertical? "#120#" : "#119#", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL +#endif + } + //-------------------------------------------------------------------- + + return value; +} + +// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f +// WARNING: It multiplies current alpha by alpha scale factor +static Color GuiFade(Color color, float alpha) +{ + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + Color result = { color.r, color.g, color.b, (unsigned char)(color.a*alpha) }; + + return result; +} + +#if defined(RAYGUI_STANDALONE) +// Returns a Color struct from hexadecimal value +static Color GetColor(int hexValue) +{ + Color color; + + color.r = (unsigned char)(hexValue >> 24) & 0xff; + color.g = (unsigned char)(hexValue >> 16) & 0xff; + color.b = (unsigned char)(hexValue >> 8) & 0xff; + color.a = (unsigned char)hexValue & 0xff; + + return color; +} + +// Returns hexadecimal value for a Color +static int ColorToInt(Color color) +{ + return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a); +} + +// Check if point is inside rectangle +static bool CheckCollisionPointRec(Vector2 point, Rectangle rec) +{ + bool collision = false; + + if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && + (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true; + + return collision; +} + +// Formatting of text with variables to 'embed' +static const char *TextFormat(const char *text, ...) +{ + #if !defined(RAYGUI_TEXTFORMAT_MAX_SIZE) + #define RAYGUI_TEXTFORMAT_MAX_SIZE 256 + #endif + + static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE]; + + va_list args; + va_start(args, text); + vsnprintf(buffer, RAYGUI_TEXTFORMAT_MAX_SIZE, text, args); + va_end(args); + + return buffer; +} + +// Draw rectangle with vertical gradient fill color +// NOTE: This function is only used by GuiColorPicker() +static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) +{ + Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height }; + DrawRectangleGradientEx(bounds, color1, color2, color2, color1); +} + +// Split string into multiple strings +char **TextSplit(const char *text, char delimiter, int *count) +{ + // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) + // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, + // all used memory is static... it has some limitations: + // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS + // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE + + #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) + #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 + #endif + #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 + #endif + + static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; + static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; + memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); + + result[0] = buffer; + int counter = 0; + + if (text != NULL) + { + counter = 1; + + // Count how many substrings text contains and point to every one of them + for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) + { + buffer[i] = text[i]; + if (buffer[i] == '\0') break; + else if (buffer[i] == delimiter) + { + buffer[i] = '\0'; // Set an end of string at this point + result[counter] = buffer + i + 1; + counter++; + + if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + } + } + } + + *count = counter; + return result; +} + +// Get integer value from text +// NOTE: This function replaces atoi() [stdlib.h] +static int TextToInteger(const char *text) +{ + int value = 0; + int sign = 1; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1; + text++; + } + + for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0'); + + return value*sign; +} + +// Get float value from text +// NOTE: This function replaces atof() [stdlib.h] +// WARNING: Only '.' character is understood as decimal point +static float TextToFloat(const char *text) +{ + float value = 0.0f; + float sign = 1.0f; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1.0f; + text++; + } + + int i = 0; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); + + if (text[i++] != '.') value *= sign; + else + { + float divisor = 10.0f; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) + { + value += ((float)(text[i] - '0'))/divisor; + divisor = divisor*10.0f; + } + } + + return value; +} + +// Encode codepoint into UTF-8 text (char array size returned as parameter) +static const char *CodepointToUTF8(int codepoint, int *byteSize) +{ + static char utf8[6] = { 0 }; + int size = 0; + + if (codepoint <= 0x7f) + { + utf8[0] = (char)codepoint; + size = 1; + } + else if (codepoint <= 0x7ff) + { + utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); + utf8[1] = (char)((codepoint & 0x3f) | 0x80); + size = 2; + } + else if (codepoint <= 0xffff) + { + utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); + utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[2] = (char)((codepoint & 0x3f) | 0x80); + size = 3; + } + else if (codepoint <= 0x10ffff) + { + utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0); + utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); + utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[3] = (char)((codepoint & 0x3f) | 0x80); + size = 4; + } + + *byteSize = size; + + return utf8; +} + +// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found +// When a invalid UTF-8 byte is encountered, exiting as soon as possible and returning a '?'(0x3f) codepoint +// Total number of bytes processed are returned as a parameter +// NOTE: The standard says U+FFFD should be returned in case of errors +// but that character is not supported by the default font in raylib +static int GetCodepointNext(const char *text, int *codepointSize) +{ + const char *ptr = text; + int codepoint = 0x3f; // Codepoint (defaults to '?') + *codepointSize = 1; + + // Get current codepoint and bytes processed + if (0xf0 == (0xf8 & ptr[0])) + { + // 4 byte UTF-8 codepoint + if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]); + *codepointSize = 4; + } + else if (0xe0 == (0xf0 & ptr[0])) + { + // 3 byte UTF-8 codepoint + if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]); + *codepointSize = 3; + } + else if (0xc0 == (0xe0 & ptr[0])) + { + // 2 byte UTF-8 codepoint + if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks + codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]); + *codepointSize = 2; + } + else if (0x00 == (0x80 & ptr[0])) + { + // 1 byte UTF-8 codepoint + codepoint = ptr[0]; + *codepointSize = 1; + } + + return codepoint; +} +#endif // RAYGUI_STANDALONE + +#endif // RAYGUI_IMPLEMENTATION diff --git a/include/rini.h b/include/rini.h new file mode 100644 index 0000000..8a5f51f --- /dev/null +++ b/include/rini.h @@ -0,0 +1,844 @@ +/********************************************************************************************** +* +* rini v3.0 - A simple and easy-to-use ini-style files reader and writer +* +* DESCRIPTION: +* Load and save ini-style files with keys and values +* +* FEATURES: +* - Init/Config files reading and writing +* - Supported value types: int, string +* - Support comment lines and empty lines +* - Support custom line comment delimiter +* - Support custom value delimiters +* - Support value description comments +* - Support custom description custom delimiter +* - Support multi-word text values w/o quote delimiters +* - Support custom key and value spacings +* - Customizable maximum values capacity +* - Minimal C standard lib dependency (optional) +* +* LIMITATIONS: +* - [sections] lines not supported +* - Saving file requires complete rewrite +* +* POSSIBLE IMPROVEMENTS: +* - Support disabled key-value entries +* +* CONFIGURATION: +* #define RINI_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. +* +* #define RINI_MAX_LINE_SIZE +* Defines the maximum size of line buffer to read from file. +* Default value: 512 bytes (considering [key + text + desc] is 256 max size by default) +* +* #define RINI_MAX_KEY_SIZE +* Defines the maximum size of value key +* Default value: 64 bytes +* +* #define RINI_MAX_TEXT_SIZE +* Defines the maximum size of value text +* Default value: 128 bytes +* +* #define RINI_MAX_DESC_SIZE +* Defines the maximum size of value description +* Default value: 128 bytes +* +* #define RINI_MAX_VALUE_CAPACITY +* Defines the maximum number of values supported +* Default value: 128 entries support +* +* #define RINI_LINE_COMMENT_DELIMITER +* Define character used to comment lines, placed at beginning of line +* Most .ini files use semicolon ';' but '#' is also used +* Default value: '#' +* +* #define RINI_LINE_SECTION_DELIMITER +* Defines section lines start character +* Sections loading is not supported, lines are just skipped for now +* Default value: '[' +* +* #define RINI_VALUE_DELIMITER +* Defines a key value delimiter, in case it is defined. +* Most .ini files use '=' as value delimiter but ':' is also used or just whitespace +* Default value: ' ' +* +* #define RINI_VALUE_QUOTATION_MARKS +* Defines quotation marks to be used around text values +* Text values are determined checking text with atoi(), only for integer values, +* in case of float values they are always considered as text +* Default value: '\"' +* +* #define RINI_DESCRIPTION_DELIMITER +* Defines a property line-end comment delimiter +* This implementation allows adding inline comments after the value. +* Default value: '#' +* +* DEPENDENCIES: C standard library: +* - stdio.h: fopen(), feof(), fgets(), fclose(), fprintf() +* - stdlib.h: malloc(), calloc(), free() +* - string.h: memset(), memcpy(), strcmp(), strlen() +* +* VERSIONS HISTORY: +* 3.0 (xx-May-2025) REDESIGN: BREAKING: Removed the _config_ in naming +* ADDED: Flag to consider a text entry as text +* ADDED: Key and Value spacing defines +* +* 2.0 (26-Jan-2024) ADDED: Support custom comment lines (as config entries) +* ADDED: Use of quotation-marks and marks customization +* ADDED: rini_set_config_comment_line() +* ADDED: rini_get_config_value_fallback(), with fallback return value +* ADDED: rini_get_config_text_fallback(), with fallback return value +* REMOVED: Config header requirement, use comments entries +* REVIEWED: Some configuration default values, capacities +* REVIEWED: rini_save_config(), removed parameter +* REVIEWED: rini_save_config_from_memory(), removed parameter +* +* 1.0 (18-May-2023) First release, basic read/write functionality +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2023-2025 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RINI_H +#define RINI_H + +#define RINI_VERSION "3.0" + +// Function specifiers in case library is build/used as a shared library (Windows) +// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll +#if defined(_WIN32) + #if defined(BUILD_LIBTYPE_SHARED) + #define RINIAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) + #elif defined(USE_LIBTYPE_SHARED) + #define RINIAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) + #endif +#endif + +// Function specifiers definition +#ifndef RINIAPI + #define RINIAPI // Functions defined as 'extern' by default (implicit specifiers) +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Allow custom memory allocators +#ifndef RINI_MALLOC + #define RINI_MALLOC(sz) malloc(sz) +#endif +#ifndef RINI_CALLOC + #define RINI_CALLOC(n,sz) calloc(n,sz) +#endif +#ifndef RINI_FREE + #define RINI_FREE(p) free(p) +#endif + +// Simple log system to avoid printf() calls if required +// NOTE: Avoiding those calls, also avoids const strings memory usage +#define RINI_SUPPORT_LOG_INFO +#if defined(RINI_SUPPORT_LOG_INFO) + #define RINI_LOG(...) printf(__VA_ARGS__) +#else + #define RINI_LOG(...) +#endif + +#if !defined(RINI_MAX_LINE_SIZE) + #define RINI_MAX_LINE_SIZE 512 +#endif + +#if !defined(RINI_MAX_KEY_SIZE) + #define RINI_MAX_KEY_SIZE 64 +#endif + +#if !defined(RINI_MAX_TEXT_SIZE) + #define RINI_MAX_TEXT_SIZE 128 +#endif + +#if !defined(RINI_MAX_DESC_SIZE) + #define RINI_MAX_DESC_SIZE 128 +#endif + +#if !defined(RINI_MAX_VALUE_CAPACITY) + #define RINI_MAX_VALUE_CAPACITY 128 +#endif + +// Total space reserved for Key, +// Value starts after this spacing +#if !defined(RINI_KEY_SPACING) + #define RINI_KEY_SPACING 36 +#endif +// Total space reserved for Value, +// Description starts after this spacing +#if !defined(RINI_VALUE_SPACING) + #define RINI_VALUE_SPACING 32 +#endif + +// Line comment delimiter (starting string) +#if !defined(RINI_LINE_COMMENT_DELIMITER) + #define RINI_LINE_COMMENT_DELIMITER '#' +#endif + +// Line section delimiter -NOT USED- +#if !defined(RINI_LINE_SECTION_DELIMITER) + #define RINI_LINE_SECTION_DELIMITER '[' +#endif + +// Value delimiter, separator between key and value +#if !defined(RINI_VALUE_DELIMITER) + #define RINI_VALUE_DELIMITER ' ' +#endif + +// Use quotation marks for text values +// NOTE: Integer values do not use quotation-marks +#define RINI_USE_TEXT_QUOTATION_MARKS 1 +// Text value quoation marks +#if !defined(RINI_VALUE_QUOTATION_MARKS) + #define RINI_VALUE_QUOTATION_MARKS '\"' +#endif + +// Description delimiter, separator between value and description +#if !defined(RINI_DESCRIPTION_DELIMITER) + #define RINI_DESCRIPTION_DELIMITER '#' +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// rini value entry +typedef struct { + char key[RINI_MAX_KEY_SIZE]; // Value key identifier + char text[RINI_MAX_TEXT_SIZE]; // Value text + char desc[RINI_MAX_DESC_SIZE]; // Value description + bool is_text; // Value should be considered as text +} rini_value; + +// rini data +typedef struct { + rini_value *values; // Values array + unsigned int count; // Values count + unsigned int capacity; // Values capacity +} rini_data; + +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif + +//------------------------------------------------------------------------------------ +// Functions declaration +//------------------------------------------------------------------------------------ +RINIAPI rini_data rini_load(const char *file_name); // Load data from file (*.ini) or create a new rini object (pass NULL) +RINIAPI rini_data rini_load_from_memory(const char *text); // Load data from text buffer +RINIAPI void rini_save(rini_data data, const char *file_name); // Save data to file, with custom header +RINIAPI char *rini_save_to_memory(rini_data data); // Save data to text buffer ('\0' EOL) +RINIAPI void rini_unload(rini_data *data); // Unload data from memory + +RINIAPI int rini_get_value(rini_data data, const char *key); // Get value int for provided key, returns 0 if not found +RINIAPI const char *rini_get_value_text(rini_data data, const char *key); // Get value text for provided key +RINIAPI const char *rini_get_value_description(rini_data data, const char *key); // Get value description for provided key + +RINIAPI int rini_get_value_fallback(rini_data data, const char *key, int fallback); // Get value for provided key with default value fallback if not found or not valid +RINIAPI const char *rini_get_value_text_fallback(rini_data data, const char *key, const char *fallback); // Get value text for provided key with fallback if not found or not valid + +RINIAPI int rini_set_comment_line(rini_data *data, const char *comment); // Set comment line + +// Set value int/text and description for existing key or create a new entry +// NOTE: When setting a text value, if id does not exist, a new entry is automatically created +RINIAPI int rini_set_value(rini_data *data, const char *key, int value, const char *desc); +RINIAPI int rini_set_value_text(rini_data *data, const char *key, const char *text, const char *desc); + +// Set value description for existing key +// WARNING: Key must exist to add description, if a description exists, it is updated +RINIAPI int rini_set_value_description(rini_data *data, const char *key, const char *desc); + +#ifdef __cplusplus +} +#endif + +#endif // RINI_H + +/*********************************************************************************** +* +* RINI IMPLEMENTATION +* +************************************************************************************/ + +#if defined(RINI_IMPLEMENTATION) + +#include // Required for: fopen(), feof(), fgets(), fclose(), fprintf() +#include // Required for: malloc(), calloc(), free() +#include // Required for: memset(), memcpy(), strcmp(), strlen() + +//---------------------------------------------------------------------------------- +// Defines and macros +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Global variables definition +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- +static int rini_read_key(const char *buffer, char *key); // Get key from a buffer line containing key-value-(description) +static int rini_read_value_text(const char *buffer, char *text, char *desc, bool *is_text); // Get value text (and description) from a buffer line + +static int rini_text_to_int(const char *text); // Convert text to int value (if possible), same as atoi() + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +// Load data from file (.ini) +rini_data rini_load(const char *file_name) +{ + rini_data data = { 0 }; + unsigned int value_counter = 0; + + // Init data to max capacity + data.capacity = RINI_MAX_VALUE_CAPACITY; + data.values = (rini_value *)RINI_CALLOC(RINI_MAX_VALUE_CAPACITY, sizeof(rini_value)); + + if (file_name != NULL) + { + FILE *rini_file = fopen(file_name, "rt"); + + if (rini_file != NULL) + { + char buffer[RINI_MAX_LINE_SIZE] = { 0 }; // Buffer to read every text line + + // First pass to count valid lines + while (fgets(buffer, RINI_MAX_LINE_SIZE, rini_file)) + { + // WARNING: fgets() keeps line endings, doesn't have any special options for converting line endings, + // but on Windows, when reading file 'rt', line endings are converted from \r\n to just \n + + // Skip commented lines and empty lines + // NOTE: We are also skipping sections delimiters + if ((buffer[0] != RINI_LINE_COMMENT_DELIMITER) && + (buffer[0] != RINI_LINE_SECTION_DELIMITER) && + (buffer[0] != '\n') && (buffer[0] != '\r') && (buffer[0] != '\0')) value_counter++; + } + + // WARNING: We can't store more values than its max capacity + data.count = (value_counter > RINI_MAX_VALUE_CAPACITY)? RINI_MAX_VALUE_CAPACITY : value_counter; + + if (data.count > 0) + { + rewind(rini_file); + value_counter = 0; + + // Second pass to read data + while (fgets(buffer, RINI_MAX_LINE_SIZE, rini_file)) + { + // WARNING: fgets() keeps line endings, doesn't have any special options for converting line endings, + // but on Windows, when reading file 'rt', line endings are converted from \r\n to just \n + + // Skip commented lines and empty lines + if ((buffer[0] != RINI_LINE_COMMENT_DELIMITER) && + (buffer[0] != RINI_LINE_SECTION_DELIMITER) && + (buffer[0] != '\n') && (buffer[0] != '\r') && (buffer[0] != '\0')) + { + // Get key identifier string + memset(data.values[value_counter].key, 0, RINI_MAX_KEY_SIZE); + rini_read_key(buffer, data.values[value_counter].key); + rini_read_value_text(buffer, data.values[value_counter].text, data.values[value_counter].desc, &data.values[value_counter].is_text); + + value_counter++; + + // Stop reading if first count reached to avoid overflow in case count == RINI_MAX_VALUE_CAPACITY + if (value_counter >= data.count) break; + } + } + } + + fclose(rini_file); + } + } + + return data; +} + +// Load data from text buffer +// NOTE: Comments and empty lines are ignored +rini_data rini_load_from_memory(const char *text) +{ + #define RINI_MAX_TEXT_LINES RINI_MAX_VALUE_CAPACITY*2 // Consider possible comments and empty lines + + rini_data data = { 0 }; + unsigned int value_counter = 0; + + // Init data to max capacity + data.capacity = RINI_MAX_VALUE_CAPACITY; + data.values = (rini_value *)RINI_CALLOC(RINI_MAX_VALUE_CAPACITY, sizeof(rini_value)); + + if (text != NULL) + { + // Split text by line-breaks + const char *lines[RINI_MAX_TEXT_LINES] = { 0 }; + int textSize = (int)strlen(text); + lines[0] = text; + int line_counter = 1; + + for (int i = 0, k = 1; (i < textSize) && (line_counter < RINI_MAX_TEXT_LINES); i++) + { + if (text[i] == '\n') + { + lines[k] = &text[i + 1]; // WARNING: next value is valid? + line_counter += 1; + k++; + } + } + + // Count possible values in lines + for (int l = 0; l < line_counter; l++) + { + // Skip commented lines and empty lines + // NOTE: We are also skipping sections delimiters + if ((lines[l][0] != RINI_LINE_COMMENT_DELIMITER) && + (lines[l][0] != RINI_LINE_SECTION_DELIMITER) && + (lines[l][0] != '\n') && (lines[l][0] != '\r') && (lines[l][0] != '\0')) value_counter++; + } + + // WARNING: We can't store more values than its max capacity + data.count = (value_counter > RINI_MAX_VALUE_CAPACITY)? RINI_MAX_VALUE_CAPACITY : value_counter; + + // Process lines to get keys and values + if (data.count > 0) + { + value_counter = 0; + + // Second pass to read data + for (int l = 0; l < line_counter; l++) + { + // Skip commented lines and empty lines + if ((lines[l][0] != RINI_LINE_COMMENT_DELIMITER) && + (lines[l][0] != RINI_LINE_SECTION_DELIMITER) && + (lines[l][0] != '\n') && (lines[l][0] != '\r') && (lines[l][0] != '\0')) + { + // Get key identifier string + memset(data.values[value_counter].key, 0, RINI_MAX_KEY_SIZE); + rini_read_key(lines[l], data.values[value_counter].key); + rini_read_value_text(lines[l], data.values[value_counter].text, data.values[value_counter].desc, &data.values[value_counter].is_text); + + value_counter++; + + // Stop reading if first count reached to avoid overflow in case count == RINI_MAX_VALUE_CAPACITY + if (value_counter >= data.count) break; + } + } + } + } + + return data; +} + +// Save data to file (*.ini) +void rini_save(rini_data data, const char *file_name) +{ + FILE *rini_file = fopen(file_name, "wt"); + + if (rini_file != NULL) + { + char valuestr[RINI_MAX_TEXT_SIZE + 2] = { 0 }; // Useful for text processing, adding quotation marks if required + + for (unsigned int i = 0; i < data.count; i++) + { + if ((data.values[i].key[0] == '\0') && (data.values[i].text[0] == RINI_LINE_COMMENT_DELIMITER)) + { + if (data.values[i].desc[0] != '\0') fprintf(rini_file, "%c %s\n", RINI_LINE_COMMENT_DELIMITER, data.values[i].desc); + else fprintf(rini_file, "%c\n", RINI_LINE_COMMENT_DELIMITER); + } + else + { + memset(valuestr, 0, RINI_MAX_TEXT_SIZE + 2); +#if RINI_USE_TEXT_QUOTATION_MARKS + // Add quotation marks if required + if (data.values[i].is_text) snprintf(valuestr, 130, "%c%s%c", RINI_VALUE_QUOTATION_MARKS, data.values[i].text, RINI_VALUE_QUOTATION_MARKS); +#else + snprintf(valuestr, RINI_MAX_TEXT_SIZE + 2, "%s", data.values[i].text); +#endif + fprintf(rini_file, "%-*s %c %-*s %c %s\n", RINI_KEY_SPACING, data.values[i].key, RINI_VALUE_DELIMITER, + RINI_VALUE_SPACING, data.values[i].is_text? valuestr : data.values[i].text, + RINI_DESCRIPTION_DELIMITER, data.values[i].desc); + } + } + + fclose(rini_file); + } +} + +// Save data to text buffer ('\0' EOL) +char *rini_save_to_memory(rini_data data) +{ + #define RINI_MAX_TEXT_FILE_SIZE 4096 + + // Verify required data size is smaller than memory buffer size + // NOTE: We add 64 extra possible characters by entry line + int requiredSize = 0; + for (unsigned int i = 0; i < data.count; i++) requiredSize += ((int)strlen(data.values[i].key) + (int)strlen(data.values[i].text) + (int)strlen(data.values[i].desc) + 64); + if (requiredSize > RINI_MAX_TEXT_FILE_SIZE) RINI_LOG("WARNING: Required data.ini size is bigger than max supported memory size, increase RINI_MAX_TEXT_FILE_SIZE\n"); + + // NOTE: Using a static buffer to avoid de-allocation requirement on user side + static char text[RINI_MAX_TEXT_FILE_SIZE] = { 0 }; + memset(text, 0, RINI_MAX_TEXT_FILE_SIZE); + int offset = 0; + + char valuestr[RINI_MAX_TEXT_FILE_SIZE + 2] = { 0 }; // Useful for text processing, adding quotation marks if required + + for (unsigned int i = 0; i < data.count; i++) + { + if ((data.values[i].key[0] == '\0') && (data.values[i].text[0] == RINI_LINE_COMMENT_DELIMITER)) + { + if (data.values[i].desc[0] != '\0') offset += snprintf(text + offset, RINI_MAX_LINE_SIZE, "%c %s\n", RINI_LINE_COMMENT_DELIMITER, data.values[i].desc); + else offset += snprintf(text + offset, RINI_MAX_LINE_SIZE, "%c\n", RINI_LINE_COMMENT_DELIMITER); + } + else + { + memset(valuestr, 0, RINI_MAX_TEXT_FILE_SIZE + 2); +#if RINI_USE_TEXT_QUOTATION_MARKS + // Add quotation marks if required + if (data.values[i].is_text) snprintf(valuestr, RINI_MAX_TEXT_FILE_SIZE + 2, "%c%s%c", RINI_VALUE_QUOTATION_MARKS, data.values[i].text, RINI_VALUE_QUOTATION_MARKS); +#else + snprintf(valuestr, RINI_MAX_TEXT_FILE_SIZE + 2, "%s", data.values[i].text); +#endif + offset += snprintf(text + offset, RINI_MAX_LINE_SIZE, "%-*s %c %-*s %c %s\n", RINI_KEY_SPACING, data.values[i].key, RINI_VALUE_DELIMITER, + RINI_VALUE_SPACING, data.values[i].is_text? valuestr : data.values[i].text, + RINI_DESCRIPTION_DELIMITER, data.values[i].desc); + } + } + + return text; +} + +// Unload data +void rini_unload(rini_data *data) +{ + RINI_FREE(data->values); + + data->values = NULL; + data->count = 0; + data->capacity = 0; +} + +// Get value for provided key, returns 0 if not found or not valid +int rini_get_value(rini_data data, const char *key) +{ + int value = 0; + + for (unsigned int i = 0; i < data.count; i++) + { + if (strcmp(key, data.values[i].key) == 0) // Key found + { + value = rini_text_to_int(data.values[i].text); + break; + } + } + + return value; +} + +// Get value for provided key with default value fallback if not found or not valid +int rini_get_value_fallback(rini_data data, const char *key, int fallback) +{ + int value = fallback; + + for (unsigned int i = 0; i < data.count; i++) + { + if (strcmp(key, data.values[i].key) == 0) // Key found + { + // TODO: Detect if conversion fails... + value = rini_text_to_int(data.values[i].text); + break; + } + } + + return value; +} + +// Get text for string id +const char *rini_get_value_text(rini_data data, const char *key) +{ + const char *text = NULL; + + for (unsigned int i = 0; i < data.count; i++) + { + if (strcmp(key, data.values[i].key) == 0) // Key found + { + text = data.values[i].text; + break; + } + } + + return text; +} + +// Get value text for provided key with fallback if not found or not valid +RINIAPI const char *rini_get_value_text_fallback(rini_data data, const char *key, const char *fallback) +{ + const char *text = fallback; + + for (unsigned int i = 0; i < data.count; i++) + { + if (strcmp(key, data.values[i].key) == 0) // Key found + { + text = data.values[i].text; + break; + } + } + + return text; +} + +// Get description for string id +const char *rini_get_value_description(rini_data data, const char *key) +{ + const char *desc = NULL; + + for (unsigned int i = 0; i < data.count; i++) + { + if (strcmp(key, data.values[i].key) == 0) // Key found + { + desc = data.values[i].desc; + break; + } + } + + return desc; +} + +// Set comment line +int rini_set_comment_line(rini_data *data, const char *comment) +{ + int result = -1; + char text[2] = { RINI_LINE_COMMENT_DELIMITER, '\0' }; + + result = rini_set_value_text(data, NULL, text, comment); + + return result; +} + +// Set value and description for existing key or create a new entry +int rini_set_value(rini_data *data, const char *key, int value, const char *desc) +{ + int result = -1; + char value_text[RINI_MAX_TEXT_SIZE] = { 0 }; + + snprintf(value_text, RINI_MAX_TEXT_SIZE, "%i", value); + + result = rini_set_value_text(data, key, value_text, desc); + + data->values[data->count - 1].is_text = false; + + return result; +} + +// Set value text and description for existing key or create a new entry +// NOTE: When setting a text value, if id does not exist, a new entry is automatically created +int rini_set_value_text(rini_data *data, const char *key, const char *text, const char *desc) +{ + int result = -1; + + //if ((text == NULL) || (text[0] == '\0')) return result; // WARNING: It avoids empty text + + if (key != NULL) + { + // Try to find key and update text and description + for (unsigned int i = 0; i < data->count; i++) + { + if (strcmp(key, data->values[i].key) == 0) // Key found + { + memset(data->values[i].text, 0, RINI_MAX_TEXT_SIZE); + memcpy(data->values[i].text, text, strlen(text)); + + memset(data->values[i].desc, 0, RINI_MAX_DESC_SIZE); + if (desc != NULL) memcpy(data->values[i].desc, desc, strlen(desc)); + result = 0; + break; + } + } + } + + // Key not found, we add a new entry if possible + if (result == -1) + { + if (data->count < data->capacity) + { + // NOTE: Supporting comment line entries + if ((key == NULL) && (text[0] == RINI_LINE_COMMENT_DELIMITER)) + { + data->values[data->count].key[0] = '\0'; + data->values[data->count].text[0] = RINI_LINE_COMMENT_DELIMITER; + if (desc != NULL) for (int i = 0; (i < RINI_MAX_DESC_SIZE) && (desc[i] != '\0'); i++) + data->values[data->count].desc[i] = desc[i]; + else data->values[data->count].desc[0] = '\0'; + } + else + { + // NOTE: We do a manual copy to avoid possible overflows on input data + for (int i = 0; (i < RINI_MAX_KEY_SIZE) && (key[i] != '\0'); i++) data->values[data->count].key[i] = key[i]; + for (int i = 0; (i < RINI_MAX_TEXT_SIZE) && (text[i] != '\0'); i++) data->values[data->count].text[i] = text[i]; + if (desc != NULL) for (int i = 0; (i < RINI_MAX_DESC_SIZE) && (desc[i] != '\0'); i++) data->values[data->count].desc[i] = desc[i]; + } + + data->values[data->count].is_text = true; + data->count++; + result = 0; + } + } + + return result; +} + +// Set value description for existing key +// WARNING: Key must exist to add description, if a description exists, it is updated +int rini_set_value_description(rini_data *data, const char *key, const char *desc) +{ + int result = 1; + + for (unsigned int i = 0; i < data->count; i++) + { + if (strcmp(key, data->values[i].key) == 0) // Key found + { + memset(data->values[i].desc, 0, RINI_MAX_DESC_SIZE); + if (desc != NULL) memcpy(data->values[i].desc, desc, strlen(desc)); + result = 0; + break; + } + } + + return result; +} + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- +// Get string id from a buffer line containing id-value pair +static int rini_read_key(const char *buffer, char *key) +{ + int len = 0; + while ((buffer[len] != '\0') && (buffer[len] != ' ') && (buffer[len] != RINI_VALUE_DELIMITER)) len++; // Skip keyentifier + + memcpy(key, buffer, len); + + return len; +} + +// Get string-value from a buffer line containing id-value pair +static int rini_read_value_text(const char *buffer, char *text, char *desc, bool *is_text) +{ + char *buffer_ptr = (char *)buffer; + + // Expected line structure: + // [key][spaces?][delimiter?][spaces?][quot-mark?][textValue][quot-mark?][spaces?][[;][#]description?] + // We need to skip spaces, check for delimiter (if required), skip spaces, and get text value + + while ((buffer_ptr[0] != '\0') && (buffer_ptr[0] != ' ')) buffer_ptr++; // Skip keyentifier + + while ((buffer_ptr[0] != '\0') && (buffer_ptr[0] == ' ')) buffer_ptr++; // Skip line spaces before text value or delimiter + +#if defined(RINI_VALUE_DELIMITER) + if (buffer_ptr[0] == RINI_VALUE_DELIMITER) + { + buffer_ptr++; // Skip delimiter + + while ((buffer_ptr[0] != '\0') && (buffer_ptr[0] == ' ')) buffer_ptr++; // Skip line spaces before text value + } +#endif + + // Now buffer_ptr should be pointing to the start of value + + int len = 0; + while ((buffer_ptr[len] != '\0') && + (buffer_ptr[len] != '\r') && + (buffer_ptr[len] != '\n')) len++; // Get text-value and description length (to the end of line) + + // Now we got the length from text-value start to end of line + + int value_len = len; + int desc_pos = 0; +#if defined(RINI_DESCRIPTION_DELIMITER) + // Scan text looking for text-value description (if used) + for (; desc_pos < len; desc_pos++) + { + if (buffer_ptr[desc_pos] == RINI_DESCRIPTION_DELIMITER) + { + value_len = desc_pos - 1; + while (buffer_ptr[value_len] == ' ') value_len--; + + value_len++; + + desc_pos++; // Skip delimiter and following spaces + while (buffer_ptr[desc_pos] == ' ') desc_pos++; + break; + } + } +#endif + +#if RINI_USE_TEXT_QUOTATION_MARKS + // Remove starting quotation-mark from text (if being used) + if (buffer_ptr[0] == RINI_VALUE_QUOTATION_MARKS) + { + buffer_ptr++; desc_pos--; len--; value_len--; + + // Remove ending quotation-mark from text (if being used) + if (buffer_ptr[value_len - 1] == RINI_VALUE_QUOTATION_MARKS) { value_len--; } + + *is_text = true; + } +#endif + + // Clear text buffers to be updated + memset(text, 0, RINI_MAX_TEXT_SIZE); + memset(desc, 0, RINI_MAX_DESC_SIZE); + + // Copy value-text and description to provided pointers + memcpy(text, buffer_ptr, value_len); + memcpy(desc, buffer_ptr + desc_pos, ((len - desc_pos) > (RINI_MAX_DESC_SIZE - 1))? (RINI_MAX_DESC_SIZE - 1) : (len - desc_pos)); + + return len; +} + +// Convert text to int value (if possible), same as atoi() +static int rini_text_to_int(const char *text) +{ + int value = 0; + int sign = 1; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1; + text++; + } + + int i = 0; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0'); + + //if (strlen(text) != i) // Text starts with numbers but contains some text after that... + + return value*sign; +} + +#endif // RINI_IMPLEMENTATION diff --git a/meson.build b/meson.build index 74b4ed5..50a3c82 100644 --- a/meson.build +++ b/meson.build @@ -3,6 +3,7 @@ project ('Raylib-vala', [ 'vala', 'c' ], version: '4.2') # Variables source_dir = meson.current_source_dir () vapi_dir = source_dir / 'vapi' +include_dir = source_dir / 'include' # Build variables project_dependency = [] @@ -18,7 +19,10 @@ valac_arguments = [ ] cc_arguments = [ - '-DPHYSAC_IMPLEMENTATION' + '-I' + include_dir, + '-DRAYGUI_IMPLEMENTATION', + '-DPHYSAC_IMPLEMENTATION', + '-DRINI_IMPLEMENTATION' ] add_project_arguments (valac_arguments, language: 'vala') @@ -26,13 +30,13 @@ add_project_arguments (cc_arguments, language: 'c') project_dependency = [ valac.find_library ('raylib', dirs: vapi_dir), + valac.find_library ('raymath', dirs: vapi_dir), valac.find_library ('rlgl', dirs: vapi_dir), valac.find_library ('physac', dirs: vapi_dir), + valac.find_library ('raygui', dirs: vapi_dir), cc.find_library ('raylib'), cc.find_library ('m') ] -subdir ('examples/Camera3D') -subdir ('examples/SmoothPixel') -subdir ('examples/Physac') +subdir('examples') diff --git a/vala-lint.conf b/vala-lint.conf index a7f3b60..de9c2af 100644 --- a/vala-lint.conf +++ b/vala-lint.conf @@ -4,7 +4,7 @@ double-semicolon=error double-spaces=error ellipsis=error line-length=warn -naming-convention=null +naming-convention=error no-space=error note=warn space-before-paren=error diff --git a/vapi/physac.deps b/vapi/physac.deps new file mode 100644 index 0000000..3dedc24 --- /dev/null +++ b/vapi/physac.deps @@ -0,0 +1,2 @@ +raylib +raymath diff --git a/vapi/physac.vapi b/vapi/physac.vapi new file mode 100644 index 0000000..7268d81 --- /dev/null +++ b/vapi/physac.vapi @@ -0,0 +1,212 @@ +using Raylib; +using Raymath; + +[CCode (cprefix = "", cheader_filename = "physac.h")] +namespace Physac { + [CCode (cname = "PHYSAC_MAX_BODIES")] + public const int MAX_BODIES; + + [CCode (cname = "PHYSAC_MAX_MANIFOLDS")] + public const int MAX_MANIFOLDS; + + [CCode (cname = "PHYSAC_MAX_VERTICES")] + public const int MAX_VERTICES; + + [CCode (cname = "PHYSAC_CIRCLE_VERTICES")] + public const int CIRCLE_VERTICES; + + [CCode (cname = "PHYSAC_COLLISION_ITERATIONS")] + public const int COLLISION_ITERATIONS; + + [CCode (cname = "PHYSAC_PI")] + public const float PI; + + [CCode (cname = "PHYSAC_DEG2RAD")] + public const float DEG2RAD; + + // Matrix2x2 type (used for polygon shape rotation matrix) + [SimpleType] + [CCode (cname = "Matrix2x2", has_type_id = false)] + public struct Matrix2x2 { + float m00; + float m01; + float m10; + float m11; + } + + [CCode (cname = "PhysicsShapeType", cprefix = "PHYSICS_", has_type_id = false)] + public enum PhysicsShapeType { + CIRCLE, + POLYGON + } // PhysicsShapeType + + [CCode (cname = "PhysicsVertexData", has_type_id = false)] + public struct PhysicsVertexData { + [CCode (cname = "vertexCount")] + public uint vertex_count; // Vertex count (positions and normals) + + public Vector2 positions[MAX_VERTICES]; // Vertex positions vectors + + public Vector2 normals[MAX_VERTICES]; // Vertex normals vectors + } + + [CCode (cname = "PhysicsShape", has_type_id = false)] + public struct PhysicsShape { + public PhysicsShapeType type; // Shape type (circle or polygon) + + public PhysicsBody body; // Shape physics body data pointer + + [CCode (cname = "vertexData")] + public PhysicsVertexData vertex_data; // Shape vertices data (used for polygon shapes) + + public float radius; // Shape radius (used for circle shapes) + + public Matrix2x2 transform; // Vertices transform matrix 2x2 + } + + [CCode (cname = "PhysicsBodyData", has_type_id = false)] + public class PhysicsBodyData { + public uint id; // Unique identifier + + public bool enabled; // Enabled dynamics state (collisions are calculated anyway) + + public Vector2 position; // Physics body shape pivot + + public Vector2 velocity; // Current linear velocity applied to position + + public Vector2 force; // Current linear force (reset to 0 every step) + + [CCode (cname = "angularVelocity")] + public float angular_velocity; // Current angular velocity applied to orient + + public float torque; // Current angular force (reset to 0 every step) + + public float orient; // Rotation in radians + + public float inertia; // Moment of inertia + + [CCode (cname = "inverseInertia")] + public float inverse_inertia; // Inverse value of inertia + + public float mass; // Physics body mass + + [CCode (cname = "inverseMass")] + public float inverse_mass; // Inverse value of mass + + [CCode (cname = "staticFriction")] + public float static_friction; // Friction when the body has not movement (0 to 1) + + [CCode (cname = "dynamicFriction")] + public float dynamic_friction; // Friction when the body has movement (0 to 1) + + public float restitution; // Restitution coefficient of the body (0 to 1) + + [CCode (cname = "useGravity")] + public bool use_gravity; // Apply gravity force to dynamics + + [CCode (cname = "isGrounded")] + public bool is_grounded; // Physics grounded on other body state + + [CCode (cname = "freezeOrient")] + public bool freeze_orient; // Physics rotation constraint + + public PhysicsShape shape; // Physics body shape information (type, radius, vertices, transform) + } + + [CCode (cname = "PhysicsBodyData", unref_function = "", + has_type_id = false)] + public class PhysicsBody : PhysicsBodyData {} + + [CCode (cname = "PhysicsManifoldData", has_type_id = false)] + public struct PhysicsManifoldData { + public uint id; // Unique identifier + + [CCode (cname = "bodyA")] + public PhysicsBody body_a; // Manifold first physics body reference + + [CCode (cname = "bodyB")] + public PhysicsBody body_b; // Manifold second physics body reference + + public float penetration; // Depth of penetration from collision + + public Vector2 normal; // Normal direction vector from 'a' to 'b' + + public Vector2 contacts[2]; // Points of contact during collision + + [CCode (cname = "contactsCount")] + public uint contacts_count; // Current collision number of contacts + + public float restitution; // Mixed restitution during collision + + [CCode (cname = "dynamicFriction")] + public float dynamic_friction; // Mixed dynamic friction during collision + + [CCode (cname = "staticFriction")] + public float static_friction; // Mixed static friction during collision + } + + //---------------------------------------------------------------------------------- + // Module Functions Declaration + //---------------------------------------------------------------------------------- + + // Physics system management + [CCode (cname = "InitPhysics")] + public static void init_physics (); // Initializes physics system + + [CCode (cname = "UpdatePhysics")] + public static void update_physics (); // Update physics system + + [CCode (cname = "ResetPhysics")] + public static void reset_physics(); // Reset physics system (global variables) + + [CCode (cname = "ClosePhysics")] + public static void close_physics (); // Close physics system and unload used memory + + [CCode (cname = "SetPhysicsTimeStep")] + public static void set_physics_time_step (double delta); // Sets physics fixed time step in milliseconds. 1.666666 by default + + [CCode (cname = "SetPhysicsGravity")] + public static void set_physics_gravity (float x, float y); // Sets physics global gravity force + + // Physic body creation/destroy + [CCode (cname = "CreatePhysicsBodyCircle")] + public static PhysicsBody create_physics_body_circle (Vector2 pos, float radius, float density); // Creates a new circle physics body with generic parameters + + [CCode (cname = "CreatePhysicsBodyRectangle")] + public static PhysicsBody create_physics_body_rectangle (Vector2 pos, float width, float height, float density); // Creates a new rectangle physics body with generic parameters + + [CCode (cname = "CreatePhysicsBodyPolygon")] + public static PhysicsBody create_physics_body_polygon (Vector2 pos, float radius, int sides, float density); // Creates a new polygon physics body with generic parameters + + [CCode (cname = "DestroyPhysicsBody")] + public static void destroy_physics_body (PhysicsBody body); // Destroy a physics body + + // Physic body forces + [CCode (cname = "PhysicsAddForce")] + public static void physics_add_force (PhysicsBody body, Vector2 force); // Adds a force to a physics body + + [CCode (cname = "PhysicsAddForce")] + public static void physics_add_torque (PhysicsBody body, float amount); // Adds an angular force to a physics body + + [CCode (cname = "PhysicsShatter")] + public static void physics_shatter (PhysicsBody body, Vector2 position, float force); // Shatters a polygon shape physics body to little physics bodies with explosion force + + [CCode (cname = "SetPhysicsBodyRotation")] + public static void set_physics_body_rotation (PhysicsBody body, float radians); // Sets physics body shape transform based on radians parameter + + // Query physics info + [CCode (cname = "GetPhysicsBody")] + public static PhysicsBody get_physics_body (int index); // Returns a physics body of the bodies pool at a specific index + + [CCode (cname = "GetPhysicsBodiesCount")] + public static int get_physics_bodies_count (); // Returns the current amount of created physics bodies + + [CCode (cname = "GetPhysicsShapeType")] + public static PhysicsShapeType get_physics_shape_type (int index); // Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) + + [CCode (cname = "GetPhysicsShapeVerticesCount")] + public static int get_physics_shape_vertices_count (int index); // Returns the amount of vertices of a physics body shape + + [CCode (cname = "GetPhysicsShapeVertex")] + public static Vector2 get_physics_shape_vertex (PhysicsBody body, int vertex); // Returns transformed position of a body shape (body position + vertex transformed position)} +} diff --git a/vapi/raygui.deps b/vapi/raygui.deps new file mode 100644 index 0000000..b6ac0af --- /dev/null +++ b/vapi/raygui.deps @@ -0,0 +1 @@ +raylib diff --git a/vapi/raygui.vapi b/vapi/raygui.vapi new file mode 100644 index 0000000..7712297 --- /dev/null +++ b/vapi/raygui.vapi @@ -0,0 +1,715 @@ +using Raylib; +using Raymath; + +[CCode (cprefix = "", cheader_filename = "raygui.h")] +namespace Raygui { + [CCode (cname = "RAYGUI_VERSION_MAJOR")] + public const string GUI_VERSION_MAJOR; + + [CCode (cname = "RAYGUI_VERSION_MINOR")] + public const string GUI_VERSION_MINOR; + + [CCode (cname = "RAYGUI_VERSION_PATCH")] + public const string GUI_VERSION_PATCH; + + [CCode (cname = "RAYGUI_VERSION")] + public const string GUI_VERSION; + + [CCode (cname = "GUI_BUTTON_DOWN")] + public static bool gui_button_down (); + + [CCode (cname = "GUI_BUTTON_DOWN_ALT")] + public static bool gui_button_down_alt (); + + [CCode (cname = "GUI_BUTTON_PRESSED")] + public static bool gui_button_pressed (); + + [CCode (cname = "GUI_BUTTON_RELEASED")] + public static bool gui_button_released (); + + [CCode (cname = "GUI_SCROLL_DELTA")] + public static float gui_scroll_delta (); + + [CCode (cname = "GUI_POINTER_POSITION")] + public static Vector2 gui_pointer_position (); + + [CCode (cname = "GUI_KEY_DOWN")] + public static bool gui_key_down (KeyboardKey key); + + [CCode (cname = "GUI_KEY_PRESSED")] + public static bool gui_key_pressed (KeyboardKey key); + + [CCode (cname = "GUI_INPUT_KEY")] + public static char gui_input_key (); + + // Style property + // NOTE: Used when exporting style as code for convenience + [SimpleType] + [CCode (cname = "GuiStyleProp", has_type_id = false)] + public struct StyleProp { + [CCode (cname = "controlId")] + public ushort control_id; + + [CCode (cname = "propertyId")] + public ushort property_id; + + [CCode (cname = "propertyValue")] + public int property_value; + } // StyleProp + + // RayGui control state + [CCode (cname = "GuiState", cprefix = "STATE_", has_type_id = false)] + public enum State { + NORMAL, + FOCUSED, + PRESSED, + DISABLED; + } // State + + // RayGui control text alignment + [CCode (cname = "GuiTextAlignment", cprefix = "TEXT_ALIGN_", has_type_id = false)] + public enum TextAlignment { + LEFT, + CENTER, + RIGHT + } // TextAlignment + + // RayGui control text alignment vertical + // NOTE: Text vertical position inside the text bounds + [CCode (cname = "GuiTextAlignmentVertical", cprefix = "TEXT_ALIGN_", has_type_id = false)] + public enum TextAlignmentVertical { + TOP, + MIDDLE, + BOTTOM + } // TextAlignmentVertical + + // RayGui control text wrap mode + // NOTE: Useful for multiline text + [CCode (cname = "GuiTextWrapMode", cprefix = "TEXT_WRAP_", has_type_id = false)] + public enum TextWrapMode { + NONE, + CHAR, + WORD + } // TextWrapMode + + // RayGui controls + [CCode (cname = "GuiControl", cprefix = "", has_type_id = false)] + public enum Control { + // Default -> populates to all controls when set + DEFAULT, + + // Basic controls + LABEL, // Used also for: LABELBUTTON + BUTTON, + TOGGLE, // Used also for: TOGGLEGROUP + SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER + [CCode (cname = "PROGRESSBAR")] + PROGRESS_BAR, + [CCode (cname = "CHECKBOX")] + CHECK_BOX, + [CCode (cname = "COMBOBOX")] + COMBO_BOX, + [CCode (cname = "DROPDOWNBOX")] + DROPDOWN_BOX, + [CCode (cname = "TEXTBOX")] + TEXT_BOX, // Used also for: TEXTBOXMULTI + [CCode (cname = "VALUEBOX")] + VALUE_BOX, + CONTROL11, + [CCode (cname = "LISTVIEW")] + LIST_VIEW, + [CCode (cname = "COLORPICKER")] + COLOR_PICKER, + [CCode (cname = "SCROLLBAR")] + SCROLL_BAR, + [CCode (cname = "STATUSBAR")] + STATUS_BAR + } // Control + + // RayGui base properties for every control + // NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) + [CCode (cname = "GuiControlProperty", cprefix = "", has_type_id = false)] + public enum ControlProperty { + BORDER_COLOR_NORMAL, // Control border color in STATE_NORMAL + BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL + TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL + BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED + BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED + TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED + BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED + BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED + TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED + BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED + BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED + TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED + BORDER_WIDTH, // Control border size, 0 for no border + TEXT_PADDING, // Control text padding, not considering border + TEXT_ALIGNMENT, // Control text horizontal alignment inside control text bound (after border and padding) + } // ControlProperty + + // RayGui extended properties depend on control + // NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) + //---------------------------------------------------------------------------------- + // DEFAULT extended properties + // NOTE: Those properties are common to all controls or global + // WARNING: Only 8 slots vailable for those properties by default + [CCode (cname = "GuiDefaultProperty", cprefix = "", has_type_id = false)] + public enum DefaultProperty { + TEXT_SIZE, // Text size (glyphs max height) + TEXT_SPACING, // Text spacing between glyphs + LINE_COLOR, // Line control color + BACKGROUND_COLOR, // Background color + TEXT_LINE_SPACING, // Text spacing between lines + TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) + TEXT_WRAP_MODE // Text wrap-mode inside text bounds + } // DefaultProperty + + // Toggle/ToggleGroup + [CCode (cname = "GuiToggleProperty", cprefix = "", has_type_id = false)] + public enum ToggleProperty { + GROUP_PADDING, // ToggleGroup separation between toggles + } // ToggleProperty + + // Slider/SliderBar + [CCode (cname = "GuiSliderProperty", cprefix = "", has_type_id = false)] + public enum SliderProperty { + SLIDER_WIDTH, // Slider size of internal bar + SLIDER_PADDING // Slider/SliderBar internal bar padding + } // SliderProperty + + // ProgressBar + [CCode (cname = "GuiProgressBarProperty", cprefix = "", has_type_id = false)] + public enum ProgressBarProperty { + PROGRESS_PADDING, // ProgressBar internal padding + PROGRESS_SIDE, // ProgressBar increment side: 0-left->right, 1-right-left + } // ProgressBarProperty + + // ScrollBar + [CCode (cname = "GuiScrollBarProperty", cprefix = "", has_type_id = false)] + public enum ScrollBarProperty { + ARROWS_SIZE, // ScrollBar arrows size + ARROWS_VISIBLE, // ScrollBar arrows visible + SCROLL_SLIDER_PADDING, // ScrollBar slider internal padding + SCROLL_SLIDER_SIZE, // ScrollBar slider size + SCROLL_PADDING, // ScrollBar scroll padding from arrows + SCROLL_SPEED, // ScrollBar scrolling speed + } // ScrollBarProperty + + // CheckBox + [CCode (cname = "GuiCheckBoxProperty", cprefix = "", has_type_id = false)] + public enum GuiCheckBoxProperty { + CHECK_PADDING // CheckBox internal check padding + } // GuiCheckBoxProperty + + // ComboBox + [CCode (cname = "GuiComboBoxProperty", has_type_id = false)] + public enum ComboBoxProperty { + COMBO_BUTTON_WIDTH , // ComboBox right button width + COMBO_BUTTON_SPACING // ComboBox button separation + } //ComboBoxProperty + + // DropdownBox + [CCode (cname = "GuiDropdownBoxProperty", cprefix = "", has_type_id = false)] + public enum DropdownBoxProperty { + ARROW_PADDING, // 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) + } // DropdownBoxProperty + + // TextBox/TextBoxMulti/ValueBox/Spinner + [CCode (cname = "GuiTextBoxProperty", cprefix = "", has_type_id = false)] + public enum TextBoxProperty { + TEXT_READONLY, // TextBox in read-only mode: 0-text editable, 1-text no-editable + } // TextBoxProperty + + // ValueBox/Spinner + [CCode (cname = "GuiValueBoxProperty", cprefix = "", has_type_id = false)] + public enum ValueBoxProperty { + SPINNER_BUTTON_WIDTH, // Spinner left/right buttons width + SPINNER_BUTTON_SPACING, // Spinner buttons separation + } // ValueBoxProperty + + // ListView + [CCode (cname = "GuiListViewProperty", cprefix = "", has_type_id = false)] + public enum ListViewProperty { + LIST_ITEMS_HEIGHT, // ListView items height + LIST_ITEMS_SPACING, // ListView items separation + SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) + SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) + LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state + LIST_ITEMS_BORDER_WIDTH // ListView items border width + } // ListViewProperty + + // ColorPicker + [CCode (cname = "GuiControlProperty", cprefix = "", has_type_id = false)] + public enum ColorPickerProperty { + COLOR_SELECTOR_SIZE, + HUEBAR_WIDTH, // ColorPicker right hue bar width + HUEBAR_PADDING, // ColorPicker right hue bar separation from panel + HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height + HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow + } // ColorPickerProperty + + [CCode (cname = "SCROLLBAR_LEFT_SIDE")] + public const int SCROLLBAR_LEFT_SIDE; + + [CCode (cname = "SCROLLBAR_RIGHT_SIDE")] + public const int SCROLLBAR_RIGHT_SIDE; + + // Global gui state control functions + [CCode (cname = "GuiEnable")] + public static void gui_enable (); // Enable gui controls (global state) + + [CCode (cname = "GuiDisable")] + public static void gui_disable (); // Disable gui controls (global state) + + [CCode (cname = "GuiLock")] + public static void gui_lock (); // Lock gui controls (global state) + + [CCode (cname = "GuiUnlock")] + public static void gui_unlock (); // Unlock gui controls (global state) + + [CCode (cname = "GuiIsLocked")] + public static bool gui_is_locked (); // Check if gui is locked (global state) + + [CCode (cname = "GuiSetAlpha")] + public static void gui_set_alpha (float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f + + [CCode (cname = "GuiSetState")] + public static void gui_set_state (State state); // Set gui state (global state) + + [CCode (cname = "GuiGetState")] + public static State gui_get_state (); // Get gui state (global state) + + // Font set/get functions + [CCode (cname = "GuiSetFont")] + public static void gui_set_font (Font font); // Set gui custom font (global state) + + [CCode (cname = "GuiGetFont")] + public static Font gui_get_font (); // Get gui custom font (global state) + + // Style set/get functions + [CCode (cname = "GuiSetStyle")] + public static void gui_set_style (Control control, ControlProperty property, int val); // Set one style property + + [CCode (cname = "GuiGetStyle")] + public static int gui_get_style (Control control, ControlProperty property); // Get one style property + + // Styles loading functions + [CCode (cname = "GuiLoadStyle")] + public static void gui_load_style (string fileName); // Load style file over global style variable (.rgs) + + [CCode (cname = "GuiLoadStyleDefault")] + public static void gui_load_style_default (); // Load style default over global style + + // Tooltips management functions + [CCode (cname = "GuiEnableTooltip")] + public static void gui_enable_tooltip (); // Enable gui tooltips (global state) + + [CCode (cname = "GuiDisableTooltip")] + public static void gui_disable_tooltip (); // Disable gui tooltips (global state) + + [CCode (cname = "GuiSetTooltip")] + public static void gui_set_tooltip (string tooltip); // Set tooltip string + + // Icons functionality + [CCode (cname = "GuiIconText")] + public static unowned string gui_icon_text (IconName icon_id, string text); // Get text with icon id prepended (if supported) + + [CCode (cname = "GuiSetIconScale")] + public static void gui_set_icon_scale (int scale); // Set default icon drawing size + + [CCode (cname = "GuiGetIcons", array_length = false)] + public static unowned uint[] gui_get_icons (); // Get raygui icons data pointer + + [CCode (cname = "GuiLoadIcons", array_length = false)] + public static unowned uint[] gui_load_icons (string file_name, bool load_icons_name); // Load raygui icons file (.rgi) into internal icons data + + [CCode (cname = "GuiDrawIcon")] + public static void gui_draw_icon (IconName icon_id, int pos_x, int pos_y, int pixel_size, Color color); // Draw icon using pixel size at specified position + + // Utility functions + [CCode (cname = "GuiGetTextWidth")] + public static int gui_get_text_width (string text); // Get text width considering gui style and icon size (if required) + + // Controls + //---------------------------------------------------------------------------------------------------------- + // Container/separator controls, useful for controls organization + [CCode (cname = "GuiWindowBox")] + public static int gui_window_box (Rectangle bounds, string title); // Window Box control, shows a window that can be closed + + [CCode (cname = "GuiGroupBox")] + public static int gui_group_box (Rectangle bounds, string text); // Group Box control with text name + + [CCode (cname = "GuiLine")] + public static int gui_line (Rectangle bounds, string text); // Line separator control, could contain text + + [CCode (cname = "GuiPanel")] + public static int gui_panel (Rectangle bounds, string text); // Panel control, useful to group controls + + [CCode (cname = "GuiTabBar")] + public static int gui_tab_bar (Rectangle bounds, string[] text, [CCode (array_length_pos = 1.1)] ref int[] active); // Tab Bar control, returns TAB to be closed or -1 + + [CCode (cname = "GuiScrollPanel")] + public static int gui_scroll_panel (Rectangle bounds, string? text, Rectangle content, ref Vector2 scroll, ref Rectangle view); // Scroll Panel control + + // Basic controls set + [CCode (cname = "GuiLabel")] + public static int gui_label (Rectangle bounds, string text); // Label control + + [CCode (cname = "GuiButton")] + public static int gui_button (Rectangle bounds, string? text); // Button control, returns true when clicked + + [CCode (cname = "GuiLabelButton")] + public static int gui_label_button (Rectangle bounds, string? text); // Label button control, returns true when clicked + + [CCode (cname = "GuiToggle")] + public static int gui_toggle (Rectangle bounds, string? text, ref bool active); // Toggle Button control + + [CCode (cname = "GuiToggleGroup")] + public static int gui_toggle_group (Rectangle bounds, string? text, ref int active); // Toggle Group control + + [CCode (cname = "GuiToggleSlider")] + public static int gui_toggle_slider (Rectangle bounds, string? text, ref int active); // Toggle Slider control + + [CCode (cname = "GuiCheckBox")] + public static int gui_check_box( Rectangle bounds, string? text, ref bool checked); // Check Box control, returns true when active + + [CCode (cname = "GuiComboBox")] + public static int gui_combo_box (Rectangle bounds, string? text, ref int active); // Combo Box control + + [CCode (cname = "GuiDropdownBox")] + public static int gui_dropdown_box(Rectangle bounds, string? text, ref int active, bool edit_mode); // Dropdown Box control + + [CCode (cname = "GuiSpinner")] + public static int gui_spinner (Rectangle bounds, string? text, ref int value, int min_value, int max_value, bool edit_mode); // Spinner control + + [CCode (cname = "GuiValueBox")] + public static int gui_value_box (Rectangle bounds, string? text, ref int value, int min_value, int max_value, bool edit_mode); // Value Box control, updates input text with numbers + + [CCode (cname = "GuiValueBoxFloat")] + public static int gui_value_box_float (Rectangle bounds, string? text, ref string text_value, ref float value, bool edit_mode); // Value box control for float values + + [CCode (cname = "GuiTextBox")] + public static int gui_text_box (Rectangle bounds, string text, int text_size, bool edit_mode); // Text Box control, updates input text + + [CCode (cname = "GuiSlider")] + public static int gui_slider (Rectangle bounds, string? text_left, string? text_right, ref float value, float min_value, float max_value); // Slider control + + [CCode (cname = "GuiSliderBar")] + public static int gui_slider_bar (Rectangle bounds, string? text_left, string? text_right, ref float value, float min_value, float max_value); // Slider Bar control + + [CCode (cname = "GuiProgressBar")] + public static int gui_progress_bar (Rectangle bounds, string? text_left, string? text_right, ref float value, float min_value, float max_value); // Progress Bar control + + [CCode (cname = "GuiStatusBar")] + public static int gui_status_bar (Rectangle bounds, string text); // Status Bar control, shows info text + + [CCode (cname = "GuiDummyRec")] + public static int gui_dummy_rectangle (Rectangle bounds, string? text); // Dummy control for placeholders + + [CCode (cname = "GuiGrid")] + public static int gui_grid (Rectangle bounds, string? text, float spacing, int subdivs, ref Vector2 mouse_cell); // Grid control + + // Advance controls set + [CCode (cname = "GuiListView")] + public static int gui_list_view (Rectangle bounds, string text, ref int scroll_index, ref int active); // List View control + + [CCode (cname = "GuiListViewEx")] + public static int gui_list_view_ext (Rectangle bounds, string[] text, ref int scroll_index, ref int active, ref int focus); // List View with extended parameters + + [CCode (cname = "GuiMessageBox")] + public static int gui_message_box (Rectangle bounds, string title, string message, string buttons); // Message Box control, displays a message + + [CCode (cname = "GuiTextInputBox")] + public static int gui_text_input_box (Rectangle bounds, string? title, string? message, string buttons, string text, int text_max_size, bool? secret_view_active); // Text Input Box control, ask for text, supports secret + + [CCode (cname = "GuiColorPicker")] + public static int gui_color_picker (Rectangle bounds, string? text, ref Color color); // Color Picker control (multiple color controls) + + [CCode (cname = "GuiColorPanel")] + public static int gui_color_panel (Rectangle bounds, string? text, ref Color color); // Color Panel control + + [CCode (cname = "GuiColorBarAlpha")] + public static int gui_color_bar_alpha (Rectangle bounds, string? text, ref float alpha); // Color Bar Alpha control + + [CCode (cname = "GuiColorBarHue")] + public static int gui_color_bar_hue (Rectangle bounds, string? text, ref float val); // Color Bar Hue control + + [CCode (cname = "GuiColorPickerHSV")] + public static int gui_color_picker_hsv (Rectangle bounds, string? text, ref Vector3 color_hsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls) + + [CCode (cname = "GuiColorPanelHSV")] + public static int gui_color_panel_hsv (Rectangle bounds, string text, ref Vector3 color_hsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV() + //---------------------------------------------------------------------------------------------------------- + + //---------------------------------------------------------------------------------- + // Icons enumeration + //---------------------------------------------------------------------------------- + [CCode (cname = "int", cprefix = "ICON_", has_type_id = false)] + public enum IconName { + NONE, + FOLDER_FILE_OPEN, + FILE_SAVE_CLASSIC, + FOLDER_OPEN, + FOLDER_SAVE, + FILE_OPEN, + FILE_SAVE, + FILE_EXPORT, + FILE_ADD, + FILE_DELETE, + FILETYPE_TEXT, + FILETYPE_AUDIO, + FILETYPE_IMAGE, + FILETYPE_PLAY, + FILETYPE_VIDEO, + FILETYPE_INFO, + FILE_COPY, + FILE_CUT, + FILE_PASTE, + CURSOR_HAND, + CURSOR_POINTER, + CURSOR_CLASSIC, + PENCIL, + PENCIL_BIG, + BRUSH_CLASSIC, + BRUSH_PAINTER, + WATER_DROP, + COLOR_PICKER, + RUBBER, + COLOR_BUCKET, + TEXT_T, + TEXT_A, + SCALE, + RESIZE, + FILTER_POINT, + FILTER_BILINEAR, + CROP, + CROP_ALPHA, + SQUARE_TOGGLE, + SYMMETRY, + SYMMETRY_HORIZONTAL, + SYMMETRY_VERTICAL, + LENS, + LENS_BIG, + EYE_ON, + EYE_OFF, + FILTER_TOP, + FILTER, + TARGET_POINT, + TARGET_SMALL, + TARGET_BIG, + TARGET_MOVE, + CURSOR_MOVE, + CURSOR_SCALE, + CURSOR_SCALE_RIGHT, + CURSOR_SCALE_LEFT, + UNDO, + REDO, + REREDO, + MUTATE, + ROTATE, + REPEAT, + SHUFFLE, + EMPTYBOX, + TARGET, + TARGET_SMALL_FILL, + TARGET_BIG_FILL, + TARGET_MOVE_FILL, + CURSOR_MOVE_FILL, + CURSOR_SCALE_FILL, + CURSOR_SCALE_RIGHT_FILL, + CURSOR_SCALE_LEFT_FILL, + UNDO_FILL, + REDO_FILL, + REREDO_FILL, + MUTATE_FILL, + ROTATE_FILL, + REPEAT_FILL, + SHUFFLE_FILL, + EMPTYBOX_SMALL, + BOX, + BOX_TOP, + BOX_TOP_RIGHT, + BOX_RIGHT, + BOX_BOTTOM_RIGHT, + BOX_BOTTOM, + BOX_BOTTOM_LEFT, + BOX_LEFT, + BOX_TOP_LEFT, + BOX_CENTER, + BOX_CIRCLE_MASK, + POT, + ALPHA_MULTIPLY, + ALPHA_CLEAR, + DITHERING, + MIPMAPS, + BOX_GRID, + GRID, + BOX_CORNERS_SMALL, + BOX_CORNERS_BIG, + FOUR_BOXES, + GRID_FILL, + BOX_MULTISIZE, + ZOOM_SMALL, + ZOOM_MEDIUM, + ZOOM_BIG, + ZOOM_ALL, + ZOOM_CENTER, + BOX_DOTS_SMALL, + BOX_DOTS_BIG, + BOX_CONCENTRIC, + BOX_GRID_BIG, + OK_TICK, + CROSS, + ARROW_LEFT, + ARROW_RIGHT, + ARROW_DOWN, + ARROW_UP, + ARROW_LEFT_FILL, + ARROW_RIGHT_FILL, + ARROW_DOWN_FILL, + ARROW_UP_FILL, + AUDIO, + FX, + WAVE, + WAVE_SINUS, + WAVE_SQUARE, + WAVE_TRIANGULAR, + CROSS_SMALL, + PLAYER_PREVIOUS, + PLAYER_PLAY_BACK, + PLAYER_PLAY, + PLAYER_PAUSE, + PLAYER_STOP, + PLAYER_NEXT, + PLAYER_RECORD, + MAGNET, + LOCK_CLOSE, + LOCK_OPEN, + CLOCK, + TOOLS, + GEAR, + GEAR_BIG, + BIN, + HAND_POINTER, + LASER, + COIN, + EXPLOSION, + 1UP, + PLAYER, + PLAYER_JUMP, + KEY, + DEMON, + TEXT_POPUP, + GEAR_EX, + CRACK, + CRACK_POINTS, + STAR, + DOOR, + EXIT, + MODE_2D, + MODE_3D, + CUBE, + CUBE_FACE_TOP, + CUBE_FACE_LEFT, + CUBE_FACE_FRONT, + CUBE_FACE_BOTTOM, + CUBE_FACE_RIGHT, + CUBE_FACE_BACK, + CAMERA, + SPECIAL, + LINK_NET, + LINK_BOXES, + LINK_MULTI, + LINK, + LINK_BROKE, + TEXT_NOTES, + NOTEBOOK, + SUITCASE, + SUITCASE_ZIP, + MAILBOX, + MONITOR, + PRINTER, + PHOTO_CAMERA, + PHOTO_CAMERA_FLASH, + HOUSE, + HEART, + CORNER, + VERTICAL_BARS, + VERTICAL_BARS_FILL, + LIFE_BARS, + INFO, + CROSSLINE, + HELP, + FILETYPE_ALPHA, + FILETYPE_HOME, + LAYERS_VISIBLE, + LAYERS, + WINDOW, + HIDPI, + FILETYPE_BINARY, + HEX, + SHIELD, + FILE_NEW, + FOLDER_ADD, + ALARM, + CPU, + ROM, + STEP_OVER, + STEP_INTO, + STEP_OUT, + RESTART, + BREAKPOINT_ON, + BREAKPOINT_OFF, + BURGER_MENU, + CASE_SENSITIVE, + REG_EXP, + FOLDER, + FILE, + SAND_TIMER, + WARNING, + HELP_BOX, + INFO_BOX, + PRIORITY, + LAYERS_ISO, + LAYERS2, + MLAYERS, + MAPS, + HOT, + LABEL, + NAME_ID, + SLICING, + MANUAL_CONTROL, + COLLISION, + CIRCLE_ADD, + CIRCLE_ADD_FILL, + CIRCLE_WARNING, + CIRCLE_WARNING_FILL, + BOX_MORE, + BOX_MORE_FILL, + BOX_MINUS, + BOX_MINUS_FILL, + UNION, + INTERSECTION, + DIFFERENCE, + SPHERE, + CYLINDER, + CONE, + ELLIPSOID, + CAPSULE, + [CCode (cname = "ICON_250")] + I_250, + [CCode (cname = "ICON_251")] + I_251, + [CCode (cname = "ICON_252")] + I_252, + [CCode (cname = "ICON_253")] + I_253, + [CCode (cname = "ICON_254")] + I_254, + [CCode (cname = "ICON_255")] + I_255 + } // GuiIconName +} diff --git a/vapi/raylib.deps b/vapi/raylib.deps new file mode 100644 index 0000000..ab39dff --- /dev/null +++ b/vapi/raylib.deps @@ -0,0 +1 @@ +raymath diff --git a/vapi/raylib.vapi b/vapi/raylib.vapi index 3e2140c..4521d15 100644 --- a/vapi/raylib.vapi +++ b/vapi/raylib.vapi @@ -1,3 +1,5 @@ +using Raymath; + [CCode (cprefix = "", cheader_filename = "raylib.h")] namespace Raylib { [CCode (cname = "RAYLIB_VERSION_MAJOR")] @@ -12,9 +14,9 @@ namespace Raylib { [CCode (cname = "RAYLIB_VERSION")] public const string VERSION; - //---------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------- // Some basic Defines - //---------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------- [CCode (cname = "PI")] public const float PI; @@ -24,7 +26,9 @@ namespace Raylib { [CCode (cname = "RAD2DEG")] public const float RAD2DEG; + // ---------------------------------------------------------------------------------- // Some Basic Colors + // ---------------------------------------------------------------------------- // NOTE: Custom raylib color palette for amazing visuals on WHITE background [CCode (cname = "LIGHTGRAY")] public const Color LIGHTGRAY; @@ -86,7 +90,6 @@ namespace Raylib { [CCode (cname = "BROWN")] public const Color BROWN; - [CCode (cname = "DARKBROWN")] public const Color DARKBROWN; @@ -105,66 +108,9 @@ namespace Raylib { [CCode (cname = "RAYWHITE")] public const Color RAYWHITE; - //---------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------- // Structures Definition - //---------------------------------------------------------------------------------- - [SimpleType] - [CCode (cname = "Vector2")] - public struct Vector2 { - public float x; - public float y; - } - - [SimpleType] - [CCode (cname = "Vector3")] - public struct Vector3 { - public float x; - public float y; - public float z; - } - - [SimpleType] - [CCode (cname = "Vector4")] - public struct Vector4 { - public float x; - public float y; - public float z; - public float w; - } - - [SimpleType] - [CCode (cname = "Quaternion")] - public struct Quaternion { - public float x; - public float y; - public float z; - public float w; - } - - [SimpleType] - [CCode (cname = "Matrix")] - public struct Matrix { - public float m0; - public float m4; - public float m8; - public float m12; - - public float m1; - public float m5; - public float m9; - public float m13; - - public float m2; - public float m6; - public float m10; - public float m14; - - public float m3; - public float m7; - public float m11; - public float m15; - } - + // ---------------------------------------------------------------------------------- [SimpleType] [CCode (cname = "Color")] public struct Color { @@ -186,715 +132,825 @@ namespace Raylib { [SimpleType] [CCode (cname = "Image")] public struct Image { - void* data; - - int width; - int height; - int mipmaps; - - PixelFormat format; + public void* data; + public int width; + public int height; + public int mipmaps; + public PixelFormat format; } [SimpleType] [CCode (cname = "Texture")] public struct Texture { - public uint id; // OpenGL texture id - public int width; // Texture base width - public int height; // Texture base height - public int mipmaps; // Mipmap levels, 1 by default - - public PixelFormat format; // Data format (PixelFormat type) + public uint id; // OpenGL texture id + public int width; // Texture base width + public int height; // Texture base height + public int mipmaps; // Mipmap levels, 1 by default + public PixelFormat format; // Data format (PixelFormat type) } [SimpleType] [CCode (cname = "Texture2D")] public struct Texture2D { - public uint id; // OpenGL texture id - public int width; // Texture base width - public int height; // Texture base height - public int mipmaps; // Mipmap levels, 1 by default + public uint id; // OpenGL texture id + public int width; // Texture base width + public int height; // Texture base height + public int mipmaps; // Mipmap levels, 1 by default - public PixelFormat format; // Data format (PixelFormat type) + public PixelFormat format; // Data format (PixelFormat type) } [SimpleType] [CCode (cname = "TextureCubemap")] public struct TextureCubemap { - public uint id; // OpenGL texture id - public int width; // Texture base width - public int height; // Texture base height - public int mipmaps; // Mipmap levels, 1 by default + public uint id; // OpenGL texture id + public int width; // Texture base width + public int height; // Texture base height + public int mipmaps; // Mipmap levels, 1 by default - public PixelFormat format; // Data format (PixelFormat type) + public PixelFormat format; // Data format (PixelFormat type) } [SimpleType] [CCode (cname = "RenderTexture")] public struct RenderTexture { - public uint id; // OpenGL framebuffer object id + public uint id; // OpenGL framebuffer object id - public unowned Texture2D texture; // Color buffer attachment texture - public unowned Texture2D depth; // Depth buffer attachment texture + public unowned Texture2D texture; // Color buffer attachment texture + public unowned Texture2D depth; // Depth buffer attachment texture } [SimpleType] [CCode (cname = "RenderTexture2D")] public struct RenderTexture2D : RenderTexture { - public uint id; // OpenGL framebuffer object id - - public unowned Texture2D texture; // Color buffer attachment texture - public unowned Texture2D depth; // Depth buffer attachment texture + public uint id; // OpenGL framebuffer object id + public unowned Texture2D texture; // Color buffer attachment texture + public unowned Texture2D depth; // Depth buffer attachment texture } [SimpleType] [CCode (cname = "NPatchInfo")] public struct NPatchInfo { - public unowned Rectangle source; // Texture source rectangle - - public int left; // Left border offset - public int top; // Top border offset - public int right; // Right border offset - public int bottom; // Bottom border offset - public int layout; // Layout of the n-patch: 3x3, 1x3 or 3x1 + public unowned Rectangle source; // Texture source rectangle + public int left; // Left border offset + public int top; // Top border offset + public int right; // Right border offset + public int bottom; // Bottom border offset + public int layout; // Layout of the n-patch: 3x3, 1x3 or 3x1 } [SimpleType] [CCode (cname = "GlyphInfo")] public struct GlyphInfo { - public int value; // Character value (Unicode) - public int offsetX; // Character offset X when drawing // vala-lint=naming-convention - public int offsetY; // Character offset Y when drawing // vala-lint=naming-convention - public int advanceX; // Character advance position X // vala-lint=naming-convention - - public unowned Image image; // Character image data + public int value; // Character value (Unicode) + [CCode (cname = "offsetX")] + public int offset_x; // Character offset X when drawing + [CCode (cname = "offsetY")] + public int offset_y; // Character offset Y when drawing + [CCode (cname = "advanceX")] + public int advance_x; // Character advance position X + public unowned Image image; // Character image data } [SimpleType] [CCode (cname = "Font")] public struct Font { - public int baseSize; // Base size (default chars height) // vala-lint=naming-convention - public int glyphCount; // Number of glyph characters // vala-lint=naming-convention - public int glyphPadding; // Padding around the glyph characters // vala-lint=naming-convention - - public unowned Texture2D texture; // Texture atlas containing the glyphs - public unowned Rectangle[] recs; // Rectangles in texture for the glyphs - public unowned GlyphInfo[] glyphs; // Glyphs info data + [CCode (cname = "baseSize")] + public int base_size; // Base size (default chars height) + [CCode (cname = "glyphCount")] + public int glyph_count; // Number of glyph characters + [CCode (cname = "glyphPadding")] + public int glyph_padding; // Padding around the glyph characters + public unowned Texture2D texture; // Texture atlas containing the glyphs + public unowned Rectangle[] recs; // Rectangles in texture for the glyphs + public unowned GlyphInfo[] glyphs; // Glyphs info data } [SimpleType] [CCode (cname = "Camera3D")] public struct Camera3D { - public unowned Vector3 position; // Camera position - public unowned Vector3 target; // Camera target it looks-at - public unowned Vector3 up; // Camera up vector (rotation over its axis) + public unowned Vector3 position; // Camera position + public unowned Vector3 target; // Camera target it looks-at + public unowned Vector3 up; // Camera up vector (rotation over its axis) - public float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic - public int projection; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + public float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic + public int projection; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC } [SimpleType] [CCode (cname = "Camera")] public struct Camera : Camera3D { - public unowned Vector3 position; // Camera position - public unowned Vector3 target; // Camera target it looks-at - public unowned Vector3 up; // Camera up vector (rotation over its axis) + public unowned Vector3 position; // Camera position + public unowned Vector3 target; // Camera target it looks-at + public unowned Vector3 up; // Camera up vector (rotation over its axis) - public float fovy; // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane width in orthographic - public int projection; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + public float fovy; // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane width in orthographic + public int projection; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC } [SimpleType] [CCode (cname = "Camera2D")] public struct Camera2D { - public unowned Vector2 offset; // Camera offset (displacement from target) - public unowned Vector2 target; // Camera target (rotation and zoom origin) + public unowned Vector2 offset; // Camera offset (displacement from target) + public unowned Vector2 target; // Camera target (rotation and zoom origin) - public float rotation; // Camera rotation in degrees - public float zoom; // Camera zoom (scaling), should be 1.0f by default + public float rotation; // Camera rotation in degrees + public float zoom; // Camera zoom (scaling), should be 1.0f by default } [SimpleType] [CCode (cname = "Mesh")] public struct Mesh { - public int vertexCount; // Number of vertices stored in arrays // vala-lint=naming-convention - public int triangleCount; // Number of triangles stored (indexed or not) // vala-lint=naming-convention + [CCode (cname = "vertexCount")] + public int vertex_count; // Number of vertices stored in arrays + [CCode (cname = "triangleCount")] + public int triangle_count; // Number of triangles stored (indexed or not) // Vertex attributes data - public unowned float[] vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) - public unowned float[] texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) - public unowned float[] texcoords2; // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5) - public unowned float[] normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) - public unowned float[] tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) - public unowned uchar[] colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) - public unowned ushort[] indices; // Vertex indices (in case vertex data comes indexed) - - // Animation vertex data - public unowned float[] animVertices; // Animated vertex positions (after bones transformations) // vala-lint=naming-convention - public unowned float[] animNormals; // Animated normals (after bones transformations) // vala-lint=naming-convention - public unowned uchar[] boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) // vala-lint=naming-convention - public unowned float[] boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) // vala-lint=naming-convention + [CCode (array_length = false)] + public unowned float[] vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) + [CCode (array_length = false)] + public unowned float[] texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + [CCode (array_length = false)] + public unowned float[] texcoords2; // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5) + [CCode (array_length = false)] + public unowned float[] normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) + [CCode (array_length = false)] + public unowned float[] tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) + [CCode (array_length = false)] + public unowned uchar[] colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) + [CCode (array_length = false)] + public unowned ushort[] indices; // Vertex indices (in case vertex data comes indexed) + + // Skin data for animation + [CCode (cname = "boneCount")] + public unowned int bone_count; // Number of bones + [CCode (cname = "boneIndices", array_length = false)] + public unowned uchar[] bone_indices; // Vertex bone indices, up to 4 bones influence by vertex (skinning) (shader-location = 6) + [CCode (cname = "boneWeights", array_length = false)] + public unowned float[] bone_weights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7) + + // Runtime animation vertex data (CPU skinning) + // NOTE: In case of GPU skinning, not used, pointers are NULL + [CCode (cname = "animVertices", array_length = false)] + public unowned float[] anim_vertices; // Animated vertex positions (after bones transformations) + [CCode (cname = "animNormals", array_length = false)] + public unowned float[] anim_normals; // Animated normals (after bones transformations) // OpenGL identifiers - public uint vaoId; // OpenGL Vertex Array Object id // vala-lint=naming-convention - public unowned uint[] vboId; // OpenGL Vertex Buffer Objects id (default vertex data) // vala-lint=naming-convention + [CCode (cname = "vaoId")] + public uint vao_id; // OpenGL Vertex Array Object id + [CCode (cname = "vboId", array_length = false)] + public unowned uint[] vbo_id; // OpenGL Vertex Buffer Objects id (default vertex data) } [SimpleType] [CCode (cname = "Shader")] public struct Shader { - public uint id; // Shader program id - public unowned int[] locs; // Shader locations array (RL_MAX_SHADER_LOCATIONS) + public uint id; // Shader program id + [CCode (array_length = false)] + public unowned int[] locs; // Shader locations array (RL_MAX_SHADER_LOCATIONS) } [SimpleType] [CCode (cname = "MaterialMap")] public struct MaterialMap { - unowned Texture2D texture; // Material map texture - Color color; // Material map color - - float value; // Material map value + public unowned Texture2D texture; // Material map texture + public Color color; // Material map color + public float value; // Material map value } [SimpleType] [CCode (cname = "Material")] public struct Material { - unowned Shader shader; // Material shader - unowned MaterialMap[] maps; // Material maps array (MAX_MATERIAL_MAPS) - float @params[4]; // Material generic parameters (if required) + public unowned Shader shader; // Material shader + [CCode (array_length = false)] + public unowned MaterialMap[] maps; // Material maps array (MAX_MATERIAL_MAPS) + [CCode (cname = "params")] + public float parameters[4]; // Material generic parameters (if required) } [SimpleType] [CCode (cname = "Transform")] public struct Transform { - public Vector3 translation; // Translation - public Quaternion rotation; // Rotation - public Vector3 scale; // Scale + public Vector3 translation; // Translation + public Quaternion rotation; // Rotation + public Vector3 scale; // Scale } [SimpleType] [CCode (cname = "BoneInfo")] public struct BoneInfo { - public unowned string name; // Bone name - public int parent; // Bone parent + public unowned string name; // Bone name + public int parent; // Bone parent + } + + [SimpleType] + [CCode (cname = "ModelSkeleton")] + public struct ModelSkeleton { + [CCode (cname = "boneCount")] + public int bone_count; // Number of bones + [CCode (array_length = false)] + public unowned BoneInfo[] bones; // Bones information (skeleton) + [CCode (cname = "bindPose", array_length = false)] + public unowned Transform[] bind_pose; // Bones base transformation (Transform[]) } [SimpleType] [CCode (cname = "Model")] public struct Model { - public Matrix transform; // Local transform matrix + public Matrix transform; // Local transform matrix - public int meshCount; // Number of meshes // vala-lint=naming-convention - public int materialCount; // Number of materials // vala-lint=naming-convention - public unowned Mesh[] meshes; // Meshes array - public unowned Material[] materials; // Materials array - public unowned int[] meshMaterial; // Mesh material number // vala-lint=naming-convention + [CCode (array_length_cname = "meshCount", array_length_type = "int")] + public unowned Mesh[] meshes; // Meshes array + [CCode (array_length_cname = "materialCount", array_length_type = "int")] + public unowned Material[] materials; // Materials array + [CCode (cname = "meshMaterial", array_length = false)] + public unowned int[] mesh_material; // Mesh material number // Animation data - public int boneCount; // Number of bones // vala-lint=naming-convention - public unowned BoneInfo[] bones; // Bones information (skeleton) - public unowned Transform[] bindPose; // Bones base transformation (pose) // vala-lint=naming-convention + public unowned ModelSkeleton skeleton; // Skeleton for animation + + // Runtime animation data (CPU/GPU skinning) + [CCode (cname = "currentPose", array_length = false)] + public unowned Transform[] current_pose; // Current animation pose (Transform[]) + [CCode (cname = "boneMatrices", array_length = false)] + public unowned Matrix[] bone_matrices; // Bones animated transformation matrices } [SimpleType] [CCode (cname = "ModelAnimation")] public struct ModelAnimation { - public int boneCount; // Number of bones // vala-lint=naming-convention - public int frameCount; // Number of animation frames // vala-lint=naming-convention - public unowned BoneInfo[] bones; // Bones information (skeleton) - public unowned Transform[,] framePoses; // Poses array by frame // vala-lint=naming-convention - public char name[32]; // Animation name + public unowned string name; // Animation name + + [CCode (cname = "boneCount")] + public int bone_count; // Number of bones (per pose) + [CCode (cname = "keyframeCount")] + public int keyframe_count; // Number of animation key frames + [CCode (cname = "keyframePoses", array_length = false)] + public unowned Transform[,] keyframe_poses; // Animation sequence keyframe poses [keyframe][pose] } [SimpleType] [CCode (cname = "Ray")] public struct Ray { - public Vector3 position; // Ray position (origin) - public Vector3 direction; // Ray direction + public Vector3 position; // Ray position (origin) + public Vector3 direction; // Ray direction } [SimpleType] [CCode (cname = "RayCollision")] public struct RayCollision { - public bool hit; // Did the ray hit something? - public float distance; // Distance to nearest hit - public Vector3 point; // Point of nearest hit - public Vector3 normal; // Surface normal of hit + public bool hit; // Did the ray hit something? + public float distance; // Distance to nearest hit + public Vector3 point; // Point of nearest hit + public Vector3 normal; // Surface normal of hit } [SimpleType] [CCode (cname = "BoundingBox")] public struct BoundingBox { - public Vector3 min; // Minimum vertex box-corner - public Vector3 max; // Maximum vertex box-corner + public Vector3 min; // Minimum vertex box-corner + public Vector3 max; // Maximum vertex box-corner } [SimpleType] [CCode (cname = "Wave")] public struct Wave { - public uint frameCount; // Total number of frames (considering channels) // vala-lint=naming-convention - public uint sampleRate; // Frequency (samples per second) // vala-lint=naming-convention - public uint sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) // vala-lint=naming-convention - public uint channels; // Number of channels (1-mono, 2-stereo, ...) - public void *data; // Buffer data pointer + [CCode (cname = "frameCount")] + public uint frame_count; // Total number of frames (considering channels) + [CCode (cname = "sampleRate")] + public uint sample_rate; // Frequency (samples per second) + [CCode (cname = "sampleSize")] + public uint sample_size; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + public uint channels; // Number of channels (1-mono, 2-stereo, ...) + public void* data; // Buffer data pointer } [SimpleType] [CCode (cname = "rAudioBuffer")] - public struct AudioBuffer { } + public struct AudioBuffer {} [SimpleType] [CCode (cname = "rAudioProcessor")] - public struct AudioProcessor { } + public struct AudioProcessor {} [SimpleType] [CCode (cname = "AudioStream")] public struct AudioStream { - public AudioBuffer buffer; // Pointer to internal data used by the audio system - public AudioProcessor processor; // Pointer to internal data processor, useful for audio effects - - public uint sampleRate; // Frequency (samples per second) // vala-lint=naming-convention - public uint sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) // vala-lint=naming-convention - public uint channels; // Number of channels (1-mono, 2-stereo, ...) + public AudioBuffer buffer; // Pointer to internal data used by the audio system + public AudioProcessor processor; // Pointer to internal data processor, useful for audio effects + + [CCode (cname = "sampleRate")] + public uint sample_rate; // Frequency (samples per second) + [CCode (cname = "sampleSize")] + public uint sample_size; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + public uint channels; // Number of channels (1-mono, 2-stereo, ...) } [SimpleType] [CCode (cname = "Sound")] public struct Sound { - public AudioStream stream; // Audio stream - public uint frameCount; // Total number of frames (considering channels) // vala-lint=naming-convention + public AudioStream stream; // Audio stream + [CCode (cname = "frameCount")] + public uint frame_count; // Total number of frames (considering channels) } [SimpleType] [CCode (cname = "Music")] public struct Music { - public AudioStream stream; // Audio stream - public uint frameCount; // Total number of frames (considering channels) // vala-lint=naming-convention - public bool looping; // Music looping enable - - public int ctxType; // Type of music context (audio filetype) // vala-lint=naming-convention - public void* ctxData; // Audio context data, depends on type // vala-lint=naming-convention + public AudioStream stream; // Audio stream + [CCode (cname = "frameCount")] + public uint frame_count; // Total number of frames (considering channels) + public bool looping; // Music looping enable + + [CCode (cname = "ctxType")] + public int ctx_type; // Type of music context (audio filetype) + [CCode (cname = "ctxData")] + public void* ctx_data; // Audio context data, depends on type } [SimpleType] [CCode (cname = "VrDeviceInfo")] public struct VrDeviceInfo { - public int hResolution; // Horizontal resolution in pixels // vala-lint=naming-convention - public int vResolution; // Vertical resolution in pixels // vala-lint=naming-convention - public float hScreenSize; // Horizontal size in meters // vala-lint=naming-convention - public float vScreenSize; // Vertical size in meters // vala-lint=naming-convention - public float vScreenCenter; // Screen center in meters // vala-lint=naming-convention - public float eyeToScreenDistance; // Distance between eye and display in meters // vala-lint=naming-convention - public float lensSeparationDistance; // Lens separation distance in meters // vala-lint=naming-convention - public float interpupillaryDistance; // IPD (distance between pupils) in meters // vala-lint=naming-convention - public float lensDistortionValues[4]; // Lens distortion constant parameters // vala-lint=naming-convention - public float chromaAbCorrection[4]; // Chromatic aberration correction parameters // vala-lint=naming-convention + [CCode (cname = "hResolution")] + public int h_resolution; // Horizontal resolution in pixels + [CCode (cname = "vResolution")] + public int v_resolution; // Vertical resolution in pixels + [CCode (cname = "hScreenSize")] + public float h_screen_size; // Horizontal size in meters + [CCode (cname = "vScreenSize")] + public float v_screen_size; // Vertical size in meters + [CCode (cname = "eyeToScreenDistance")] + public float eye_to_screen_distance; // Distance between eye and display in meters + [CCode (cname = "lensSeparationDistance")] + public float lens_separation_distance; // Lens separation distance in meters + [CCode (cname = "interpupillaryDistance")] + public float interpupillary_distance; // IPD (distance between pupils) in meters + [CCode (cname = "lensDistortionValues")] + public float lens_distortion_values[4]; // Lens distortion constant parameters + [CCode (cname = "chromaAbCorrection")] + public float chroma_aberration_correction[4]; // Chromatic aberration correction parameters } [SimpleType] [CCode (cname = "VrStereoConfig")] public struct VrStereoConfig { - public Matrix projection[2]; // VR projection matrices (per eye) - public Matrix viewOffset[2]; // VR view offset matrices (per eye) // vala-lint=naming-convention - public float leftLensCenter[2]; // VR left lens center // vala-lint=naming-convention - public float rightLensCenter[2]; // VR right lens center // vala-lint=naming-convention - public float leftScreenCenter[2]; // VR left screen center // vala-lint=naming-convention - public float rightScreenCenter[2]; // VR right screen center // vala-lint=naming-convention - public float scale[2]; // VR distortion scale - public float scaleIn[2]; // VR distortion scale in // vala-lint=naming-convention + public Matrix projection[2]; // VR projection matrices (per eye) + [CCode (cname = "viewOffset")] + public Matrix view_offset[2]; // VR view offset matrices (per eye) + [CCode (cname = "leftLensCenter")] + public float left_lens_center[2]; // VR left lens center + [CCode (cname = "rightLensCenter")] + public float right_lens_center[2]; // VR right lens center + [CCode (cname = "leftScreenCenter")] + public float left_screen_center[2]; // VR left screen center + [CCode (cname = "rightScreenCenter")] + public float right_screen_center[2]; // VR right screen center + public float scale[2]; // VR distortion scale + [CCode (cname = "scaleIn")] + public float scale_in[2]; // VR distortion scale in } [SimpleType] [CCode (cname = "FilePathList")] public struct FilePathList { - public uint capacity; // Filepaths max entries - public uint count; // Filepaths entries count - public unowned string[] paths; // Filepaths entries + [CCode (array_length_cname = "count", array_length_type = "uint")] + public unowned string[] paths; // Filepaths entries } [SimpleType] [CCode (cname = "AutomationEvent")] public struct AutomationEvent { - public uint frame; // Event frame - public uint type; // Event type (AutomationEventType) - public int @params[4]; // Event parameters (if required) + public uint frame; // Event frame + public uint type; // Event type (AutomationEventType) + [CCode (cname = "params")] + public int parameters[4]; // Event parameters (if required) } [SimpleType] [CCode (cname = "AutomationEventList")] public struct AutomationEventList { - public uint capacity; // Events max entries (MAX_AUTOMATION_EVENTS) - public uint count; // Events entries count - public unowned AutomationEvent[] events; // Events entries + public uint capacity; // Events max entries (MAX_AUTOMATION_EVENTS) + [CCode (array_length_cname = "count", array_length_type = "int")] + public unowned AutomationEvent[] events; // Events entries } [Flags] [CCode (cname = "ConfigFlags", cprefix = "FLAG_", has_type_id = false)] public enum ConfigFlags { - VSYNC_HINT, // Set to try enabling V-Sync on GPU - FULLSCREEN_MODE, // Set to run program in fullscreen - WINDOW_RESIZABLE, // Set to allow resizable window - WINDOW_UNDECORATED, // Set to disable window decoration (frame and buttons) - WINDOW_HIDDEN, // Set to hide window - WINDOW_MINIMIZED, // Set to minimize window (iconify) - WINDOW_MAXIMIZED, // Set to maximize window (expanded to monitor) - WINDOW_UNFOCUSED, // Set to window non focused - WINDOW_TOPMOST, // Set to window always on top - WINDOW_ALWAYS_RUN, // Set to allow windows running while minimized - WINDOW_TRANSPARENT, // Set to allow transparent framebuffer - WINDOW_HIGHDPI, // Set to support HighDPI - WINDOW_MOUSE_PASSTHROUGH, // Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED - BORDERLESS_WINDOWED_MODE, // Set to run program in borderless windowed mode - MSAA_4X_HINT, // Set to try enabling MSAA 4X - INTERLACED_HINT // Set to try enabling interlaced video format (for V3D) + VSYNC_HINT, // Set to try enabling V-Sync on GPU + FULLSCREEN_MODE, // Set to run program in fullscreen + WINDOW_RESIZABLE, // Set to allow resizable window + WINDOW_UNDECORATED, // Set to disable window decoration (frame and buttons) + WINDOW_HIDDEN, // Set to hide window + WINDOW_MINIMIZED, // Set to minimize window (iconify) + WINDOW_MAXIMIZED, // Set to maximize window (expanded to monitor) + WINDOW_UNFOCUSED, // Set to window non focused + WINDOW_TOPMOST, // Set to window always on top + WINDOW_ALWAYS_RUN, // Set to allow windows running while minimized + WINDOW_TRANSPARENT, // Set to allow transparent framebuffer + WINDOW_HIGHDPI, // Set to support HighDPI + WINDOW_MOUSE_PASSTHROUGH, // Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED + BORDERLESS_WINDOWED_MODE, // Set to run program in borderless windowed mode + MSAA_4X_HINT, // Set to try enabling MSAA 4X + INTERLACED_HINT // Set to try enabling interlaced video format (for V3D) } [CCode (cname = "TraceLogLevel", cprefix = "LOG_", has_type_id = false)] public enum TraceLogLevel { - ALL, // Display all logs - TRACE, // Trace logging, intended for internal use only - DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds - INFO, // Info logging, used for program execution info - WARNING, // Warning logging, used on recoverable failures - ERROR, // Error logging, used on unrecoverable failures - FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) - NONE // Disable logging + ALL, // Display all logs + TRACE, // Trace logging, intended for internal use only + DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds + INFO, // Info logging, used for program execution info + WARNING, // Warning logging, used on recoverable failures + ERROR, // Error logging, used on unrecoverable failures + FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) + NONE // Disable logging } [CCode (cname = "KeyboardKey", cprefix = "KEY_", has_type_id = false)] public enum KeyboardKey { - NULL, // Key: NULL, used for no key pressed + NULL, // Key: NULL, used for no key pressed // Alphanumeric keys - APOSTROPHE, // Key: ' - COMMA, // Key: , - MINUS, // Key: - - PERIOD, // Key: . - SLASH, // Key: / - ZERO, // Key: 0 - ONE, // Key: 1 - TWO, // Key: 2 - THREE, // Key: 3 - FOUR, // Key: 4 - FIVE, // Key: 5 - SIX, // Key: 6 - SEVEN, // Key: 7 - EIGHT, // Key: 8 - NINE, // Key: 9 - SEMICOLON, // Key: ; - EQUAL, // Key: = - A, // Key: A | a - B, // Key: B | b - C, // Key: C | c - D, // Key: D | d - E, // Key: E | e - F, // Key: F | f - G, // Key: G | g - H, // Key: H | h - I, // Key: I | i - J, // Key: J | j - K, // Key: K | k - L, // Key: L | l - M, // Key: M | m - N, // Key: N | n - O, // Key: O | o - P, // Key: P | p - Q, // Key: Q | q - R, // Key: R | r - S, // Key: S | s - T, // Key: T | t - U, // Key: U | u - V, // Key: V | v - W, // Key: W | w - X, // Key: X | x - Y, // Key: Y | y - Z, // Key: Z | z - LEFT_BRACKET, // Key: [ - BACKSLASH, // Key: '\' - RIGHT_BRACKET, // Key: ] - GRAVE, // Key: ` + APOSTROPHE, // Key: ' + COMMA, // Key: , + MINUS, // Key: - + PERIOD, // Key: . + SLASH, // Key: / + ZERO, // Key: 0 + ONE, // Key: 1 + TWO, // Key: 2 + THREE, // Key: 3 + FOUR, // Key: 4 + FIVE, // Key: 5 + SIX, // Key: 6 + SEVEN, // Key: 7 + EIGHT, // Key: 8 + NINE, // Key: 9 + SEMICOLON, // Key: ; + EQUAL, // Key: = + A, // Key: A | a + B, // Key: B | b + C, // Key: C | c + D, // Key: D | d + E, // Key: E | e + F, // Key: F | f + G, // Key: G | g + H, // Key: H | h + I, // Key: I | i + J, // Key: J | j + K, // Key: K | k + L, // Key: L | l + M, // Key: M | m + N, // Key: N | n + O, // Key: O | o + P, // Key: P | p + Q, // Key: Q | q + R, // Key: R | r + S, // Key: S | s + T, // Key: T | t + U, // Key: U | u + V, // Key: V | v + W, // Key: W | w + X, // Key: X | x + Y, // Key: Y | y + Z, // Key: Z | z + LEFT_BRACKET, // Key: [ + BACKSLASH, // Key: '\' + RIGHT_BRACKET, // Key: ] + GRAVE, // Key: ` // Function keys - SPACE, // Key: Space - ESCAPE, // Key: Esc - ENTER, // Key: Enter - TAB, // Key: Tab - BACKSPACE, // Key: Backspace - INSERT, // Key: Ins - DELETE, // Key: Del - RIGHT, // Key: Cursor right - LEFT, // Key: Cursor left - DOWN, // Key: Cursor down - UP, // Key: Cursor up - PAGE_UP, // Key: Page up - PAGE_DOWN, // Key: Page down - HOME, // Key: Home - END, // Key: End - CAPS_LOCK, // Key: Caps lock - SCROLL_LOCK, // Key: Scroll down - NUM_LOCK, // Key: Num lock - PRINT_SCREEN, // Key: Print screen - PAUSE, // Key: Pause - F1, // Key: F1 - F2, // Key: F2 - F3, // Key: F3 - F4, // Key: F4 - F5, // Key: F5 - F6, // Key: F6 - F7, // Key: F7 - F8, // Key: F8 - F9, // Key: F9 - F10, // Key: F10 - F11, // Key: F11 - F12, // Key: F12 - LEFT_SHIFT, // Key: Shift left - LEFT_CONTROL, // Key: Control left - LEFT_ALT, // Key: Alt left - LEFT_SUPER, // Key: Super left - RIGHT_SHIFT, // Key: Shift right - RIGHT_CONTROL, // Key: Control right - RIGHT_ALT, // Key: Alt right - RIGHT_SUPER, // Key: Super right - KB_MENU, // Key: KB menu + SPACE, // Key: Space + ESCAPE, // Key: Esc + ENTER, // Key: Enter + TAB, // Key: Tab + BACKSPACE, // Key: Backspace + INSERT, // Key: Ins + DELETE, // Key: Del + RIGHT, // Key: Cursor right + LEFT, // Key: Cursor left + DOWN, // Key: Cursor down + UP, // Key: Cursor up + PAGE_UP, // Key: Page up + PAGE_DOWN, // Key: Page down + HOME, // Key: Home + END, // Key: End + CAPS_LOCK, // Key: Caps lock + SCROLL_LOCK, // Key: Scroll down + NUM_LOCK, // Key: Num lock + PRINT_SCREEN, // Key: Print screen + PAUSE, // Key: Pause + F1, // Key: F1 + F2, // Key: F2 + F3, // Key: F3 + F4, // Key: F4 + F5, // Key: F5 + F6, // Key: F6 + F7, // Key: F7 + F8, // Key: F8 + F9, // Key: F9 + F10, // Key: F10 + F11, // Key: F11 + F12, // Key: F12 + LEFT_SHIFT, // Key: Shift left + LEFT_CONTROL, // Key: Control left + LEFT_ALT, // Key: Alt left + LEFT_SUPER, // Key: Super left + RIGHT_SHIFT, // Key: Shift right + RIGHT_CONTROL, // Key: Control right + RIGHT_ALT, // Key: Alt right + RIGHT_SUPER, // Key: Super right + KB_MENU, // Key: KB menu // Keypad keys - KP_0, // Key: Keypad 0 - KP_1, // Key: Keypad 1 - KP_2, // Key: Keypad 2 - KP_3, // Key: Keypad 3 - KP_4, // Key: Keypad 4 - KP_5, // Key: Keypad 5 - KP_6, // Key: Keypad 6 - KP_7, // Key: Keypad 7 - KP_8, // Key: Keypad 8 - KP_9, // Key: Keypad 9 - KP_DECIMAL, // Key: Keypad . - KP_DIVIDE, // Key: Keypad / - KP_MULTIPLY, // Key: Keypad * - KP_SUBTRACT, // Key: Keypad - - KP_ADD, // Key: Keypad + - KP_ENTER, // Key: Keypad Enter - KP_EQUAL, // Key: Keypad = + KP_0, // Key: Keypad 0 + KP_1, // Key: Keypad 1 + KP_2, // Key: Keypad 2 + KP_3, // Key: Keypad 3 + KP_4, // Key: Keypad 4 + KP_5, // Key: Keypad 5 + KP_6, // Key: Keypad 6 + KP_7, // Key: Keypad 7 + KP_8, // Key: Keypad 8 + KP_9, // Key: Keypad 9 + KP_DECIMAL, // Key: Keypad . + KP_DIVIDE, // Key: Keypad / + KP_MULTIPLY, // Key: Keypad * + KP_SUBTRACT, // Key: Keypad - + KP_ADD, // Key: Keypad + + KP_ENTER, // Key: Keypad Enter + KP_EQUAL, // Key: Keypad = // Android key buttons - BACK, // Key: Android back button - MENU, // Key: Android menu button - VOLUME_UP, // Key: Android volume up button - VOLUME_DOWN // Key: Android volume down button + BACK, // Key: Android back button + MENU, // Key: Android menu button + VOLUME_UP, // Key: Android volume up button + VOLUME_DOWN // Key: Android volume down button } [CCode (cname = "MouseButton", cprefix = "MOUSE_BUTTON_", has_type_id = false)] public enum MouseButton { - LEFT, // Mouse button left - RIGHT, // Mouse button right - MIDDLE, // Mouse button middle (pressed wheel) - SIDE, // Mouse button side (advanced mouse device) - EXTRA, // Mouse button extra (advanced mouse device) - FORWARD, // Mouse button fordward (advanced mouse device) - BACK, // Mouse button back (advanced mouse device) + LEFT, // Mouse button left + RIGHT, // Mouse button right + MIDDLE, // Mouse button middle (pressed wheel) + SIDE, // Mouse button side (advanced mouse device) + EXTRA, // Mouse button extra (advanced mouse device) + FORWARD, // Mouse button fordward (advanced mouse device) + BACK, // Mouse button back (advanced mouse device) } [CCode (cname = "MouseCursor", cprefix = "MOUSE_CURSOR_", has_type_id = false)] public enum MouseCursor { - DEFAULT, // Default pointer shape - ARROW, // Arrow shape - IBEAM, // Text writing cursor shape - CROSSHAIR, // Cross shape - POINTING_HAND, // Pointing hand cursor - RESIZE_EW, // Horizontal resize/move arrow shape - RESIZE_NS, // Vertical resize/move arrow shape - RESIZE_NWSE, // Top-left to bottom-right diagonal resize/move arrow shape - RESIZE_NESW, // The top-right to bottom-left diagonal resize/move arrow shape - RESIZE_ALL, // The omni-directional resize/move cursor shape - NOT_ALLOWED // The operation-not-allowed shape + DEFAULT, // Default pointer shape + ARROW, // Arrow shape + IBEAM, // Text writing cursor shape + CROSSHAIR, // Cross shape + POINTING_HAND, // Pointing hand cursor + RESIZE_EW, // Horizontal resize/move arrow shape + RESIZE_NS, // Vertical resize/move arrow shape + RESIZE_NWSE, // Top-left to bottom-right diagonal resize/move arrow shape + RESIZE_NESW, // The top-right to bottom-left diagonal resize/move arrow shape + RESIZE_ALL, // The omni-directional resize/move cursor shape + NOT_ALLOWED // The operation-not-allowed shape } [CCode (cname = "GamepadButton", cprefix = "GAMEPAD_BUTTON_", has_type_id = false)] public enum GamepadButton { - UNKNOWN, // Unknown button, just for error checking - LEFT_FACE_UP, // Gamepad left DPAD up button - LEFT_FACE_RIGHT, // Gamepad left DPAD right button - LEFT_FACE_DOWN, // Gamepad left DPAD down button - LEFT_FACE_LEFT, // Gamepad left DPAD left button - RIGHT_FACE_UP, // Gamepad right button up (i.e. PS3: Triangle, Xbox: Y) - RIGHT_FACE_RIGHT, // Gamepad right button right (i.e. PS3: Square, Xbox: X) - RIGHT_FACE_DOWN, // Gamepad right button down (i.e. PS3: Cross, Xbox: A) - RIGHT_FACE_LEFT, // Gamepad right button left (i.e. PS3: Circle, Xbox: B) - LEFT_TRIGGER_1, // Gamepad top/back trigger left (first), it could be a trailing button - LEFT_TRIGGER_2, // Gamepad top/back trigger left (second), it could be a trailing button - RIGHT_TRIGGER_1, // Gamepad top/back trigger right (one), it could be a trailing button - RIGHT_TRIGGER_2, // Gamepad top/back trigger right (second), it could be a trailing button - MIDDLE_LEFT, // Gamepad center buttons, left one (i.e. PS3: Select) - MIDDLE, // Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX) - MIDDLE_RIGHT, // Gamepad center buttons, right one (i.e. PS3: Start) - LEFT_THUMB, // Gamepad joystick pressed button left - RIGHT_THUMB // Gamepad joystick pressed button right + UNKNOWN, // Unknown button, just for error checking + LEFT_FACE_UP, // Gamepad left DPAD up button + LEFT_FACE_RIGHT, // Gamepad left DPAD right button + LEFT_FACE_DOWN, // Gamepad left DPAD down button + LEFT_FACE_LEFT, // Gamepad left DPAD left button + RIGHT_FACE_UP, // Gamepad right button up (i.e. PS3: Triangle, Xbox: Y) + RIGHT_FACE_RIGHT, // Gamepad right button right (i.e. PS3: Square, Xbox: X) + RIGHT_FACE_DOWN, // Gamepad right button down (i.e. PS3: Cross, Xbox: A) + RIGHT_FACE_LEFT, // Gamepad right button left (i.e. PS3: Circle, Xbox: B) + LEFT_TRIGGER_1, // Gamepad top/back trigger left (first), it could be a trailing button + LEFT_TRIGGER_2, // Gamepad top/back trigger left (second), it could be a trailing button + RIGHT_TRIGGER_1, // Gamepad top/back trigger right (one), it could be a trailing button + RIGHT_TRIGGER_2, // Gamepad top/back trigger right (second), it could be a trailing button + MIDDLE_LEFT, // Gamepad center buttons, left one (i.e. PS3: Select) + MIDDLE, // Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX) + MIDDLE_RIGHT, // Gamepad center buttons, right one (i.e. PS3: Start) + LEFT_THUMB, // Gamepad joystick pressed button left + RIGHT_THUMB // Gamepad joystick pressed button right } [CCode (cname = "GamepadAxis", cprefix = "GAMEPAD_AXIS_", has_type_id = false)] public enum GamepadAxis { - LEFT_X, // Gamepad left stick X axis - LEFT_Y, // Gamepad left stick Y axis - RIGHT_X, // Gamepad right stick X axis - RIGHT_Y, // Gamepad right stick Y axis - LEFT_TRIGGER, // Gamepad back trigger left, pressure level: [1..-1] - RIGHT_TRIGGER // Gamepad back trigger right, pressure level: [1..-1] + LEFT_X, // Gamepad left stick X axis + LEFT_Y, // Gamepad left stick Y axis + RIGHT_X, // Gamepad right stick X axis + RIGHT_Y, // Gamepad right stick Y axis + LEFT_TRIGGER, // Gamepad back trigger left, pressure level: [1..-1] + RIGHT_TRIGGER // Gamepad back trigger right, pressure level: [1..-1] } [CCode (cname = "MaterialMapIndex", cprefix = "MATERIAL_MAP_", has_type_id = false)] public enum MaterialMapIndex { - ALBEDO, // Albedo material (same as: MATERIAL_MAP_DIFFUSE) - METALNESS, // Metalness material (same as: MATERIAL_MAP_SPECULAR) - NORMAL, // Normal material - ROUGHNESS, // Roughness material - OCCLUSION, // Ambient occlusion material - EMISSION, // Emission material - HEIGHT, // Heightmap material - CUBEMAP, // Cubemap material (NOTE: Uses GL_TEXTURE_CUBE_MAP) - IRRADIANCE, // Irradiance material (NOTE: Uses GL_TEXTURE_CUBE_MAP) - PREFILTER, // Prefilter material (NOTE: Uses GL_TEXTURE_CUBE_MAP) + ALBEDO, // Albedo material (same as: MATERIAL_MAP_DIFFUSE) + METALNESS, // Metalness material (same as: MATERIAL_MAP_SPECULAR) + NORMAL, // Normal material + ROUGHNESS, // Roughness material + OCCLUSION, // Ambient occlusion material + EMISSION, // Emission material + HEIGHT, // Heightmap material + CUBEMAP, // Cubemap material (NOTE: Uses GL_TEXTURE_CUBE_MAP) + IRRADIANCE, // Irradiance material (NOTE: Uses GL_TEXTURE_CUBE_MAP) + PREFILTER, // Prefilter material (NOTE: Uses GL_TEXTURE_CUBE_MAP) BRDF } + [CCode (cname = "ShaderLocationIndex", cprefix = "SHADER_LOC_", has_type_id = false)] + public enum ShaderLocationIndex { + VERTEX_POSITION = 0, // Shader location: vertex attribute: position + VERTEX_TEXCOORD01, // Shader location: vertex attribute: texcoord01 + VERTEX_TEXCOORD02, // Shader location: vertex attribute: texcoord02 + VERTEX_NORMAL, // Shader location: vertex attribute: normal + VERTEX_TANGENT, // Shader location: vertex attribute: tangent + VERTEX_COLOR, // Shader location: vertex attribute: color + MATRIX_MVP, // Shader location: matrix uniform: model-view-projection + MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) + MATRIX_PROJECTION, // Shader location: matrix uniform: projection + MATRIX_MODEL, // Shader location: matrix uniform: model (transform) + MATRIX_NORMAL, // Shader location: matrix uniform: normal + VECTOR_VIEW, // Shader location: vector uniform: view + COLOR_DIFFUSE, // Shader location: vector uniform: diffuse color + COLOR_SPECULAR, // Shader location: vector uniform: specular color + COLOR_AMBIENT, // Shader location: vector uniform: ambient color + MAP_ALBEDO, // Shader location: sampler2d texture: albedo (same as: SHADER_LOC_MAP_DIFFUSE) + MAP_METALNESS, // Shader location: sampler2d texture: metalness (same as: SHADER_LOC_MAP_SPECULAR) + MAP_NORMAL, // Shader location: sampler2d texture: normal + MAP_ROUGHNESS, // Shader location: sampler2d texture: roughness + MAP_OCCLUSION, // Shader location: sampler2d texture: occlusion + MAP_EMISSION, // Shader location: sampler2d texture: emission + MAP_HEIGHT, // Shader location: sampler2d texture: height + MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap + MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance + MAP_PREFILTER, // Shader location: samplerCube texture: prefilter + MAP_BRDF, // Shader location: sampler2d texture: brdf + VERTEX_BONEIDS, // Shader location: vertex attribute: bone indices + VERTEX_BONEWEIGHTS, // Shader location: vertex attribute: bone weights + MATRIX_BONETRANSFORMS, // Shader location: matrix attribute: bone transforms (animation) + VERTEX_INSTANCETRANSFORM; // Shader location: vertex attribute: instance transforms + + [CCode (cname = "SHADER_LOC_MAP_DIFFUSE")] + public const ShaderLocationIndex MAP_DIFFUSE; + + [CCode (cname = "SHADER_LOC_MAP_SPECULAR")] + public const ShaderLocationIndex MAP_SPECULAR; + } + [CCode (cname = "ShaderUniformDataType", cprefix = "SHADER_UNIFORM_", has_type_id = false)] public enum ShaderUniformDataType { - FLOAT, // Shader uniform type: float - VEC2, // Shader uniform type: vec2 (2 float) - VEC3, // Shader uniform type: vec3 (3 float) - VEC4, // Shader uniform type: vec4 (4 float) - INT, // Shader uniform type: int - IVEC2, // Shader uniform type: ivec2 (2 int) - IVEC3, // Shader uniform type: ivec3 (3 int) - IVEC4, // Shader uniform type: ivec4 (4 int) - SAMPLER2D // Shader uniform type: sampler2d + FLOAT, // Shader uniform type: float + VEC2, // Shader uniform type: vec2 (2 float) + VEC3, // Shader uniform type: vec3 (3 float) + VEC4, // Shader uniform type: vec4 (4 float) + INT, // Shader uniform type: int + IVEC2, // Shader uniform type: ivec2 (2 int) + IVEC3, // Shader uniform type: ivec3 (3 int) + IVEC4, // Shader uniform type: ivec4 (4 int) + UINT, // Shader uniform type: unsigned int + UIVEC2, // Shader uniform type: uivec2 (2 unsigned int) + UIVEC3, // Shader uniform type: uivec3 (3 unsigned int) + UIVEC4, // Shader uniform type: uivec4 (4 unsigned int) + SAMPLER2D // Shader uniform type: sampler2d } [CCode (cname = "ShaderAttributeDataType", cprefix = "SHADER_ATTRIB_", has_type_id = false)] public enum ShaderAttributeDataType { - FLOAT, // Shader attribute type: float - VEC2, // Shader attribute type: vec2 (2 float) - VEC3, // Shader attribute type: vec3 (3 float) - VEC4 // Shader attribute type: vec4 (4 float) + FLOAT, // Shader attribute type: float + VEC2, // Shader attribute type: vec2 (2 float) + VEC3, // Shader attribute type: vec3 (3 float) + VEC4 // Shader attribute type: vec4 (4 float) } [CCode (cname = "PixelFormat", cprefix = "PIXELFORMAT_", has_type_id = false)] public enum PixelFormat { - UNCOMPRESSED_GRAYSCALE, // 8 bit per pixel (no alpha) - UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) - UNCOMPRESSED_R5G6B5, // 16 bpp - UNCOMPRESSED_R8G8B8, // 24 bpp - UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) - UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) - UNCOMPRESSED_R8G8B8A8, // 32 bpp - UNCOMPRESSED_R32, // 32 bpp (1 channel - float) - UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) - UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) - UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) - UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) - UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) - COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) - COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) - COMPRESSED_DXT3_RGBA, // 8 bpp - COMPRESSED_DXT5_RGBA, // 8 bpp - COMPRESSED_ETC1_RGB, // 4 bpp - COMPRESSED_ETC2_RGB, // 4 bpp - COMPRESSED_ETC2_EAC_RGBA, // 8 bpp - COMPRESSED_PVRT_RGB, // 4 bpp - COMPRESSED_PVRT_RGBA, // 4 bpp - COMPRESSED_ASTC_4x4_RGBA, // 8 bpp // vala-lint=naming-convention - COMPRESSED_ASTC_8x8_RGBA // 2 bpp // vala-lint=naming-convention + UNCOMPRESSED_GRAYSCALE, // 8 bit per pixel (no alpha) + UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) + UNCOMPRESSED_R5G6B5, // 16 bpp + UNCOMPRESSED_R8G8B8, // 24 bpp + UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) + UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) + UNCOMPRESSED_R8G8B8A8, // 32 bpp + UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) + UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) + UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) + UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) + COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) + COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) + COMPRESSED_DXT3_RGBA, // 8 bpp + COMPRESSED_DXT5_RGBA, // 8 bpp + COMPRESSED_ETC1_RGB, // 4 bpp + COMPRESSED_ETC2_RGB, // 4 bpp + COMPRESSED_ETC2_EAC_RGBA, // 8 bpp + COMPRESSED_PVRT_RGB, // 4 bpp + COMPRESSED_PVRT_RGBA, // 4 bpp + [CCode (cname = "PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA")] + COMPRESSED_ASTC_4X4_RGBA, + [CCode (cname = "PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA")] + COMPRESSED_ASTC_8X8_RGBA // 2 bpp } [CCode (cname = "TextureFilter", cprefix = "TEXTURE_FILTER_", has_type_id = false)] public enum TextureFilter { - POINT, // No filter, just pixel approximation - BILINEAR, // Linear filtering - TRILINEAR, // Trilinear filtering (linear with mipmaps) - ANISOTROPIC_4X, // Anisotropic filtering 4x - ANISOTROPIC_8X, // Anisotropic filtering 8x - ANISOTROPIC_16X, // Anisotropic filtering 16x + POINT, // No filter, just pixel approximation + BILINEAR, // Linear filtering + TRILINEAR, // Trilinear filtering (linear with mipmaps) + ANISOTROPIC_4X, // Anisotropic filtering 4x + ANISOTROPIC_8X, // Anisotropic filtering 8x + ANISOTROPIC_16X, // Anisotropic filtering 16x } [CCode (cname = "TextureWrap", cprefix = "TEXTURE_WRAP_", has_type_id = false)] public enum TextureWrap { - REPEAT, // Repeats texture in tiled mode - CLAMP, // Clamps texture to edge pixel in tiled mode - MIRROR_REPEAT, // Mirrors and repeats the texture in tiled mode - MIRROR_CLAMP // Mirrors and clamps to border the texture in tiled mode + REPEAT, // Repeats texture in tiled mode + CLAMP, // Clamps texture to edge pixel in tiled mode + MIRROR_REPEAT, // Mirrors and repeats the texture in tiled mode + MIRROR_CLAMP // Mirrors and clamps to border the texture in tiled mode } [CCode (cname = "CubemapLayout", cprefix = "CUBEMAP_LAYOUT_", has_type_id = false)] public enum CubemapLayout { - AUTO_DETECT, // Automatically detect layout type - LINE_VERTICAL, // Layout is defined by a vertical line with faces - LINE_HORIZONTAL, // Layout is defined by an horizontal line with faces - CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces - CROSS_FOUR_BY_THREE, // Layout is defined by a 4x3 cross with cubemap faces - PANORAMA // Layout is defined by a panorama image (equirectangular map) + AUTO_DETECT, // Automatically detect layout type + LINE_VERTICAL, // Layout is defined by a vertical line with faces + LINE_HORIZONTAL, // Layout is defined by an horizontal line with faces + CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces + CROSS_FOUR_BY_THREE, // Layout is defined by a 4x3 cross with cubemap faces } [CCode (cname = "FontType", cprefix = "FONT_", has_type_id = false)] public enum FontType { - DEFAULT, // Default font generation, anti-aliased - BITMAP, // Bitmap font generation, no anti-aliasing - SDF // SDF font generation, requires external shader + DEFAULT, // Default font generation, anti-aliased + BITMAP, // Bitmap font generation, no anti-aliasing + SDF // SDF font generation, requires external shader } [CCode (cname = "BlendMode", cprefix = "BLEND_", has_type_id = false)] public enum BlendMode { - ALPHA, // Blend textures considering alpha (default) - ADDITIVE, // Blend textures adding colors - MULTIPLIED, // Blend textures multiplying colors - ADD_COLORS, // Blend textures adding colors (alternative) - SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) - ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha - CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendMode()) - BLEND_CUSTOM_SEPARATE // Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate()) + ALPHA, // Blend textures considering alpha (default) + ADDITIVE, // Blend textures adding colors + MULTIPLIED, // Blend textures multiplying colors + ADD_COLORS, // Blend textures adding colors (alternative) + SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) + ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha + CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendMode()) + BLEND_CUSTOM_SEPARATE // Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate()) } [Flags] [CCode (cname = "Gesture", cprefix = "GESTURE_", has_type_id = false)] public enum Gesture { - NONE, // No gesture - TAP, // Tap gesture - DOUBLETAP, // Double tap gesture - HOLD, // Hold gesture - DRAG, // Drag gesture - SWIPE_RIGHT, // Swipe right gesture - SWIPE_LEFT, // Swipe left gesture - SWIPE_UP, // Swipe up gesture - SWIPE_DOWN, // Swipe down gesture - PINCH_IN, // Pinch in gesture - PINCH_OUT // Pinch out gesture + NONE, // No gesture + TAP, // Tap gesture + DOUBLETAP, // Double tap gesture + HOLD, // Hold gesture + DRAG, // Drag gesture + SWIPE_RIGHT, // Swipe right gesture + SWIPE_LEFT, // Swipe left gesture + SWIPE_UP, // Swipe up gesture + SWIPE_DOWN, // Swipe down gesture + PINCH_IN, // Pinch in gesture + PINCH_OUT // Pinch out gesture } [CCode (cname = "CameraMode", cprefix = "CAMERA_", has_type_id = false)] public enum CameraMode { - CUSTOM, // Custom camera - FREE, // Free camera - ORBITAL, // Orbital camera - FIRST_PERSON, // First person camera - THIRD_PERSON // Third person camera + CUSTOM, // Custom camera + FREE, // Free camera + ORBITAL, // Orbital camera + FIRST_PERSON, // First person camera + THIRD_PERSON // Third person camera } [CCode (cname = "CameraProjection", cprefix = "CAMERA_", has_type_id = false)] public enum CameraProjection { - PERSPECTIVE, // Perspective projection - ORTHOGRAPHIC // Orthographic projection + PERSPECTIVE, // Perspective projection + ORTHOGRAPHIC // Orthographic projection } [CCode (cname = "NPatchLayout", cprefix = "NPATCH_", has_type_id = false)] public enum NPatchLayout { - NINE_PATCH, // Npatch layout: 3x3 tiles - THREE_PATCH_VERTICAL, // Npatch layout: 1x3 tiles - THREE_PATCH_HORIZONTAL // Npatch layout: 3x1 tiles + NINE_PATCH, // Npatch layout: 3x3 tiles + THREE_PATCH_VERTICAL, // Npatch layout: 1x3 tiles + THREE_PATCH_HORIZONTAL // Npatch layout: 3x1 tiles } + // ---------------------------------------------------------------------------------- // Callbacks to hook some internal functions - // WARNING: This callbacks are intended for advance users + // ---------------------------------------------------------------------------------- + // WARNING: This callbacks are intended for advanced users [CCode (cname = "TraceLogCallback")] public delegate void TraceLogCallback (TraceLogLevel log_level, string text, va_list args); [CCode (cname = "LoadFileDataCallback")] - public delegate uchar LoadFileDataCallback (string filename, out int bytes_read); + public delegate uchar LoadFileDataCallback (string filename, out int data_size); [CCode (cname = "SaveFileDataCallback")] - public delegate bool SaveFileDataCallback (string filename, void* data, int bytes_to_write); + public delegate bool SaveFileDataCallback (string filename, void* data, int data_size); [CCode (cname = "LoadFileTextCallback")] public delegate char LoadFileTextCallback (string filename); @@ -903,19 +959,24 @@ namespace Raylib { public delegate bool SaveFileTextCallback (string filename, string text); //------------------------------------------------------------------------------------ - // Window and Graphics Device Functions (Module: core) + // Global Variables Definition //------------------------------------------------------------------------------------ + // It's lonely here... + + // ------------------------------------------------------------------------------------ + // Window and Graphics Device Functions (Module: core) + // ------------------------------------------------------------------------------------ // Window-related functions [CCode (cname = "InitWindow")] public static void init_window (int width, int height, string title); - [CCode (cname = "WindowShouldClose")] - public static bool window_should_close (); - [CCode (cname = "CloseWindow")] public static void close_window (); + [CCode (cname = "WindowShouldClose")] + public static bool window_should_close (); + [CCode (cname = "IsWindowReady")] public static bool is_window_ready (); @@ -950,10 +1011,10 @@ namespace Raylib { public static void toggle_fullscreen (); [CCode (cname = "ToggleBorderlessWindowed")] - public static void toggle_borderless (); + public static void toggle_borderless_windowed (); [CCode (cname = "MaximizeWindow")] - public static void maximise_window (); + public static void maximize_window (); [CCode (cname = "MinimizeWindow")] public static void minimize_window (); @@ -992,7 +1053,7 @@ namespace Raylib { public static void set_window_focused (); [CCode (cname = "GetWindowHandle")] - public static void* get_window_handle (); + public static void * get_window_handle (); [CCode (cname = "GetScreenWidth")] public static int get_screen_width (); @@ -1006,26 +1067,20 @@ namespace Raylib { [CCode (cname = "GetRenderHeight")] public static int get_render_height (); + [CCode (cname = "GetMonitorCount")] + public static int get_monitor_count (); + [CCode (cname = "GetCurrentMonitor")] public static int get_current_monitor (); [CCode (cname = "GetMonitorPosition")] public static Vector2 get_monitor_position (int monitor); - [CCode (cname = "GetWindowPosition")] - public static Vector2 get_window_position (); - - [CCode (cname = "GetWindowScaleDPI")] - public static Vector2 get_window_scale_dpi (); - - [CCode (cname = "GetMonitorCount")] - public static int get_monitor_count (); - [CCode (cname = "GetMonitorWidth")] public static int get_monitor_width (int monitor); [CCode (cname = "GetMonitorHeight")] - public static int get_hmonitor_eight (int monitor); + public static int get_monitor_height (int monitor); [CCode (cname = "GetMonitorPhysicalWidth")] public static int get_monitor_physical_width (int monitor); @@ -1036,6 +1091,12 @@ namespace Raylib { [CCode (cname = "GetMonitorRefreshRate")] public static int get_monitor_refresh_rate (int monitor); + [CCode (cname = "GetWindowPosition")] + public static Vector2 get_window_position (); + + [CCode (cname = "GetWindowScaleDPI")] + public static Vector2 get_window_scale_dpi (); + [CCode (cname = "GetMonitorName")] public static string get_monitor_name (int monitor); @@ -1045,23 +1106,15 @@ namespace Raylib { [CCode (cname = "GetClipboardText")] public static string get_clipboard_text (); + [CCode (cname = "GetClipboardImage")] + public static Image get_clipboard_image (); + [CCode (cname = "EnableEventWaiting")] public static void enable_event_waiting (); [CCode (cname = "DisableEventWaiting")] public static void disable_event_waiting (); - // Custom frame control functions - // NOTE: Those functions are intended for advance users that want full control over the frame processing - [CCode (cname = "SwapScreenBuffer")] - public static void swap_screen_buffer (); - - [CCode (cname = "PollInputEvents")] - public static void poll_input_events (); - - [CCode (cname = "WaitTime")] - public static void wait_time (double seconds); - // Cursor-related functions [CCode (cname = "ShowCursor")] public static void show_cursor (); @@ -1092,16 +1145,16 @@ namespace Raylib { public static void end_drawing (); [CCode (cname = "BeginMode2D")] - public static void begin_mode_2D (Camera2D camera); // vala-lint=naming-convention + public static void begin_mode_2d (Camera2D camera); [CCode (cname = "EndMode2D")] - public static void end_mode_2D (); // vala-lint=naming-convention + public static void end_mode_2d (); [CCode (cname = "BeginMode3D")] - public static void begin_mode_3D (Camera3D camera); // vala-lint=naming-convention + public static void begin_mode_3d (Camera3D camera); [CCode (cname = "EndMode3D")] - public static void end_mode_3D (); // vala-lint=naming-convention + public static void end_mode_3d (); [CCode (cname = "BeginTextureMode")] public static void begin_texture_mode (RenderTexture2D target); @@ -1148,8 +1201,8 @@ namespace Raylib { [CCode (cname = "LoadShaderFromMemory")] public static Shader load_shader_from_memory (string? vertex_shader, string? fragment_shader); - [CCode (cname = "IsShaderReady")] - public static bool is_shader_ready (Shader shader); + [CCode (cname = "IsShaderValid")] + public static bool is_shader_valid (Shader shader); [CCode (cname = "GetShaderLocation")] public int get_shader_location (Shader shader, string uniform_name); @@ -1161,7 +1214,8 @@ namespace Raylib { public void set_shader_value (Shader shader, int location, void* value, ShaderUniformDataType type); [CCode (cname = "SetShaderValueV")] - public void set_shader_value_vector (Shader shader, int location, void* value, ShaderUniformDataType type, int count); + public void set_shader_value_vector (Shader shader, int location, void* value, ShaderUniformDataType type, + int count); [CCode (cname = "SetShaderValueMatrix")] public void set_shader_value_matrix (Shader shader, int location, Matrix matrix); @@ -1172,91 +1226,103 @@ namespace Raylib { [CCode (cname = "UnloadShader")] public void unload_shader (Shader shader); - // Screen-space-related functions - [CCode (cname = "GetMouseRay")] - public static Ray get_mouse_ray (Vector2 mouse_position, Camera camera); + // Screen-space-related functions + [CCode (cname = "GetScreenToWorldRay")] + public static Ray get_screen_to_world_ray (Vector2 mouse_position, Camera camera); - [CCode (cname = "GetCameraMatrix")] - public static Matrix get_camera_matrix (Camera camera); - - [CCode (cname = "GetCameraMatrix2D")] - public static Matrix get_camera_matrix_2D (Camera2D camera); // vala-lint=naming-convention + [CCode (cname = "GetScreenToWorldRayEx")] + public static Ray get_screen_to_world_ray_ext (Vector2 mouse_position, Camera camera, int width, int height); [CCode (cname = "GetWorldToScreen")] public static Vector2 get_world_to_screen (Vector3 position, Camera camera); - [CCode (cname = "GetScreenToWorld2D")] - public static Vector2 get_screen_to_world_2D (Vector2 position, Camera2D camera); // vala-lint=naming-convention - [CCode (cname = "GetWorldToScreenEx")] - public static Vector2 get_get_world_to_screen_ext (Vector3 position, Camera camera, int width, int height); + public static Vector2 get_world_to_screen_ext (Vector3 position, Camera camera, int width, int height); [CCode (cname = "GetWorldToScreen2D")] - public static Vector2 get_world_to_screen_2D (Vector2 position, Camera2D camera); // vala-lint=naming-convention + public static Vector2 get_world_to_screen_2d (Vector3 position, Camera2D camera); + + [CCode (cname = "GetScreenToWorld2D")] + public static Vector2 get_screen_to_world_2d (Vector2 position, Camera2D camera); + + [CCode (cname = "GetCameraMatrix")] + public static Matrix get_camera_matrix (Camera camera); + + [CCode (cname = "GetCameraMatrix2D")] + public static Matrix get_camera_matrix_2d (Camera2D camera); - // Timing-related functions + // Timing-related functions [CCode (cname = "SetTargetFPS")] public static void set_target_fps (int fps); - [CCode (cname = "GetFPS")] - public static int get_fps (); - [CCode (cname = "GetFrameTime")] public static float get_frame_time (); [CCode (cname = "GetTime")] public static double get_time (); - // Misc. functions - [CCode (cname = "GetRandomValue")] - public static int get_random_value (int minimum, int maximum); + [CCode (cname = "GetFPS")] + public static int get_fps (); + + // Custom frame control functions + // NOTE: Those functions are intended for advance users that want full control over the frame processing + // By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents() + // To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL + [CCode (cname = "SwapScreenBuffer")] + public static void swap_screen_buffer (); + + [CCode (cname = "PollInputEvents")] + public static void poll_input_events (); + + [CCode (cname = "WaitTime")] + public static void wait_time (double seconds); + // Random values generation functions [CCode (cname = "SetRandomSeed")] public static void set_random_seed (uint seed); + [CCode (cname = "GetRandomValue")] + public static int get_random_value (int minimum, int maximum); + + [CCode (cname = "LoadRandomSequence", array_length_cname = "count", array_length_type = "int")] + public static int[] load_random_sequence (uint count, int min, int max); + + [CCode (cname = "UnloadRandomSequence", array_length = false)] + public static void unload_random_sequence ([CCode (array_length = false)] int[] sequence); + + // Misc. functions [CCode (cname = "TakeScreenshot")] public static void take_screenshot (string filename); [CCode (cname = "SetConfigFlags")] public static void set_config_flags (ConfigFlags flags); + [CCode (cname = "OpenURL")] + public static void open_url (string url); + + //------------------------------------------------------------------ + // NOTE: Following functions implemented in module [utils] + //------------------------------------------------------------------ + // Logging system + [CCode (cname = "SetTraceLogLevel")] + public static void set_trace_log_level (TraceLogLevel level); [CCode (cname = "TraceLog")] public static void trace_log (TraceLogLevel level, string text, ...); - [CCode (cname = "SetTraceLogLevel")] - public static void set_trace_log_level (TraceLogLevel level); + [CCode (cname = "SetTraceLogCallback")] + public static void set_trace_log_callback (TraceLogCallback callback); + // Memory management, using internal allocators [CCode (cname = "MemAlloc")] - public static void* memory_allocate (uint size); + public static void * memory_allocate (uint size); [CCode (cname = "MemRealloc")] - public static void* memory_realocate (void* pointer, uint size); + public static void * memory_realocate (void* pointer, uint size); [CCode (cname = "MemFree")] public static void memory_free (void* pointer); - - [CCode (cname = "OpenURL")] - public static void open_url (string url); - - // Set custom callbacks - // WARNING: Callbacks setup is intended for advance users - [CCode (cname = "SetTraceLogCallback")] - public static void set_trace_log_callback (TraceLogCallback callback); - - [CCode (cname = "SetLoadFileDataCallback")] - public static void set_load_file_data_callback (LoadFileDataCallback callback); - - [CCode (cname = "SetSaveFileDataCallback")] - public static void set_save_file_data_callback (SaveFileDataCallback callback); - - [CCode (cname = "SetLoadFileTextCallback")] - public static void set_load_file_text_callback (LoadFileTextCallback callback); - - [CCode (cname = "SetSaveFileTextCallback")] - public static void set_save_file_text_callback (SaveFileTextCallback callback); - // Files management functions [CCode (cname = "LoadFileData")] public static uchar[] load_file_data (string filename, out uint bytes_read); @@ -1279,6 +1345,39 @@ namespace Raylib { [CCode (cname = "SaveFileText")] public static bool save_file_text (string filename, string text); + // Set custom callbacks + // WARNING: Callbacks setup is intended for advance users + [CCode (cname = "SetLoadFileDataCallback")] + public static void set_load_file_data_callback (LoadFileDataCallback callback); + + [CCode (cname = "SetSaveFileDataCallback")] + public static void set_save_file_data_callback (SaveFileDataCallback callback); + + [CCode (cname = "SetLoadFileTextCallback")] + public static void set_load_file_text_callback (LoadFileTextCallback callback); + + [CCode (cname = "SetSaveFileTextCallback")] + public static void set_save_file_text_callback (SaveFileTextCallback callback); + + // File system functions + [CCode (cname = "FileRename")] + public static int file_rename (string file_name, string file_rename); + + [CCode (cname = "FileRemove")] + public static int file_remove (string file_name); + + [CCode (cname = "FileCopy")] + public static int file_copy (string src_path, string dst_path); + + [CCode (cname = "FileMove")] + public static int file_move (string src_path, string dst_path); + + [CCode (cname = "FileTextReplace")] + public static int file_text_replace (string file_name, string search, string replacement); + + [CCode (cname = "FileTextFindIndex")] + public static int file_text_find_index (string file_name, string search); + [CCode (cname = "FileExists")] public static bool file_exists (string filename); @@ -1291,38 +1390,47 @@ namespace Raylib { [CCode (cname = "GetFileLength")] public static int get_file_length (string filename); + [CCode (cname = "GetFileModTime")] + public static long get_file_modified_time (string filename); + [CCode (cname = "GetFileExtension")] public static string get_file_extension (string filename); - [CCode (cname = "Getfilename")] - public static string get_filename (string file); + [CCode (cname = "GetFileName")] + public static string get_file_name (string file_path); - [CCode (cname = "GetfilenameWithoutExt")] - public static string get_filename_without_extension (string file); + [CCode (cname = "GetFileNameWithoutExt")] + public static string get_file_name_without_extension (string file_path); [CCode (cname = "GetDirectoryPath")] - public static string get_directory_path (string file); + public static string get_directory_path (string file_path); [CCode (cname = "GetPrevDirectoryPath")] public static string get_previous_directory_path (string directory); [CCode (cname = "GetWorkingDirectory")] - public static string get_work_directory (); + public static string get_working_directory (); [CCode (cname = "GetApplicationDirectory")] public static string get_application_directory (); + [CCode (cname = "MakeDirectory")] + public static int make_directory (string dir_path); + [CCode (cname = "ChangeDirectory")] public static bool change_directory (string dir); [CCode (cname = "IsPathFile")] public static bool is_path_file (string path); + [CCode (cname = "IsFileNameValid")] + public static bool is_file_name_valid (string file_name); + [CCode (cname = "LoadDirectoryFiles")] public static FilePathList load_directory_files (string directory); [CCode (cname = "LoadDirectoryFilesEx")] - public static FilePathList load_directory_files_ext (string basePath, string filter, bool scan_sub_directories); + public static FilePathList load_directory_files_ext (string base_path, string filter, bool scan_sub_directories); [CCode (cname = "UnloadDirectoryFiles")] public static void unload_directory_files (FilePathList files); @@ -1330,82 +1438,94 @@ namespace Raylib { [CCode (cname = "IsFileDropped")] public static bool is_file_dropped (); - [CCode (cname = "FilePathList")] + [CCode (cname = "LoadDroppedFiles")] public static FilePathList load_dropped_files (); [CCode (cname = "UnloadDroppedFiles")] public static void unload_dropped_files (FilePathList files); - [CCode (cname = "GetFileModTime")] - public static long get_fil_modified_time (string filename); - // Compression/Encoding functionality [CCode (cname = "CompressData")] - public static uchar[] compress_data (uchar[] data, out int size); + public static uchar[] compress_data (uchar[] data); [CCode (cname = "DecompressData")] - public static uchar[] decompress_data (uchar[] compressed_data, out int size); + public static uchar[] decompress_data (uchar[] compressed_data); [CCode (cname = "EncodeDataBase64")] - public static char[] encode_data_base64 (uchar[] data, out int size); + public static char[] encode_data_base64 (uchar[] data); [CCode (cname = "DecodeDataBase64")] - public static uchar[] decode_data_base64 (uchar[] data, out int size); + public static uchar[] decode_data_base64 (uchar[] data); + + [CCode (cname = "ComputeCRC32")] + public static int compute_crc32 (uchar[] data); + + [CCode (cname = "ComputeMD5", array_length_cexpr = "4")] + public static int[] compute_md5 (uchar[] data); + + [CCode (cname = "ComputeSHA1", array_length_cexpr = "5")] + public static int[] compute_sha1 (uchar[] data); + + [CCode (cname = "ComputeSHA256", array_length_cexpr = "8")] + public static int[] compute_sha256 (uchar[] data); // Automation events functionality [CCode (cname = "LoadAutomationEventList")] - public static AutomationEventList load_automation_event_list (string filename); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS + public static AutomationEventList load_automation_event_list (string file_name); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS [CCode (cname = "UnloadAutomationEventList")] - public static void unload_automation_event_list (AutomationEventList[] list); // Unload automation events list from file + public static void unload_automation_event_list (AutomationEventList list); // Unload automation events list from file [CCode (cname = "ExportAutomationEventList")] - public static bool export_automation_event_list (AutomationEventList list, string filename); // Export automation events list as text file + public static bool export_automation_event_list (AutomationEventList list, string file_name); // Export automation events list as text file [CCode (cname = "SetAutomationEventList")] - public static void set_automation_event_list (AutomationEventList[] list); // Set automation event list to record to + public static void set_automation_event_list (AutomationEventList list); // Set automation event list to record to [CCode (cname = "SetAutomationEventBaseFrame")] - public static void set_automation_event_base_frame (int frame); // Set automation event internal base frame to start recording + public static void set_automation_event_base_frame (int frame); // Set automation event internal base frame to start recording [CCode (cname = "StartAutomationEventRecording")] - public static void start_automation_event_recording (); // Start recording automation events (AutomationEventList must be set) + public static void start_automation_event_recording (); // Start recording automation events (AutomationEventList must be set) [CCode (cname = "StopAutomationEventRecording")] - public static void stop_automation_event_recording (); // Stop recording automation events + public static void stop_automation_event_recording (); // Stop recording automation events [CCode (cname = "PlayAutomationEvent")] - public static void play_automation_event (AutomationEvent event); // Play a recorded automation event + public static void play_automation_event (AutomationEvent event); // Play a recorded automation event - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Input-related functions: keyboard [CCode (cname = "IsKeyPressed")] public static bool is_key_pressed (KeyboardKey key); + [CCode (cname = "IsKeyPressedRepeat")] + public static bool is_key_pressed_repeat (Raylib.KeyboardKey key); + [CCode (cname = "IsKeyDown")] public static bool is_key_down (KeyboardKey key); [CCode (cname = "IsKeyReleased")] public static bool is_key_released (KeyboardKey key); - [CCode (cname = "IsKeyPressedRepeat")] - public static bool is_key_pressed_repeat (Raylib.KeyboardKey key); - [CCode (cname = "IsKeyUp")] public static bool is_key_up (KeyboardKey key); - [CCode (cname = "SetExitKey")] - public static void set_exit_key (KeyboardKey key); - [CCode (cname = "GetKeyPressed")] public static KeyboardKey get_key_pressed (); [CCode (cname = "GetCharPressed")] public static int get_char_pressed (); + [CCode (cname = "GetKeyName")] + public static string get_key_name (KeyboardKey key); + + [CCode (cname = "SetExitKey")] + public static void set_exit_key (KeyboardKey key); + // Input-related functions: gamepads [CCode (cname = "IsGamepadAvailable")] public static bool is_gamepad_available (int gamepad); @@ -1437,6 +1557,9 @@ namespace Raylib { [CCode (cname = "SetGamepadMappings")] public static int set_gamepad_mappings (string mappings); + [CCode (cname = "SetGamepadVibration")] + public static int set_gamepad_vibration (int gamepad, float left_motor, float right_motor, float duration); + // Input-related functions: mouse [CCode (cname = "IsMouseButtonPressed")] public static bool is_mouse_button_pressed (MouseButton button); @@ -1496,9 +1619,9 @@ namespace Raylib { [CCode (cname = "GetTouchPointCount")] public static int get_touch_point_count (); - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: rgestures) - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ [CCode (cname = "SetGestureEnabled")] public static void set_gesture_enabled (Gesture flags); @@ -1512,7 +1635,7 @@ namespace Raylib { public static float get_gesture_hold_duration (); [CCode (cname = "GetGestureDragVector")] - public static Vector2 get_gesture_drag_duration (); + public static Vector2 get_gesture_drag_vector (); [CCode (cname = "GetGestureDragAngle")] public static float get_gesture_drag_angle (); @@ -1523,22 +1646,30 @@ namespace Raylib { [CCode (cname = "GetGesturePinchAngle")] public static float get_gesture_pinch_angle (); - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Camera System Functions (Module: rcamera) - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ [CCode (cname = "UpdateCamera")] public static void update_camera (Camera? camera, CameraMode mode); [CCode (cname = "UpdateCameraPro")] public static void update_camera_pro (Camera? camera, Vector3 movement, Vector3 rotation, float zoom); - - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Basic Shapes Drawing Functions (Module: shapes) - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ + // Set texture and rectangle to be used on shapes drawing + // NOTE: It can be useful when using basic shapes and one single font, + // defining a font char white rectangle would allow drawing everything in a single draw call [CCode (cname = "SetShapesTexture")] public static void set_shapes_texture (Texture2D texture, Rectangle source); + [CCode (cname = "GetShapesTexture")] + public static Texture2D get_shapes_texture (); + + [CCode (cname = "GetShapesTextureRectangle")] + public Rectangle get_shapes_texture_rectangle (); + [CCode (cname = "DrawPixel")] public static void draw_pixel (int x, int y, Color color); @@ -1557,14 +1688,23 @@ namespace Raylib { [CCode (cname = "DrawLineStrip")] public static void draw_line_strip (Vector2[] points, Color color); + [CCode (cname = "DrawLineBezier")] + public static void draw_line_bezier (Vector2 start_pos, Vector2 end_pos, float thick, Color color); + + [CCode (cname = "DrawLineDashed")] + public static void draw_line_dashed (Vector2 start_pos, Vector2 end_pos, int dash_size, int space_size, + Color color); + [CCode (cname = "DrawCircle")] public static void draw_circle (int center_x, int center_y, float radius, Color color); [CCode (cname = "DrawCircleSector")] - public static void draw_circle_sector (Vector2 center, float radius, float start, float end, int segments, Color color); + public static void draw_circle_sector (Vector2 center, float radius, float start_angle, float end_angle, + int segments, Color color); [CCode (cname = "DrawCircleSectorLines")] - public static void draw_circle_sector_lines (Vector2 center, float radius, float start, float end, int segments, Color color); + public static void draw_circle_sector_lines (Vector2 center, float radius, float start_angle, float end_angle, + int segments, Color color); [CCode (cname = "DrawCircleGradient")] public static void draw_circle_gradient (int center_x, int center_y, float radius, Color color1, Color color2); @@ -1579,16 +1719,28 @@ namespace Raylib { public static void draw_circle_lines_vector (Vector2 centre, float radius, Color color); [CCode (cname = "DrawEllipse")] - public static void draw_ellipse (int center_x, int center_y, float radius_horizontal, float radius_vertical, Color color); + public static void draw_ellipse (int center_x, int center_y, float radius_horizontal, float radius_vertical, + Color color); + + [CCode (cname = "DrawEllipseV")] + public static void draw_ellipse_vector (Vector2 center, float radius_horizontal, float radius_vertical, + Color color); [CCode (cname = "DrawEllipseLines")] - public static void draw_ellipse_lines (int center_x, int center_y, float radius_horizontal, float radius_vertical, Color color); + public static void draw_ellipse_lines (int center_x, int center_y, float radius_horizontal, float radius_vertical, + Color color); + + [CCode (cname = "DrawEllipseLinesV")] + public static void draw_ellipse_lines_vector (Vector2 center, float radius_horizontal, float radius_vertical, + Color color); [CCode (cname = "DrawRing")] - public static void draw_ring (Vector2 center, float inner_radius, float outer_radius, float start, float end, int segments, Color color); + public static void draw_ring (Vector2 center, float inner_radius, float outer_radius, float start, float end, + int segments, Color color); [CCode (cname = "DrawRingLines")] - public static void draw_ring_lines (Vector2 center, float inner_radius, float outer_radius, float start, float end, int segments, Color color); + public static void draw_ring_lines (Vector2 center, float inner_radius, float outer_radius, float start, float end, + int segments, Color color); [CCode (cname = "DrawRectangle")] public static void draw_rectangle (int x, int y, int width, int height, Color color); @@ -1606,10 +1758,12 @@ namespace Raylib { public static void draw_rectangle_gradient_vector (int x, int y, int width, int height, Color color1, Color color2); [CCode (cname = "DrawRectangleGradientH")] - public static void draw_rectangle_gradient_horizontal (int x, int y, int width, int height, Color color1, Color color2); + public static void draw_rectangle_gradient_horizontal (int x, int y, int width, int height, Color color1, + Color color2); [CCode (cname = "DrawRectangleGradientEx")] - public static void draw_rectangle_gradient_ext (Rectangle rectangle, Color color1, Color color2, Color color3, Color color4); + public static void draw_rectangle_gradient_ext (Rectangle rectangle, Color color1, Color color2, Color color3, + Color color4); [CCode (cname = "DrawRectangleLines")] public static void draw_rectangle_lines (int x, int y, int width, int height, Color color); @@ -1621,7 +1775,11 @@ namespace Raylib { public static void draw_rectangle_rounded (Rectangle rectangle, float roundness, int segments, Color color); [CCode (cname = "DrawRectangleRoundedLines")] - public static void draw_rectangle_rounded_lines (Rectangle rectangle, float roundness, int segments, float thickness, Color color); + public static void draw_rectangle_rounded_lines (Rectangle rectangle, float roundness, int segments, Color color); + + [CCode (cname = "DrawRectangleRoundedLinesEx")] + public static void draw_rectangle_rounded_lines_ext (Rectangle rectangle, float roundness, int segments, + float thickness, Color color); [CCode (cname = "DrawTriangle")] public static void draw_triangle (Vector2 vector1, Vector2 vector2, Vector2 vector3, Color color); @@ -1642,13 +1800,14 @@ namespace Raylib { public static void draw_poly_lines (Vector2 center, int sides, float radius, float rotation, Color color); [CCode (cname = "DrawPolyLinesEx")] - public static void draw_poly_lines_ext (Vector2 center, int sides, float radius, float rotation, float thickness, Color color); + public static void draw_poly_lines_ext (Vector2 center, int sides, float radius, float rotation, float thickness, + Color color); // Splines drawing functions [CCode (cname = "DrawSplineLinear")] public static void draw_spline_linear (Vector2[] points, float thick, Color color); - [CCode (cname = "DrawSplineBasic")] + [CCode (cname = "DrawSplineBasis")] public static void draw_spline_basis (Vector2[] points, float thick, Color color); [CCode (cname = "DrawSplineCatmullRom")] @@ -1664,16 +1823,20 @@ namespace Raylib { public static void draw_spline_segment_linear (Vector2 p1, Vector2 p2, float thick, Color color); [CCode (cname = "DrawSplineSegmentBasis")] - public static void draw_spline_segment_basis (Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); + public static void draw_spline_segment_basis (Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, + Color color); [CCode (cname = "DrawSplineSegmentCatmullRom")] - public static void draw_spline_segment_catmull_rom (Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); + public static void draw_spline_segment_catmull_rom (Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, + Color color); [CCode (cname = "DrawSplineSegmentBezierQuadratic")] - public static void draw_spline_segment_bezier_quadratic (Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color); + public static void draw_spline_segment_bezier_quadratic (Vector2 p1, Vector2 c2, Vector2 p3, float thick, + Color color); [CCode (cname = "DrawSplineSegmentBezierCubic")] - public static void draw_spline_segment_bezier_cubic (Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color); + public static void draw_spline_segment_bezier_cubic (Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, + Color color); // Spline segment point evaluation functions, for a given t [0.0f .. 1.0f] [CCode (cname = "GetSplinePointLinear")] @@ -1691,7 +1854,7 @@ namespace Raylib { [CCode (cname = "GetSplinePointBezierCubic")] public static Vector2 get_spline_point_bezier_cubic (Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float weight); - // Basic shapes collision detection functions + // Basic shapes collision detection functions [CCode (cname = "CheckCollisionRecs")] public static bool check_collision_rectangles (Rectangle rectangle1, Rectangle rectangle2); @@ -1701,6 +1864,9 @@ namespace Raylib { [CCode (cname = "CheckCollisionCircleRec")] public static bool check_collision_circle_rectangle (Vector2 center, float radius, Rectangle rectangle); + [CCode (cname = "CheckCollisionCircleLine")] + public static bool check_collision_circle_line (Vector2 center, float radius, Vector2 p1, Vector2 p2); + [CCode (cname = "CheckCollisionPointRec")] public static bool check_collision_point_rectangle (Vector2 point, Rectangle rectangle); @@ -1710,21 +1876,22 @@ namespace Raylib { [CCode (cname = "CheckCollisionPointTriangle")] public static bool check_collision_point_triangle (Vector2 point, Vector2 point1, Vector2 point2, Vector2 point3); + [CCode (cname = "CheckCollisionPointLine")] + public static bool check_collision_point_line (Vector2 point, Vector2 start, Vector2 end, int threshold); + [CCode (cname = "CheckCollisionPointPoly")] public static bool check_collision_point_poly (Vector2 point, Vector2[] points); [CCode (cname = "CheckCollisionLines")] - public static bool check_collision_lines (Vector2 start1, Vector2 end1, Vector2 start2, Vector2 end2, Vector2[] collision_point); - - [CCode (cname = "CheckCollisionPointLine")] - public static bool check_collision_point_line (Vector2 point, Vector2 start, Vector2 end, int threshold); + public static bool check_collision_lines (Vector2 start1, Vector2 end1, Vector2 start2, Vector2 end2, + Vector2[] collision_point); [CCode (cname = "GetCollisionRec")] public static Rectangle get_collision_rectangle (Rectangle rectangle1, Rectangle rectangle2); - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Texture Loading and Drawing Functions (Module: textures) - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Image loading functions // NOTE: This functions do not require GPU access @@ -1734,12 +1901,13 @@ namespace Raylib { [CCode (cname = "LoadImageRaw")] public static Image load_image_raw (string filename, int width, int height, int format, int header_size); - [CCode (cname = "LoadImageSvg")] - public static Image load_image_svg (string filename, int width, int height); - [CCode (cname = "LoadImageAnim")] public static Image load_image_animation (string filename, out int frames); + [CCode (cname = "LoadImageAnimFromMemory")] + public static Image load_image_animation_from_memory (string file_type, uchar[] file_data, + [CCode (array_length = false)] int[] frames); + [CCode (cname = "LoadImageFromMemory")] public static Image load_image_from_memory (string filename, uchar[] file_data); @@ -1749,8 +1917,8 @@ namespace Raylib { [CCode (cname = "LoadImageFromScreen")] public static Image load_image_from_screen (); - [CCode (cname = "IsImageReady")] - public static bool is_image_ready (Image image); + [CCode (cname = "IsImageValid")] + public static bool is_image_valid (Image image); [CCode (cname = "UnloadImage")] public static void unload_image (Image image); @@ -1778,7 +1946,8 @@ namespace Raylib { public static Image generate_image_gradient_square (int width, int height, float density, Color inner, Color outer); [CCode (cname = "GenImageChecked")] - public static Image generate_image_checked (int width, int height, int checks_x, int checks_y, Color primary, Color secondary); + public static Image generate_image_checked (int width, int height, int checks_x, int checks_y, Color primary, + Color secondary); [CCode (cname = "GenImageWhiteNoise")] public static Image generate_image_white_noise (int width, int height, float factor); @@ -1799,6 +1968,9 @@ namespace Raylib { [CCode (cname = "ImageFromImage")] public static Image image_from_image (Image image, Rectangle rectangle); + [CCode (cname = "ImageFromChannel")] + public static Image image_from_channel (Image image, int selected_channel); + [CCode (cname = "ImageText")] public static Image image_text (string text, int font_size, Color color); @@ -1829,6 +2001,9 @@ namespace Raylib { [CCode (cname = "ImageBlurGaussian")] public static void image_blur_gaussian (Image? image, int blur_size); + [CCode (cname = "ImageKernelConvolution")] + public static void image_kernel_convolution (Image? image, float[] kernel); + [CCode (cname = "ImageResize")] public static void image_resize (Image? image, int width, int height); @@ -1836,7 +2011,8 @@ namespace Raylib { public static void image_resize_nearest_neighbour (Image? image, int width, int height); [CCode (cname = "ImageResizeCanvas")] - public static void image_resize_canvas (Image? image, int width, int height, int offset_x, int offset_y, Color fill); + public static void image_resize_canvas (Image? image, int width, int height, int offset_x, int offset_y, + Color fill); [CCode (cname = "ImageMipmaps")] public static void image_mipmaps (Image? image); @@ -1913,6 +2089,9 @@ namespace Raylib { [CCode (cname = "ImageDrawLineV")] public static void image_draw_line_vector (Image? image, Vector2 start, Vector2 end, Color color); + [CCode (cname = "ImageDrawLineEx")] + public static void image_draw_line_ext (Image? image, Vector2 start, Vector2 end, int thickness, Color color); + [CCode (cname = "ImageDrawCircle")] public static void image_draw_circle (Image? image, int x, int y, int radius, Color color); @@ -1929,7 +2108,7 @@ namespace Raylib { public static void image_draw_rectangle (Image? image, int x, int y, int width, int height, Color color); [CCode (cname = "ImageDrawRectangleV")] - public static void image_draw_rectanglev (Image? image, Vector2 position, Vector2 size, Color color); + public static void image_draw_rectangle_vector (Image? image, Vector2 position, Vector2 size, Color color); [CCode (cname = "ImageDrawRectangleRec")] public static void image_draw_rectangle_rectangle (Image? image, Rectangle rectangle, Color color); @@ -1937,14 +2116,32 @@ namespace Raylib { [CCode (cname = "ImageDrawRectangleLines")] public static void image_draw_rectangle_lines (Image? image, Rectangle rectangle, int thickness, Color color); + [CCode (cname = "ImageDrawTriangle")] + public static void image_draw_triangle (Image? image, Vector2 v1, Vector2 v2, Vector2 v3, Color color); + + [CCode (cname = "ImageDrawTriangleEx")] + public static void image_draw_triangle_ext (Image? image, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, + Color c3); + + [CCode (cname = "ImageDrawTriangleLines")] + public static void image_draw_triangle_lines (Image? image, Vector2 v1, Vector2 v2, Vector2 v3, Color color); + + [CCode (cname = "ImageDrawTriangleFan")] + public static void image_draw_triangle_fan (Image? image, Vector2[] points, Color color); + + [CCode (cname = "ImageDrawTriangleStrip")] + public static void image_draw_triangle_strip (Image? image, Vector2[] points, Color color); + [CCode (cname = "ImageDraw")] - public static void image_draw (Image? image, Image source, Rectangle source_rectangle, Rectangle destination_rectangle, Color tint); + public static void image_draw (Image? image, Image source, Rectangle source_rectangle, + Rectangle destination_rectangle, Color tint); [CCode (cname = "ImageDrawText")] public static void image_draw_text (Image? image, string text, int x, int y, int font_size, Color color); [CCode (cname = "ImageDrawTextEx")] - public static void image_draw_text_ext (Image? image, Font font, string text, Vector2 position, float font_size, float spacing, Color tint); + public static void image_draw_text_ext (Image? image, Font font, string text, Vector2 position, float font_size, + float spacing, Color tint); // Texture loading functions // NOTE: These functions require GPU access @@ -1960,14 +2157,14 @@ namespace Raylib { [CCode (cname = "LoadRenderTexture")] public static RenderTexture2D load_render_texture (int width, int height); - [CCode (cname = "IsTextureReady")] - public static bool is_texture_ready (Texture2D texture); + [CCode (cname = "IsTextureValid")] + public static bool is_texture_valid (Texture2D texture); [CCode (cname = "UnloadTexture")] public static void unload_texture (Texture2D texture); - [CCode (cname = "IsRenderTextureReady")] - public static bool is_render_texture_ready (RenderTexture2D target); + [CCode (cname = "IsRenderTextureValid")] + public static bool is_render_texture_valid (RenderTexture2D target); [CCode (cname = "UnloadRenderTexture")] public static void unload_render_texture (RenderTexture2D target); @@ -1978,7 +2175,6 @@ namespace Raylib { [CCode (cname = "UpdateTextureRec")] public static void update_texture_rectangle (Texture2D texture, Rectangle rectangle, void* pixels); - // Texture configuration functions [CCode (cname = "GenTextureMipmaps")] public static void generate_texture_mipmaps (Texture2D? texture); @@ -2004,13 +2200,17 @@ namespace Raylib { public static void draw_texture_rectangle (Texture2D texture, Rectangle source, Vector2 position, Color tint); [CCode (cname = "DrawTexturePro")] - public static void draw_texture_pro (Texture2D texture, Rectangle source, Rectangle destination, Vector2 origin, float rotation, Color tint); + public static void draw_texture_pro (Texture2D texture, Rectangle source, Rectangle destination, Vector2 origin, + float rotation, Color tint); [CCode (cname = "DrawTextureNPatch")] - public static void draw_texture_npatch (Texture2D texture, NPatchInfo info, Rectangle destination, Vector2 origin, float rotation, Color tint); - + public static void draw_texture_npatch (Texture2D texture, NPatchInfo info, Rectangle destination, Vector2 origin, + float rotation, Color tint); // Color/pixel related functions + [CCode (cname = "ColorIsEqual")] + public static bool color_is_equal (Color col1, Color col2); + [CCode (cname = "Fade")] public static Color fade (Color color, float alpha); @@ -2044,6 +2244,9 @@ namespace Raylib { [CCode (cname = "ColorAlphaBlend")] public static Color color_alpha_blend (Color destination, Color source, Color tint); + [CCode (cname = "ColorLerp")] + public static Color color_lerp (Color color1, Color color2, float factor); + [CCode (cname = "GetColor")] public static Color get_color (uint hex); @@ -2056,9 +2259,9 @@ namespace Raylib { [CCode (cname = "GetPixelDataSize")] public static int get_pixel_data_size (int width, int height, int format); - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Font Loading and Text Drawing Functions (Module: text) - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Font loading/unloading functions [CCode (cname = "GetFontDefault")] @@ -2076,14 +2279,15 @@ namespace Raylib { [CCode (cname = "LoadFontFromMemory")] public static Font load_font_from_memory (string file_type, uchar file_data, int font_size, int[] code_points); - [CCode (cname = "IsFontReady")] - public static bool is_font_ready (Font font); + [CCode (cname = "IsFontValid")] + public static bool is_font_valid (Font font); [CCode (cname = "LoadFontData")] - public static GlyphInfo? load_font_data (uchar[] file_data, int font_size, int[] code_points, FontType type); + public static GlyphInfo ? load_font_data (uchar[] file_data, int font_size, int[] code_points, FontType type); [CCode (cname = "GenImageFontAtlas")] - public static Image generate_image_font_atlas (GlyphInfo* characters, unowned Rectangle[] glyph_rectangles, int font_size, int padding, int pack_method); + public static Image generate_image_font_atlas (GlyphInfo* characters, Rectangle[] glyph_rectangles, int font_size, + int padding, int pack_method); [CCode (cname = "UnloadFontData")] public static void unload_font_data (GlyphInfo[] glyphs); @@ -2102,16 +2306,19 @@ namespace Raylib { public static void draw_text (string text, int x, int y, int font_size, Color color); [CCode (cname = "DrawTextEx")] - public static void draw_text_ext (Font font, string text, Vector2 position, float font_size, float spacing, Color tint); + public static void draw_text_ext (Font font, string text, Vector2 position, float font_size, float spacing, + Color tint); [CCode (cname = "DrawTextPro")] - public static void draw_text_pro (Font font, string text, Vector2 position, Vector2 origin, float rotation, float font_size, float spacing, Color tint); + public static void draw_text_pro (Font font, string text, Vector2 position, Vector2 origin, float rotation, + float font_size, float spacing, Color tint); [CCode (cname = "DrawTextCodepoint")] public static void draw_text_codepoint (Font font, int codepoint, Vector2 position, float font_size, Color tint); [CCode (cname = "DrawTextCodepoints")] - public static void draw_text_codepoints (Font font, int[] codepoints, Vector2 position, float font_size, float spacing, Color tint); + public static void draw_text_codepoints (Font font, int[] codepoints, Vector2 position, float font_size, + float spacing, Color tint); // Text font info functions [CCode (cname = "SetTextLineSpacing")] @@ -2162,6 +2369,12 @@ namespace Raylib { // Text strings management functions (no UTF-8 strings, only byte chars) // NOTE: Some strings allocate memory internally for returned strings, just be careful! + [CCode (cname = "LoadTextLines")] + public static string[] load_text_lines (string text); + + [CCode (cname = "UnloadTextLines")] + public static string[] unload_text_lines (string[] text); + [CCode (cname = "TextCopy")] public static int text_copy (out string destination, string source); @@ -2171,14 +2384,23 @@ namespace Raylib { [CCode (cname = "TextLength")] public static uint text_length (string text); - [CCode (cname = "TextFormat")] - public static string text_format (string text, ...); + [PrintfFormat, CCode (cname = "TextFormat", sentinel = "")] + public static unowned string text_format (string text, ...); [CCode (cname = "TextSubtext")] - public static string text_subtext (string text, int position, int length); + public static unowned string text_subtext (string text, int position, int length); + + [CCode (cname = "TextRemoveSpaces")] + public static string text_remove_spaces (string text); + + [CCode (cname = "GetTextBetween")] + public static string get_text_between (string text, string begin, string end); [CCode (cname = "TextReplace")] - public static string text_replace (out string text, string replace, string by); + public static string text_replace (string text, string search, string replacement); + + [CCode (cname = "TextReplaceBetween")] + public static string text_replace_between (string text, string begin, string end, string replacement); [CCode (cname = "TextInsert")] public static string text_insert (string text, string insert, int position); @@ -2204,28 +2426,38 @@ namespace Raylib { [CCode (cname = "TextToPascal")] public static string text_to_pascal (string text); + [CCode (cname = "TextToSnake")] + public static string text_to_snake (string text); + + [CCode (cname = "TextToCamel")] + public static string text_to_camel (string text); + [CCode (cname = "TextToInteger")] public static int text_to_integer (string text); - //------------------------------------------------------------------------------------ + [CCode (cname = "TextToFloat")] + public static float text_to_float (string text); + + // ------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Basic geometric 3D shapes drawing functions [CCode (cname = "DrawLine3D")] - public static void draw_line_3D (Vector3 start, Vector3 end, Color color); // vala-lint=naming-convention + public static void draw_line_3d (Vector3 start, Vector3 end, Color color); [CCode (cname = "DrawPoint3D")] - public static void draw_point_3D (Vector3 position, Color color); // vala-lint=naming-convention + public static void draw_point_3d (Vector3 position, Color color); [CCode (cname = "DrawCircle3D")] - public static void draw_circle_3D (Vector3 center, float radius, Vector3 rotation_axis, float rotation_angle, Color color); // vala-lint=naming-convention + public static void draw_circle_3d (Vector3 center, float radius, Vector3 rotation_axis, float rotation_angle, + Color color); [CCode (cname = "DrawTriangle3D")] - public static void draw_triangle_3D (Vector3 vector1, Vector3 vector2, Vector3 vector3, Color color); // vala-lint=naming-convention + public static void draw_triangle_3d (Vector3 vector1, Vector3 vector2, Vector3 vector3, Color color); [CCode (cname = "DrawTriangleStrip3D")] - public static void draw_triangle_strip_3D (Vector3[] points, Color color); // vala-lint=naming-convention + public static void draw_triangle_strip_3d (Vector3[] points, Color color); [CCode (cname = "DrawCube")] public static void draw_cube (Vector3 position, float width, float height, float length, Color color); @@ -2249,22 +2481,27 @@ namespace Raylib { public static void draw_sphere_wires (Vector3 center_position, float radius, int rings, int slices, Color color); [CCode (cname = "DrawCylinder")] - public static void draw_cylinder (Vector3 position, float radius_top, float radius_bottom, float height, int slices, Color color); + public static void draw_cylinder (Vector3 position, float radius_top, float radius_bottom, float height, int slices, + Color color); [CCode (cname = "DrawCylinderEx")] - public static void draw_cylinder_ext (Vector3 start, Vector3 end, float start_radius, float end_radius, int sides, Color color); + public static void draw_cylinder_ext (Vector3 start, Vector3 end, float start_radius, float end_radius, int sides, + Color color); [CCode (cname = "DrawCylinderWires")] - public static void draw_cylinder_wires (Vector3 position, float radius_top, float radius_bottom, float height, int slices, Color color); + public static void draw_cylinder_wires (Vector3 position, float radius_top, float radius_bottom, float height, + int slices, Color color); [CCode (cname = "DrawCylinderWiresEx")] - public static void draw_cylinder_wires_ext (Vector3 start, Vector3 end, float start_adius, float end_radius, int sides, Color color); + public static void draw_cylinder_wires_ext (Vector3 start, Vector3 end, float start_adius, float end_radius, + int sides, Color color); [CCode (cname = "DrawCapsule")] public static void draw_capsule (Vector3 start, Vector3 end, float radius, int slices, int rings, Color color); [CCode (cname = "DrawCapsuleWires")] - public static void draw_capsule_wires (Vector3 start, Vector3 end, float radius, int slices, int rings, Color color); + public static void draw_capsule_wires (Vector3 start, Vector3 end, float radius, int slices, int rings, + Color color); [CCode (cname = "DrawPlane")] public static void draw_plane (Vector3 center, Vector2 size, Color color); @@ -2275,9 +2512,9 @@ namespace Raylib { [CCode (cname = "DrawGrid")] public static void draw_grid (int slices, float spacing); - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Model 3d Loading and Drawing Functions (Module: models) - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Model management functions [CCode (cname = "LoadModel")] @@ -2286,12 +2523,12 @@ namespace Raylib { [CCode (cname = "LoadModelFromMesh")] public static Model load_model_from_mesh (Mesh mesh); + [CCode (cname = "IsModelValid")] + public static bool is_model_valid (Model model); + [CCode (cname = "UnloadModel")] public static void unload_model (Model model); - [CCode (cname = "UnloadModelKeepMeshes")] - public static void unload_model_keep_meshes (Model model); - [CCode (cname = "GetModelBoundingBox")] public static BoundingBox get_model_bounding_box (Model model); @@ -2300,13 +2537,22 @@ namespace Raylib { public static void draw_model (Model model, Vector3 position, float scale, Color tint); [CCode (cname = "DrawModelEx")] - public static void draw_model_ext (Model model, Vector3 position, Vector3 rotation_axis, float rotation_angle, Vector3 scale, Color tint); + public static void draw_model_ext (Model model, Vector3 position, Vector3 rotation_axis, float rotation_angle, + Vector3 scale, Color tint); [CCode (cname = "DrawModelWires")] public static void draw_model_wires (Model model, Vector3 position, float scale, Color tint); [CCode (cname = "DrawModelWiresEx")] - public static void draw_model_wires_ext (Model model, Vector3 position, Vector3 rotation_axis, float rotation_angle, Vector3 scale, Color tint); + public static void draw_model_wires_ext (Model model, Vector3 position, Vector3 rotation_axis, float rotation_angle, + Vector3 scale, Color tint); + + [CCode (cname = "DrawModelPoints")] + public static void draw_model_points (Model model, Vector3 position, float scale, Color tint); + + [CCode (cname = "DrawModelPointsEx")] + public static void draw_model_points_ext (Model model, Vector3 position, Vector3 rotation_axis, + float rotation_angle, Vector3 scale, Color tint); [CCode (cname = "DrawBoundingBox")] public static void draw_bounding_box (BoundingBox box, Color color); @@ -2315,10 +2561,12 @@ namespace Raylib { public static void draw_billboard (Camera camera, Texture2D texture, Vector3 position, float size, Color tint); [CCode (cname = "DrawBillboardRec")] - public static void draw_billboard_rectangle (Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); + public static void draw_billboard_rectangle (Camera camera, Texture2D texture, Rectangle source, Vector3 position, + Vector2 size, Color tint); [CCode (cname = "DrawBillboardPro")] - public static void draw_billboard_pro (Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); + public static void draw_billboard_pro (Camera camera, Texture2D texture, Rectangle source, Vector3 position, + Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Mesh management functions [CCode (cname = "UploadMesh")] @@ -2336,15 +2584,18 @@ namespace Raylib { [CCode (cname = "DrawMeshInstanced")] public static void draw_mesh_instanced (Mesh mesh, Material material, Matrix[] transforms); - [CCode (cname = "ExportMesh")] - public static bool export_mesh (Mesh mesh, string filename); - [CCode (cname = "GetMeshBoundingBox")] public static BoundingBox get_mesh_bounding_box (Mesh mesh); [CCode (cname = "generate_mesh_Tangents")] public static void generate_mesh_tangents (Mesh? mesh); + [CCode (cname = "ExportMesh")] + public static bool export_mesh (Mesh mesh, string filename); + + [CCode (cname = "ExportMeshAsCode")] + public static bool export_mesh_as_code (Mesh mesh, string filename); + // Mesh generation functions [CCode (cname = "GenMeshPoly")] public static Mesh generate_mesh_poly (int sides, float radius); @@ -2381,13 +2632,13 @@ namespace Raylib { // Material loading/unloading functions [CCode (cname = "LoadMaterials")] - public static Material[] load_materials (string filename, out int material_count); + public static Material[] load_materials (string filename); [CCode (cname = "LoadMaterialDefault")] public static Material load_material_default (); - [CCode (cname = "IsMaterialReady")] - public static bool is_material_ready (Material material); + [CCode (cname = "IsMaterialValid")] + public static bool is_material_valid (Material material); [CCode (cname = "UnloadMaterial")] public static void unload_material (Material material); @@ -2400,13 +2651,15 @@ namespace Raylib { // Model animations loading/unloading functions [CCode (cname = "LoadModelAnimations")] - public static ModelAnimation? load_model_animations (string filename, out int animation_count); + public static ModelAnimation ? load_model_animations (string filename, out int animation_count); [CCode (cname = "UpdateModelAnimation")] - public static void update_model_animations (Model model, ModelAnimation animation, int frame); + public static void update_model_animation (Model model, ModelAnimation animation, int frame); - [CCode (cname = "UnloadModelAnimation")] - public static void unload_model_animation (ModelAnimation animation); + [CCode (cname = "UpdateModelAnimationEx")] + public static void update_model_animation_ext (Model model, ModelAnimation anim_a, float frame_a, + ModelAnimation anim_b, float frame_b, + float blend); [CCode (cname = "UnloadModelAnimations")] public static void unload_model_animations (ModelAnimation[] animations); @@ -2437,11 +2690,12 @@ namespace Raylib { public static RayCollision get_ray_collision_triangle (Ray ray, Vector3 point1, Vector3 point2, Vector3 point3); [CCode (cname = "GetRayCollisionQuad")] - public static RayCollision get_ray_collision_quad (Ray ray, Vector3 point1, Vector3 point2, Vector3 point3, Vector3 point4); + public static RayCollision get_ray_collision_quad (Ray ray, Vector3 point1, Vector3 point2, Vector3 point3, + Vector3 point4); - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ [CCode (cname = "AudioCallback")] public delegate void AudioCallback (void* buffer_data, uint frames); @@ -2468,8 +2722,8 @@ namespace Raylib { [CCode (cname = "LoadWaveFromMemory")] public static Wave load_wave_from_memory (string file_type, uchar[] file_data); - [CCode (cname = "IsWaveReady")] - public static bool is_wave_ready (Wave wave); + [CCode (cname = "IsWaveValid")] + public static bool is_wave_valid (Wave wave); [CCode (cname = "LoadSound")] public static Sound load_sound (string filename); @@ -2480,8 +2734,8 @@ namespace Raylib { [CCode (cname = "LoadSoundAlias")] public static Sound load_sound_alias (Sound alias); - [CCode (cname = "IsSoundReady")] - public static bool is_sound_ready (Sound sound); + [CCode (cname = "IsSoundValid")] + public static bool is_sound_valid (Sound sound); [CCode (cname = "UpdateSound")] public static void update_sound (Sound sound, void* data, int sample_ount); @@ -2548,8 +2802,8 @@ namespace Raylib { [CCode (cname = "LoadMusicStreamFromMemory")] public static Music load_music_stream_from_memory (string file_type, uchar[] data); - [CCode (cname = "IsMusicReady")] - public static bool is_music_ready (Music music); + [CCode (cname = "IsMusicValid")] + public static bool is_music_valid (Music music); [CCode (cname = "UnloadMusicStream")] public static void unload_music_stream (Music music); @@ -2594,8 +2848,8 @@ namespace Raylib { [CCode (cname = "LoadAudioStream")] public static AudioStream load_audio_stream (uint sample_rate, uint sample_size, uint channels); - [CCode (cname = "IsAudioStreamReady")] - public static bool is_audio_stream_ready (AudioStream stream); + [CCode (cname = "IsAudioStreamValid")] + public static bool is_audio_stream_valid (AudioStream stream); [CCode (cname = "UnloadAudioStream")] public static void unload_audio_stream (AudioStream stream); @@ -2636,14 +2890,12 @@ namespace Raylib { [CCode (cname = "SetAudioStreamCallback")] public static void set_audio_stream_callback (AudioStream stream, AudioCallback callback); - [CCode (cname = "AttachAudioStreamProcessor")] public static void attach_audio_stream_processor (AudioStream stream, AudioCallback processor); [CCode (cname = "DetachAudioStreamProcessor")] public static void detach_audio_stream_processor (AudioStream stream, AudioCallback processor); - [CCode (cname = "AttachAudioMixedProcessor")] public static void attach_audio_mixed_processor (AudioCallback processor); diff --git a/vapi/raymath.vapi b/vapi/raymath.vapi new file mode 100644 index 0000000..001252b --- /dev/null +++ b/vapi/raymath.vapi @@ -0,0 +1,645 @@ +[CCode (cprefix = "", cheader_filename = "raymath.h")] +namespace Raymath { + //---------------------------------------------------------------------------------- + // Defines and Macros + //---------------------------------------------------------------------------------- + [CCode (cname = "PI")] + public const float PI; + + [CCode (cname = "EPSILON")] + public const float EPSILON; + + [CCode (cname = "DEG2RAD")] + public const float DEG2RAD; + + [CCode (cname = "RAD2DEG")] + public const float RAD2DEG; + + [CCode (cname = "MatrixToFloat")] + public static float matrix_to_float (Matrix mat); + + [CCode (cname = "Vector3ToFloat")] + public static float vector3_to_float (Vector3 vec); + + //---------------------------------------------------------------------------------- + // Types and Structures Definition + //---------------------------------------------------------------------------------- + + [SimpleType] + [CCode (cname = "float3", has_type_id = false)] + public struct Float3 { + public float v[3]; + } + + [SimpleType] + [CCode (cname = "float16", has_type_id = false)] + public struct Float16 { + public float v[16]; + } + + //---------------------------------------------------------------------------------- + // Module Functions Definition - Utils math + //---------------------------------------------------------------------------------- + + [CCode (cname = "Clamp")] + public static float clamp (float val, float min, float max); + + [CCode (cname = "Lerp")] + public static float lerp (float start, float end, float amount); + + [CCode (cname = "Normalize")] + public static float normalize (float val, float start, float end); + + [CCode (cname = "Remap")] + public static float remap (float val, float input_start, float input_end, float output_start, float output_end); + + [CCode (cname = "Wrap")] + public static float wrap (float val, float min, float max); + + [CCode (cname = "FloatEquals")] + public static int float_equals (float x, float y); + + //---------------------------------------------------------------------------------- + // Module Functions Definition - Vector2 math + //---------------------------------------------------------------------------------- + + [SimpleType] + [CCode (cname = "Vector2", has_type_id = false)] + public struct Vector2 { + public float x; + public float y; + + public float length { + [CCode (cname = "Vector2Length")] get; + } + + public float length_squared { + [CCode (cname = "Vector2LengthSqr")] get; + } + + public Vector2 negated { + [CCode (cname = "Vector2Negate")] get; + } + + public Vector2 normalized { + [CCode (cname = "Vector2Normalize")] get; + } + + public Vector2 inverted { + [CCode (cname = "Vector2Invert")] get; + } + + [CCode (cname = "Vector2Zero")] + public Vector2 (); + + [CCode (cname = "Vector2Zero")] + public Vector2.zero (); + + [CCode (cname = "Vector2One")] + public Vector2.one (); + + public Vector2.unit_x () { x = 1; y = 0; } + + public Vector2.unit_y () { x = 0; y = 1; } + + [CCode (cname = "Vector2Add")] + public Vector2 add (Vector2 v); + + [CCode (cname = "Vector2AddValue")] + public Vector2 add_value (float add); + + [CCode (cname = "Vector2Subtract")] + public Vector2 subtract (Vector2 v); + + [CCode (cname = "Vector2SubtractValue")] + public Vector2 subtract_value (float sub); + + [CCode (cname = "Vector2DotProduct")] + public float dot (Vector2 v); + + [CCode (cname = "Vector2CrossProduct")] + public float cross (Vector2 v); + + [CCode (cname = "Vector2Distance")] + public Vector2 distance (Vector2 v); + + [CCode (cname = "Vector2DistanceSqr")] + public Vector2 distance_squared (Vector2 v); + + [CCode (cname = "Vector2Angle")] + public float angle (Vector2 v); + + [CCode (cname = "Vector2Scale")] + public Vector2 scale (float scalar); + + [CCode (cname = "Vector2Multiply")] + public Vector2 multiply (Vector2 v); + + [CCode (cname = "Vector2Divide")] + public Vector2 divide (Vector2 v); + + [CCode (cname = "Vector2Transform")] + public Vector2 transform (Matrix mat); + + [CCode (cname = "Vector2Reflect")] + public Vector2 reflect (Vector2 normal); + + [CCode (cname = "Vector2Min")] + public Vector2 minimum (Vector2 v); + + [CCode (cname = "Vector2Max")] + public Vector2 maximum (Vector2 v); + + [CCode (cname = "Vector2Rotate")] + public Vector2 rotate (float angle); + + [CCode (cname = "Vector2MoveTowards")] + public Vector2 move_towards (Vector2 v, float max_distance); + + [CCode (cname = "Vector2Clamp")] + public Vector2 clamp (Vector2 min, Vector2 max); + + [CCode (cname = "Vector2ClampValue")] + public Vector2 clamp_magnitude (float min, float max); + + [CCode (cname = "Vector2Equals")] + public bool equal_to (Vector2 v); + + public string to_string () { + return "{%f, %f}".printf (x, y); + } + + [CCode (cname = "Vector2Lerp")] + public static Vector2 lerp (Vector2 v1, Vector2 v2, float t); + + [CCode (cname = "Vector2LineAngle")] + public static float line_angle (Vector2 start, Vector2 end); + + [CCode (cname = "Vector2Refract")] + public static Vector2 refract (Vector2 direction, Vector2 normal, float ratio); + } + + //---------------------------------------------------------------------------------- + // Module Functions Definition - Vector3 math + //---------------------------------------------------------------------------------- + + [SimpleType] + [CCode (cname = "Vector3", has_type_id = false)] + public struct Vector3 { + public float x; + public float y; + public float z; + + public float length { + [CCode (cname = "Vector3Length")] get; + } + + public float length_squared { + [CCode (cname = "Vector3LengthSqr")] get; + } + + public Vector3 negated { + [CCode (cname = "Vector3Negate")] get; + } + + public Vector3 normalized { + [CCode (cname = "Vector3Normalize")] get; + } + + public Vector3 inverted { + [CCode (cname = "Vector3Invert")] get; + } + + [CCode (cname = "Vector3Zero")] + public Vector3 (); + + [CCode (cname = "Vector3Zero")] + public Vector3.zero (); + + [CCode (cname = "Vector3One")] + public Vector3.one (); + + public Vector3.unit_x () { x = 1; y = 0; z = 0; } + + public Vector3.unit_y () { x = 0; y = 1; z = 0; } + + public Vector3.unit_z () { x = 0; y = 0; z = 1; } + + [CCode (cname = "Vector3Add")] + public Vector3 add (Vector3 v); + + [CCode (cname = "Vector3AddValue")] + public Vector3 add_value (float add); + + [CCode (cname = "Vector3Subtract")] + public Vector3 subtract (Vector3 v); + + [CCode (cname = "Vector3SubtractValue")] + public Vector3 subtract_value (float sub); + + [CCode (cname = "Vector3Scale")] + public Vector3 scale (float scalar); + + [CCode (cname = "Vector3Multiply")] + public Vector3 multiply (Vector3 v); + + [CCode (cname = "Vector3CrossProduct")] + public Vector3 cross (Vector3 v2); + + [CCode (cname = "Vector3Perpendicular")] + public Vector3 perpendicular (Vector3 v2); + + [CCode (cname = "Vector3DotProduct")] + public float dot (Vector3 v); + + [CCode (cname = "Vector3Distance")] + public Vector3 distance (Vector3 v); + + [CCode (cname = "Vector3DistanceSqr")] + public Vector3 distance_squared (Vector3 v); + + [CCode (cname = "Vector3Angle")] + public float angle (Vector3 v); + + [CCode (cname = "Vector3Divide")] + public Vector3 divide (Vector3 v); + + [CCode (cname = "Vector3Project")] + public Vector3 project (Vector3 v); + + [CCode (cname = "Vector3Reject")] + public Vector3 reject (Vector3 v); + + [CCode (cname = "Vector3Transform")] + public Vector3 transform (Matrix m); + + [CCode (cname = "Vector3RotateByQuaternion")] + public Vector3 rotate_by_quaternion (Quaternion q); + + [CCode (cname = "Vector3RotateByAxisAngle")] + public Vector3 rotate_by_axis_angle (Vector3 axis, float angle); + + [CCode (cname = "Vector3MoveTowards")] + public Vector3 move_towards (Vector3 target, float max_distance); + + [CCode (cname = "Vector3Reflect")] + public Vector3 reflect (Vector3 normal); + + [CCode (cname = "Vector3Min")] + public Vector3 minimum (Vector3 v); + + [CCode (cname = "Vector2Max")] + public Vector3 maximum (Vector3 v); + + [CCode (cname = "Vector3ToFloatV")] + public Float3 to_float3 (); + + [CCode (cname = "Vector3Clamp")] + public Vector3 clamp (Vector3 min, Vector3 max); + + [CCode (cname = "Vector3ClampValue")] + public Vector3 clamp_magnitude (float min, float max); + + [CCode (cname = "Vector3Equals")] + public bool equal_to (Vector3 v); + + public string to_string () { + return "{%f, %f, %f}".printf (x, y, z); + } + + [CCode (cname = "Vector3OrthoNormalize")] + public static void ortho_normalize (ref Vector3 v1, ref Vector3 v2); + + [CCode (cname = "Vector3CubicHermite")] + public static Vector3 cubic_hermite (Vector3 v1, Vector3 tangent1, Vector3 v2, Vector3 tangent2, float t); + + [CCode (cname = "Vector3Lerp")] + public static Vector3 lerp (Vector3 v1, Vector3 v2, float t); + + [CCode (cname = "Vector3Barycenter")] + public static Vector3 barycenter (Vector3 p, Vector3 a, Vector3 b, Vector3 c); + + [CCode (cname = "Vector3Unproject")] + public static Vector3 unproject (Vector3 source, Matrix projection, Matrix view); + + [CCode (cname = "Vector3Refract")] + public static Vector3 refract (Vector3 direction, Vector3 normal, float ratio); + } + + //---------------------------------------------------------------------------------- + // Module Functions Definition - Vector4 math + //---------------------------------------------------------------------------------- + + [SimpleType] + [CCode (cname = "Vector4", has_type_id = false)] + public struct Vector4 { + public float x; + public float y; + public float z; + public float w; + + public float length { + [CCode (cname = "Vector4Length")] get; + } + + public float length_squared { + [CCode (cname = "Vector4LengthSqr")] get; + } + + public Vector4 negated { + [CCode (cname = "Vector4Negate")] get; + } + + public Vector4 normalized { + [CCode (cname = "Vector4Normalize")] get; + } + + public Vector4 inverted { + [CCode (cname = "Vector4Invert")] get; + } + + [CCode (cname = "Vector4Zero")] + public Vector4 (); + + [CCode (cname = "Vector4Zero")] + public Vector4.zero (); + + [CCode (cname = "Vector4One")] + public Vector4.one (); + + public Vector4.unit_x () { x = 1; y = 0; z = 0; w = 0; } + + public Vector4.unit_y () { x = 0; y = 1; z = 0; w = 0; } + + public Vector4.unit_z () { x = 0; y = 0; z = 1; w = 0; } + + public Vector4.unit_w () { x = 0; y = 0; z = 0; w = 1; } + + [CCode (cname = "Vector4Add")] + public Vector4 add (Vector4 v); + + [CCode (cname = "Vector4AddValue")] + public Vector4 add_value (float add); + + [CCode (cname = "Vector4Subtract")] + public Vector4 subtract (Vector3 v); + + [CCode (cname = "Vector4SubtractValue")] + public Vector4 subtract_value (float sub); + + [CCode (cname = "Vector4DotProduct")] + public float dot (Vector4 v); + + [CCode (cname = "Vector4Distance")] + public Vector4 distance (Vector4 v); + + [CCode (cname = "Vector4DistanceSqr")] + public Vector4 distance_squared (Vector4 v); + + [CCode (cname = "Vector4Scale")] + public Vector4 scale (float scalar); + + [CCode (cname = "Vector4Multiply")] + public Vector4 multiply (Vector4 v); + + [CCode (cname = "Vector4Divide")] + public Vector4 divide (Vector4 v); + + [CCode (cname = "Vector4Min")] + public Vector4 minimum (Vector4 v); + + [CCode (cname = "Vector4Max")] + public Vector4 maximum (Vector4 v); + + [CCode (cname = "Vector4MoveTowards")] + public Vector4 move_towards (Vector4 target, float max_distance); + + [CCode (cname = "Vector4Equals")] + public bool equal_to (Vector4 v); + + public string to_string () { + return "{%f, %f, %f, %f}".printf (x, y, z, w); + } + + [CCode (cname = "Vector4Lerp")] + public static Vector4 lerp (Vector4 v1, Vector4 v2, float t); + } + + //---------------------------------------------------------------------------------- + // Module Functions Definition - Matrix math + //---------------------------------------------------------------------------------- + + [SimpleType] + [CCode (cname = "Matrix", has_type_id = false)] + public struct Matrix { + // Row 1 + public float m0; + public float m4; + public float m8; + public float m12; + + // Row 2 + public float m1; + public float m5; + public float m9; + public float m13; + + // Row 3 + public float m2; + public float m6; + public float m10; + public float m14; + + // Row 4 + public float m3; + public float m7; + public float m11; + public float m15; + + public float determinant { + [CCode (cname = "MatrixDeterminant")] get; + } + + public float trace { + [CCode (cname = "MatrixTrace")] get; + } + + public float transposed { + [CCode (cname = "MatrixTranspose")] get; + } + + public float inverted { + [CCode (cname = "MatrixInvert")] get; + } + + [CCode (cname = "MatrixIdentity")] + public Matrix.identity (); + + [CCode (cname = "MatrixTranslate")] + public Matrix.translation (float x, float y, float z); + + [CCode (cname = "MatrixRotate")] + public Matrix.rotation (Vector3 axis, float angle); + + [CCode (cname = "MatrixRotateX")] + public Matrix.rotation_x (float angle); + + [CCode (cname = "MatrixRotateY")] + public Matrix.rotation_y (float angle); + + [CCode (cname = "MatrixRotateZ")] + public Matrix.rotation_z (float angle); + + [CCode (cname = "MatrixRotateXYZ")] + public Matrix.rotation_xyz (Vector3 angle); + + [CCode (cname = "MatrixRotateZYX")] + public Matrix.rotation_zxy (Vector3 angle); + + [CCode (cname = "MatrixFrustum")] + public Matrix.frustum (double left, double right, double bottom, double top, double near_plane, + double far_plane); + + [CCode (cname = "MatrixPerspective")] + public Matrix.perspective (double fov, double aspec, double near_plane, double far_plane); + + [CCode (cname = "MatrixOrtho")] + public Matrix.orthographic (double left, double right, double bottom, double top, double near_plane, + double far_plane); + + [CCode (cname = "MatrixLookAt")] + public Matrix.look_at (Vector3 eye, Vector3 target, Vector3 up); + + [CCode (cname = "MatrixScale")] + public Matrix.scale (float x, float y, float z); + + [CCode (cname = "MatrixCompose")] + public Matrix.compose (Vector3 translation, Quaternion rotation, Vector3 scale); + + [CCode (cname = "MatrixAdd")] + public Matrix add (Matrix m); + + [CCode (cname = "MatrixSubtract")] + public Matrix subtract (Matrix m); + + [CCode (cname = "MatrixMultiply")] + public Matrix multiply (Matrix m); + + [CCode (cname = "MatrixMultiplyValue")] + public Matrix multiply_value (float val); + + [CCode (cname = "MatrixToFloatV")] + public Float16 to_float16 (); + + [CCode (cname = "MatrixDecompose")] + public Matrix decompose (out Vector3 translation, out Quaternion rotation, out Vector3 scale); + + public string to_string () { + return ("{%f, %f, %f, %f}\n" + + "{%f, %f, %f, %f}\n" + + "{%f, %f, %f, %f}\n" + + "{%f, %f, %f, %f}").printf (m0, m4, m8, m12, + m1, m5, m9, m13, + m2, m6, m10, m14, + m3, m7, m11, m15); + } + } + + //---------------------------------------------------------------------------------- + // Module Functions Definition - Quaternion math + //---------------------------------------------------------------------------------- + + [SimpleType] + [CCode (cname = "Quaternion", has_type_id = false)] + public struct Quaternion { + public float x; + public float y; + public float z; + public float w; + + public float length { + [CCode (cname = "QuaternionLength")] get; + } + + public Quaternion normalized { + [CCode (cname = "QuaternionNormalize")] get; + } + + public Quaternion inverted { + [CCode (cname = "QuaternionInvert")] get; + } + + public Quaternion.zero () { x = 0; y = 0; z = 0; w = 0; } + + public Quaternion.one () { x = 1; y = 1; z = 1; w = 1; } + + [CCode (cname = "QuaternionIdentity")] + public Quaternion.identity (); + + [CCode (cname = "QuaternionFromVector3ToVector3")] + public Quaternion.from_vector3_to_vector3 (Vector3 from, Vector3 to); + + [CCode (cname = "QuaternionFromMatrix")] + public Quaternion.from_matrix (Matrix mat); + + [CCode (cname = "QuaternionFromAxisAngle")] + public Quaternion.from_axis_angle (Vector3 axis, float angle); + + [CCode (cname = "QuaternionFromEuler")] + public Quaternion.from_euler (float pitch, float yaw, float roll); + + [CCode (cname = "QuaternionAdd")] + public Quaternion add (Quaternion q); + + [CCode (cname = "QuaternionAddValue")] + public Quaternion add_value (float add); + + [CCode (cname = "QuaternionSubtract")] + public Quaternion subtract (Quaternion q); + + [CCode (cname = "QuaternionSubtractValue")] + public Quaternion subtract_value (float sub); + + [CCode (cname = "QuaternionMultiply")] + public Quaternion multiply (Quaternion q); + + [CCode (cname = "QuaternionScale")] + public Quaternion scale (float scalar); + + [CCode (cname = "QuaternionDivide")] + public Quaternion divide (Quaternion q); + + [CCode (cname = "QuaternionToMatrix")] + public Matrix to_matrix (); + + [CCode (cname = "QuaternionToAxisAngle")] + public void to_axis_angle (out Vector3 axis, out float angle); + + [CCode (cname = "QuaternionToEuler")] + public Vector3 to_euler (); + + [CCode (cname = "QuaternionTransform")] + public Quaternion transform (Matrix mat); + + [CCode (cname = "QuaternionEquals")] + public int equal_to (Quaternion q); + + public string to_string () { + return "{%f, %f, %f, %f}".printf (x, y, z, w); + } + + [CCode (cname = "QuaternionLerp")] + public static Quaternion lerp (Quaternion q1, Quaternion q2, float amount); + + [CCode (cname = "QuaternionNLerp")] + public static Quaternion nlerp (Quaternion q1, Quaternion q2, float amount); + + [CCode (cname = "QuaternionSLerp")] + public static Quaternion slerp (Quaternion q1, Quaternion q2, float amount); + + [CCode (cname = "QuaternionCubicHermiteSpline")] + public static Quaternion cubic_hermite_spline (Quaternion q1, Quaternion tangent1, Quaternion q2, + Quaternion angent2, float t); + } +} + diff --git a/vapi/rini.vapi b/vapi/rini.vapi index dfdcb63..fd60b93 100644 --- a/vapi/rini.vapi +++ b/vapi/rini.vapi @@ -1,12 +1,11 @@ -[Version (experimental = true)] [CCode (cprefix = "", cheader_filename = "rini.h")] namespace Rini { [CCode (cname = "RINI_VERSION")] public const string VERSION; - //---------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------- // Defines and Macros - //---------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------- [CCode (cname = "RINI_MAX_LINE_SIZE")] public const int MAX_LINE_SIZE; @@ -34,59 +33,69 @@ namespace Rini { [CCode (cname = "RINI_LINE_SECTION_DELIMITER")] public const char LINE_SECTION_DELIMITER; - - //---------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------- // Types and Structures Definition - //---------------------------------------------------------------------------------- - [CCode (cname = "rini_config_value")] - public struct ConfigValue { - public char key[MAX_KEY_SIZE]; // Config value key identifier - public char text[MAX_TEXT_SIZE]; // Config value text - public char desc[MAX_DESC_SIZE]; // Config value description + // ---------------------------------------------------------------------------------- + [CCode (cname = "rini_value")] + public struct RiniValue { + public char key[MAX_KEY_SIZE]; // Config value key identifier + public char text[MAX_TEXT_SIZE]; // Config value text + public char desc[MAX_DESC_SIZE]; // Config value description } - [CCode (cname = "rini_config")] - public struct RiniConfig { - public ConfigValue[] values; // Config values array - public uint count; // Config values count - public uint capacity; // Config values capacity + [CCode (cname = "rini_data")] + public struct RiniData { + public RiniValue[] values; // Config values array + public uint count; // Config values count + public uint capacity; // Config values capacity } - - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Functions declaration - //------------------------------------------------------------------------------------ - [CCode (cname = "rini_load_config")] - public static RiniConfig load_config (string filename); // Load config from file (*.ini) or create a new config object (pass NULL) + // ------------------------------------------------------------------------------------ + [CCode (cname = "rini_load")] + public static RiniData load (string filename); // Load config from file (*.ini) or create a new config object (pass NULL) - [CCode (cname = "rini_unload_config")] - public static void unload_config (RiniConfig config); // Unload config data from memory + [CCode (cname = "rini_load_from_memory")] + public static RiniData rini_load_from_memory (string text); // Load data from text buffer - [CCode (cname = "rini_save_config")] - public static void save_config (RiniConfig config, string filename, string header); // Save config to file, with custom header + [CCode (cname = "rini_save")] + public static void save (RiniData data, string file_name); // Save config to file, with custom header + [CCode (cname = "rini_save_to_memory", array_null_terminated = true)] + public static uint8[] save_to_memory (RiniData data); // Save data to text buffer ('\0' EOL) - [CCode (cname = "rini_get_config_value")] - public static int get_config_value (RiniConfig config, string key); // Get config value int for provided key, returns -1 if not found + [CCode (cname = "rini_unload")] + public static void unload (RiniData data); // Unload config data from memory - [CCode (cname = "rini_get_config_value_text")] - public static string get_config_value_text (RiniConfig config, string key); // Get config value text for provided key + [CCode (cname = "rini_get_value")] + public static int get_value (RiniData data, string key); // Get config value int for provided key, returns -1 if not found - [CCode (cname = "rini_get_config_value_description")] - public static string get_config_value_description (RiniConfig config, string key); // Get config value description for provided key + [CCode (cname = "rini_get_value_text")] + public static string get_value_text (RiniData data, string key); // Get config value text for provided key + [CCode (cname = "rini_get_value_description")] + public static string get_value_description (RiniData data, string key); // Get config value description for provided key - // Set config value int/text and description for existing key or create a new entry - // NOTE: When setting a text value, if id does not exist, a new entry is automatically created - [CCode (cname = "rini_set_config_value")] - public static int set_config_value (RiniConfig config, string key, int value, string description); + [CCode (cname = "rini_get_value_fallback")] + public static int get_value_fallback (RiniData data, string key, int fallback); // Get value for provided key with default value fallback if not found or not valid - [CCode (cname = "rini_set_config_value_text")] - public static int set_config_value_text (RiniConfig config, string key, string text, string description); + [CCode (cname = "rini_get_value_text_fallback")] + public static string get_value_text_fallback (RiniData data,string key, string fallback); // Get value text for provided key with fallback if not found or not valid + + [CCode (cname = "rini_set_comment_line")] + public static int set_comment_line (RiniData data, string comment); // Set comment line + + // Set value int/text and description for existing key or create a new entry + // NOTE: When setting a text value, if id does not exist, a new entry is automatically created + [CCode (cname = "rini_set_value")] + public static int set_value (RiniData data, string key, int value, string description); + [CCode (cname = "rini_set_value_text")] + public static int set_value_text (RiniData data, string key, string text, string description); - // Set config value description for existing key + // Set value description for existing key // WARNING: Key must exist to add description, if a description exists, it is updated - [CCode (cname = "rini_set_config_value_description")] - public static int set_config_value_description (RiniConfig config, string key, string description); + [CCode (cname = "rini_set_value_description")] + public static int set_config_value_description (RiniData config, string key, string description); } diff --git a/vapi/rlgl.vapi b/vapi/rlgl.vapi index 452dfae..9df229d 100644 --- a/vapi/rlgl.vapi +++ b/vapi/rlgl.vapi @@ -4,246 +4,252 @@ namespace Rlgl { [CCode (cname = "RLGL_VERSION")] public const string VERSION; - //---------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------- // Defines and Macros - //---------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------- [CCode (cname = "RL_DEFAULT_BATCH_BUFFER_ELEMENTS")] - public const int DEFAULT_BATCH_BUFFER_ELEMENTS; // Default internal render batch elements limits + public const int DEFAULT_BATCH_BUFFER_ELEMENTS; // Default internal render batch elements limits [CCode (cname = "RL_DEFAULT_BATCH_BUFFERS")] - public const int DEFAULT_BATCH_BUFFERS; // Default number of batch buffers (multi-buffering) + public const int DEFAULT_BATCH_BUFFERS; // Default number of batch buffers (multi-buffering) [CCode (cname = "RL_DEFAULT_BATCH_DRAWCALLS")] - public const int DEFAULT_BATCH_DRAWCALLS; // Default number of batch draw calls (by state changes: mode, texture) + public const int DEFAULT_BATCH_DRAWCALLS; // Default number of batch draw calls (by state changes: mode, texture) [CCode (cname = "RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS")] - public const int DEFAULT_BATCH_MAX_TEXTURE_UNITS; // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture()) + public const int DEFAULT_BATCH_MAX_TEXTURE_UNITS; // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture()) // Internal Matrix stack [CCode (cname = "RL_MAX_MATRIX_STACK_SIZE")] - public const int MAX_MATRIX_STACK_SIZE; // Maximum size of Matrix stack + public const int MAX_MATRIX_STACK_SIZE; // Maximum size of Matrix stack // Shader limits [CCode (cname = "RL_MAX_SHADER_LOCATIONS")] - public const int MAX_SHADER_LOCATIONS; // Maximum number of shader locations supported + public const int MAX_SHADER_LOCATIONS; // Maximum number of shader locations supported // Projection matrix culling [CCode (cname = "RL_CULL_DISTANCE_NEAR")] - public const int CULL_DISTANCE_NEAR; // Default near cull distance + public const int CULL_DISTANCE_NEAR; // Default near cull distance [CCode (cname = "RL_CULL_DISTANCE_FAR")] - public const int CULL_DISTANCE_FAR; // Default far cull distance + public const int CULL_DISTANCE_FAR; // Default far cull distance // Texture parameters (equivalent to OpenGL defines) [CCode (cname = "RL_TEXTURE_WRAP_S")] - public const int TEXTURE_WRAP_S; // GL_TEXTURE_WRAP_S + public const int TEXTURE_WRAP_S; // GL_TEXTURE_WRAP_S [CCode (cname = "RL_TEXTURE_WRAP_T")] - public const int TEXTURE_WRAP_T; // GL_TEXTURE_WRAP_T + public const int TEXTURE_WRAP_T; // GL_TEXTURE_WRAP_T [CCode (cname = "RL_TEXTURE_MAG_FILTER")] - public const int TEXTURE_MAG_FILTER; // GL_TEXTURE_MAG_FILTER + public const int TEXTURE_MAG_FILTER; // GL_TEXTURE_MAG_FILTER [CCode (cname = "RL_TEXTURE_MIN_FILTER")] - public const int TEXTURE_MIN_FILTER; // GL_TEXTURE_MIN_FILTER + public const int TEXTURE_MIN_FILTER; // GL_TEXTURE_MIN_FILTER [CCode (cname = "RL_TEXTURE_FILTER_NEAREST")] - public const int TEXTURE_FILTER_NEAREST; // GL_NEAREST + public const int TEXTURE_FILTER_NEAREST; // GL_NEAREST [CCode (cname = "RL_TEXTURE_FILTER_LINEAR")] - public const int TEXTURE_FILTER_LINEAR; // GL_LINEAR + public const int TEXTURE_FILTER_LINEAR; // GL_LINEAR [CCode (cname = "RL_TEXTURE_FILTER_MIP_NEAREST")] - public const int TEXTURE_FILTER_MIP_NEAREST; // GL_NEAREST_MIPMAP_NEAREST + public const int TEXTURE_FILTER_MIP_NEAREST; // GL_NEAREST_MIPMAP_NEAREST [CCode (cname = "RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR")] - public const int TEXTURE_FILTER_NEAREST_MIP_LINEAR; // GL_NEAREST_MIPMAP_LINEAR + public const int TEXTURE_FILTER_NEAREST_MIP_LINEAR; // GL_NEAREST_MIPMAP_LINEAR [CCode (cname = "RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST")] - public const int TEXTURE_FILTER_LINEAR_MIP_NEAREST; // GL_LINEAR_MIPMAP_NEAREST + public const int TEXTURE_FILTER_LINEAR_MIP_NEAREST; // GL_LINEAR_MIPMAP_NEAREST [CCode (cname = "RL_TEXTURE_FILTER_MIP_LINEAR")] - public const int TEXTURE_FILTER_MIP_LINEAR; // GL_LINEAR_MIPMAP_LINEAR + public const int TEXTURE_FILTER_MIP_LINEAR; // GL_LINEAR_MIPMAP_LINEAR [CCode (cname = "RL_TEXTURE_FILTER_ANISOTROPIC")] - public const int TEXTURE_FILTER_ANISOTROPIC; // Anisotropic filter (custom identifier) + public const int TEXTURE_FILTER_ANISOTROPIC; // Anisotropic filter (custom identifier) [CCode (cname = "RL_TEXTURE_MIPMAP_BIAS_RATIO")] - public const int TEXTURE_MIPMAP_BIAS_RATIO; // Texture mipmap bias, percentage ratio (custom identifier) + public const int TEXTURE_MIPMAP_BIAS_RATIO; // Texture mipmap bias, percentage ratio (custom identifier) [CCode (cname = "RL_TEXTURE_WRAP_REPEAT")] - public const int TEXTURE_WRAP_REPEAT; // GL_REPEAT + public const int TEXTURE_WRAP_REPEAT; // GL_REPEAT [CCode (cname = "RL_TEXTURE_WRAP_CLAMP")] - public const int TEXTURE_WRAP_CLAMP; // GL_CLAMP_TO_EDGE + public const int TEXTURE_WRAP_CLAMP; // GL_CLAMP_TO_EDGE [CCode (cname = "RL_TEXTURE_WRAP_MIRROR_REPEAT")] - public const int TEXTURE_WRAP_MIRROR_REPEAT; // GL_MIRRORED_REPEAT + public const int TEXTURE_WRAP_MIRROR_REPEAT; // GL_MIRRORED_REPEAT [CCode (cname = "RL_TEXTURE_WRAP_MIRROR_CLAMP")] - public const int TEXTURE_WRAP_MIRROR_CLAMP; // GL_MIRROR_CLAMP_EXT + public const int TEXTURE_WRAP_MIRROR_CLAMP; // GL_MIRROR_CLAMP_EXT // Matrix modes (equivalent to OpenGL) [CCode (cname = "RL_MODELVIEW")] - public const int MODELVIEW; // GL_MODELVIEW + public const int MODELVIEW; // GL_MODELVIEW [CCode (cname = "RL_PROJECTION")] - public const int PROJECTION; // GL_PROJECTION + public const int PROJECTION; // GL_PROJECTION [CCode (cname = "RL_TEXTURE")] - public const int TEXTURE; // GL_TEXTURE + public const int TEXTURE; // GL_TEXTURE // Primitive assembly draw modes [CCode (cname = "RL_LINES")] - public const int LINES; // GL_LINES + public const int LINES; // GL_LINES [CCode (cname = "RL_TRIANGLES")] - public const int TRIANGLES; // GL_TRIANGLES + public const int TRIANGLES; // GL_TRIANGLES [CCode (cname = "RL_QUADS")] - public const int QUADS; // GL_QUADS + public const int QUADS; // GL_QUADS // GL equivalent data types [CCode (cname = "RL_UNSIGNED_BYTE")] - public const int UNSIGNED_BYTE; // GL_UNSIGNED_BYTE + public const int UNSIGNED_BYTE; // GL_UNSIGNED_BYTE [CCode (cname = "RL_FLOAT")] - public const int FLOAT; // GL_FLOAT + public const int FLOAT; // GL_FLOAT // GL buffer usage hint [CCode (cname = "RL_STREAM_DRAW")] - public const int STREAM_DRAW; // GL_STREAM_DRAW + public const int STREAM_DRAW; // GL_STREAM_DRAW [CCode (cname = "RL_STREAM_READ")] - public const int STREAM_READ; // GL_STREAM_READ + public const int STREAM_READ; // GL_STREAM_READ [CCode (cname = "RL_STREAM_COPY")] - public const int STREAM_COPY; // GL_STREAM_COPY + public const int STREAM_COPY; // GL_STREAM_COPY [CCode (cname = "RL_STATIC_DRAW")] - public const int STATIC_DRAW; // GL_STATIC_DRAW + public const int STATIC_DRAW; // GL_STATIC_DRAW [CCode (cname = "RL_STATIC_READ")] - public const int STATIC_READ; // GL_STATIC_READ + public const int STATIC_READ; // GL_STATIC_READ [CCode (cname = "RL_STATIC_COPY")] - public const int STATIC_COPY; // GL_STATIC_COPY + public const int STATIC_COPY; // GL_STATIC_COPY [CCode (cname = "RL_DYNAMIC_DRAW")] - public const int DYNAMIC_DRAW; // GL_DYNAMIC_DRAW + public const int DYNAMIC_DRAW; // GL_DYNAMIC_DRAW [CCode (cname = "RL_DYNAMIC_READ")] - public const int DYNAMIC_READ; // GL_DYNAMIC_READ + public const int DYNAMIC_READ; // GL_DYNAMIC_READ [CCode (cname = "RL_DYNAMIC_COPY")] - public const int DYNAMIC_COPY; // GL_DYNAMIC_COPY + public const int DYNAMIC_COPY; // GL_DYNAMIC_COPY // GL Shader type [CCode (cname = "RL_FRAGMENT_SHADER")] - public const int FRAGMENT_SHADER; // GL_FRAGMENT_SHADER + public const int FRAGMENT_SHADER; // GL_FRAGMENT_SHADER [CCode (cname = "RL_VERTEX_SHADER")] - public const int VERTEX_SHADER; // GL_VERTEX_SHADER + public const int VERTEX_SHADER; // GL_VERTEX_SHADER [CCode (cname = "RL_COMPUTE_SHADER")] - public const int COMPUTE_SHADER; // GL_COMPUTE_SHADER + public const int COMPUTE_SHADER; // GL_COMPUTE_SHADER // GL blending factors [CCode (cname = "RL_ZERO")] - public const int ZERO; // GL_ZERO + public const int ZERO; // GL_ZERO [CCode (cname = "RL_ONE")] - public const int ONE; // GL_ONE + public const int ONE; // GL_ONE [CCode (cname = "RL_SRC_COLOR")] - public const int SRC_COLOR; // GL_SRC_COLOR + public const int SRC_COLOR; // GL_SRC_COLOR [CCode (cname = "RL_ONE_MINUS_SRC_COLOR")] - public const int ONE_MINUS_SRC_COLOR; // GL_ONE_MINUS_SRC_COLOR + public const int ONE_MINUS_SRC_COLOR; // GL_ONE_MINUS_SRC_COLOR [CCode (cname = "RL_SRC_ALPHA")] - public const int SRC_ALPHA; // GL_SRC_ALPHA + public const int SRC_ALPHA; // GL_SRC_ALPHA [CCode (cname = "RL_ONE_MINUS_SRC_ALPHA")] - public const int ONE_MINUS_SRC_ALPHA; // GL_ONE_MINUS_SRC_ALPHA + public const int ONE_MINUS_SRC_ALPHA; // GL_ONE_MINUS_SRC_ALPHA [CCode (cname = "RL_DST_ALPHA")] - public const int DST_ALPHA; // GL_DST_ALPHA + public const int DST_ALPHA; // GL_DST_ALPHA [CCode (cname = "RL_ONE_MINUS_DST_ALPHA")] - public const int ONE_MINUS_DST_ALPHA; // GL_ONE_MINUS_DST_ALPHA + public const int ONE_MINUS_DST_ALPHA; // GL_ONE_MINUS_DST_ALPHA [CCode (cname = "RL_DST_COLOR")] - public const int DST_COLOR; // GL_DST_COLOR + public const int DST_COLOR; // GL_DST_COLOR [CCode (cname = "RL_ONE_MINUS_DST_COLOR")] - public const int ONE_MINUS_DST_COLOR; // GL_ONE_MINUS_DST_COLOR + public const int ONE_MINUS_DST_COLOR; // GL_ONE_MINUS_DST_COLOR [CCode (cname = "RL_SRC_ALPHA_SATURATE")] - public const int SRC_ALPHA_SATURATE; // GL_SRC_ALPHA_SATURATE + public const int SRC_ALPHA_SATURATE; // GL_SRC_ALPHA_SATURATE [CCode (cname = "RL_CONSTANT_COLOR")] - public const int CONSTANT_COLOR; // GL_CONSTANT_COLOR + public const int CONSTANT_COLOR; // GL_CONSTANT_COLOR [CCode (cname = "RL_ONE_MINUS_CONSTANT_COLOR")] - public const int ONE_MINUS_CONSTANT_COLOR; // GL_ONE_MINUS_CONSTANT_COLOR + public const int ONE_MINUS_CONSTANT_COLOR; // GL_ONE_MINUS_CONSTANT_COLOR [CCode (cname = "RL_CONSTANT_ALPHA")] - public const int CONSTANT_ALPHA; // GL_CONSTANT_ALPHA + public const int CONSTANT_ALPHA; // GL_CONSTANT_ALPHA [CCode (cname = "RL_ONE_MINUS_CONSTANT_ALPHA")] - public const int ONE_MINUS_CONSTANT_ALPHA; // GL_ONE_MINUS_CONSTANT_ALPHA + public const int ONE_MINUS_CONSTANT_ALPHA; // GL_ONE_MINUS_CONSTANT_ALPHA // GL blending functions/equations [CCode (cname = "RL_FUNC_ADD")] - public const int FUNC_ADD; // GL_FUNC_ADD + public const int FUNC_ADD; // GL_FUNC_ADD [CCode (cname = "RL_MIN")] - public const int MIN; // GL_MIN + public const int MIN; // GL_MIN [CCode (cname = "RL_MAX")] - public const int MAX; // GL_MAX + public const int MAX; // GL_MAX [CCode (cname = "RL_FUNC_SUBTRACT")] - public const int FUNC_SUBTRACT; // GL_FUNC_SUBTRACT + public const int FUNC_SUBTRACT; // GL_FUNC_SUBTRACT [CCode (cname = "RL_FUNC_REVERSE_SUBTRACT")] - public const int FUNC_REVERSE_SUBTRACT; // GL_FUNC_REVERSE_SUBTRACT + public const int FUNC_REVERSE_SUBTRACT; // GL_FUNC_REVERSE_SUBTRACT [CCode (cname = "RL_BLEND_EQUATION")] - public const int BLEND_EQUATION; // GL_BLEND_EQUATION + public const int BLEND_EQUATION; // GL_BLEND_EQUATION [CCode (cname = "RL_BLEND_EQUATION_RGB")] - public const int BLEND_EQUATION_RGB; // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION) + public const int BLEND_EQUATION_RGB; // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION) [CCode (cname = "RL_BLEND_EQUATION_ALPHA")] - public const int BLEND_EQUATION_ALPHA; // GL_BLEND_EQUATION_ALPHA + public const int BLEND_EQUATION_ALPHA; // GL_BLEND_EQUATION_ALPHA [CCode (cname = "RL_BLEND_DST_RGB")] - public const int BLEND_DST_RGB; // GL_BLEND_DST_RGB + public const int BLEND_DST_RGB; // GL_BLEND_DST_RGB [CCode (cname = "RL_BLEND_SRC_RGB")] - public const int BLEND_SRC_RGB; // GL_BLEND_SRC_RGB + public const int BLEND_SRC_RGB; // GL_BLEND_SRC_RGB [CCode (cname = "RL_BLEND_DST_ALPHA")] - public const int BLEND_DST_ALPHA; // GL_BLEND_DST_ALPHA + public const int BLEND_DST_ALPHA; // GL_BLEND_DST_ALPHA [CCode (cname = "RL_BLEND_SRC_ALPHA")] - public const int BLEND_SRC_ALPHA; // GL_BLEND_SRC_ALPHA + public const int BLEND_SRC_ALPHA; // GL_BLEND_SRC_ALPHA [CCode (cname = "RL_BLEND_COLOR")] - public const int BLEND_COLOR; // GL_BLEND_COLOR + public const int BLEND_COLOR; // GL_BLEND_COLOR - //---------------------------------------------------------------------------------- + [CCode (cname = "RL_READ_FRAMEBUFFER")] + public const int READ_FRAMEBUFFER; // GL_READ_FRAMEBUFFER + + [CCode (cname = "RL_DRAW_FRAMEBUFFER")] + public const int DRAW_FRAMEBUFFER; // GL_DRAW_FRAMEBUFFER + + // ---------------------------------------------------------------------------------- // Types and Structures Definition - //---------------------------------------------------------------------------------- + // ---------------------------------------------------------------------------------- [SimpleType] [CCode (cname = "Matrix")] public struct Matrix { @@ -272,236 +278,254 @@ namespace Rlgl { [SimpleType] [CCode (cname = "rlVertexBuffer")] public struct VertexBuffer { - public int elementCount; // Number of elements in the buffer (QUADS) + [CCode (cname = "elementCount")] + public int element_count; // Number of elements in the buffer (QUADS) + + public unowned float[] vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) + public unowned float[] texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + public unowned uchar[] colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) + public unowned ushort[] indices; // Vertex indices (in case vertex data comes indexed) (6 indices per quad) - public unowned float[] vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) - public unowned float[] texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) - public unowned uchar[] colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) - public unowned ushort[] indices; // Vertex indices (in case vertex data comes indexed) (6 indices per quad) + [CCode (cname = "vaoId")] + public uint vao_id; // OpenGL Vertex Array Object id - public uint vaoId; // OpenGL Vertex Array Object id - public unowned uint vboId[4]; // OpenGL Vertex Buffer Objects id (4 types of vertex data) + [CCode (cname = "vboId")] + public unowned uint vbo_id[4]; // OpenGL Vertex Buffer Objects id (4 types of vertex data) } // Draw call type [SimpleType] [CCode (cname = "rlDrawCall")] public struct DrawCall { - public int mode; // Drawing mode: LINES, TRIANGLES, QUADS - public int vertexCount; // Number of vertex of the draw - public int vertexAlignment; // Number of vertex required for index alignment (LINES, TRIANGLES) - public uint textureId; // Texture id to be used on the draw -> Use to create new draw call if changes + public int mode; // Drawing mode: LINES, TRIANGLES, QUADS + [CCode (cname = "vertex_count")] + public int vertexCount; // Number of vertex of the draw + + [CCode (cname = "vertex_alignment")] + public int vertexAlignment; // Number of vertex required for index alignment (LINES, TRIANGLES) + + [CCode (cname = "textureId")] + public uint texture_id; // Texture id to be used on the draw -> Use to create new draw call if changes } // rlRenderBatch type [SimpleType] [CCode (cname = "rlRenderBatch")] public struct RenderBatch { - public int bufferCount; // Number of vertex buffers (multi-buffering support) - public int currentBuffer; // Current buffer tracking in case of multi-buffering - public unowned VertexBuffer[] vertexBuffer; // Dynamic buffer(s) for vertex data + [CCode (cname = "currentBuffer")] + public int current_buffer; // Current buffer tracking in case of multi-buffering - public unowned DrawCall[] draws; // Draw calls array, depends on textureId - public int drawCounter; // Draw calls counter - public float currentDepth; // Current depth value for next draw + [CCode (cname = "vertexBuffer", array_length_cname = "bufferCount", array_length_type = "int")] + public unowned VertexBuffer[] vertex_buffer; // Dynamic buffer(s) for vertex data + + [CCode (array_length_cname = "drawCounter", array_length_type = "int")] + public unowned DrawCall[] draws; // Draw calls array, depends on textureId + + [CCode (cname = "currentDepth")] + public float currentDepth; // Current depth value for next draw } // OpenGL version - [CCode (cname = "rlGlVersion", has_type_id = false, cprefix="RL_")] + [CCode (cname = "rlGlVersion", has_type_id = false, cprefix = "RL_")] public enum GlVersion { - OPENGL_11, // OpenGL 1.1 - OPENGL_21, // OpenGL 2.1 (GLSL 120) - OPENGL_33, // OpenGL 3.3 (GLSL 330) - OPENGL_43, // OpenGL 4.3 (using GLSL 330) - OPENGL_ES_20 // OpenGL ES 2.0 (GLSL 100) + OPENGL_SOFTWARE, // Software rendering + OPENGL_11, // OpenGL 1.1 + OPENGL_21, // OpenGL 2.1 (GLSL 120) + OPENGL_33, // OpenGL 3.3 (GLSL 330) + OPENGL_43, // OpenGL 4.3 (using GLSL 330) + OPENGL_ES_20 // OpenGL ES 2.0 (GLSL 100) } // Trace log level - [CCode (cname = "rlTraceLogLevel", has_type_id = false, cprefix="RL_")] + [CCode (cname = "rlTraceLogLevel", has_type_id = false, cprefix = "RL_")] public enum TraceLogLevel { - LOG_ALL, // Display all logs - LOG_TRACE, // Trace logging, intended for internal use only - LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds - LOG_INFO, // Info logging, used for program execution info - LOG_WARNING, // Warning logging, used on recoverable failures - LOG_ERROR, // Error logging, used on unrecoverable failures - LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) - LOG_NONE // Disable logging + LOG_ALL, // Display all logs + LOG_TRACE, // Trace logging, intended for internal use only + LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds + LOG_INFO, // Info logging, used for program execution info + LOG_WARNING, // Warning logging, used on recoverable failures + LOG_ERROR, // Error logging, used on unrecoverable failures + LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) + LOG_NONE // Disable logging } // Texture pixel formats - [CCode (cname = "rlPixelFormat", has_type_id = false, cprefix="RL_")] + [CCode (cname = "rlPixelFormat", has_type_id = false, cprefix = "RL_PIXELFORMAT_")] public enum PixelFormat { - PIXELFORMAT_UNCOMPRESSED_GRAYSCALE, // 8 bit per pixel (no alpha) - PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) - PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp - PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp - PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) - PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) - PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp - PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) - PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) - PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) - PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) - PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) - PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp - PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp - PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp - PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp - PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp - PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp + UNCOMPRESSED_GRAYSCALE, // 8 bit per pixel (no alpha) + UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) + UNCOMPRESSED_R5G6B5, // 16 bpp + UNCOMPRESSED_R8G8B8, // 24 bpp + UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) + UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) + UNCOMPRESSED_R8G8B8A8, // 32 bpp + UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) + COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) + COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) + COMPRESSED_DXT3_RGBA, // 8 bpp + COMPRESSED_DXT5_RGBA, // 8 bpp + COMPRESSED_ETC1_RGB, // 4 bpp + COMPRESSED_ETC2_RGB, // 4 bpp + COMPRESSED_ETC2_EAC_RGBA, // 8 bpp + COMPRESSED_PVRT_RGB, // 4 bpp + COMPRESSED_PVRT_RGBA, // 4 bpp + [CCode (cname = "RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA")] + COMPRESSED_ASTC_4X4_RGBA, + [CCode (cname = "RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA")] + COMPRESSED_ASTC_8X8_RGBA // 2 bpp } // Texture parameters: filter mode - [CCode (cname = "rlTextureFilter", has_type_id = false, cprefix="RL_")] + [CCode (cname = "rlTextureFilter", has_type_id = false, cprefix = "RL_TEXTURE_FILTER_")] public enum TextureFilter { - TEXTURE_FILTER_POINT, // No filter, just pixel approximation - TEXTURE_FILTER_BILINEAR, // Linear filtering - TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) - TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x - TEXTURE_FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x - TEXTURE_FILTER_ANISOTROPIC_16X // Anisotropic filtering 16x + POINT, // No filter, just pixel approximation + BILINEAR, // Linear filtering + TRILINEAR, // Trilinear filtering (linear with mipmaps) + ANISOTROPIC_4X, // Anisotropic filtering 4x + ANISOTROPIC_8X, // Anisotropic filtering 8x + ANISOTROPIC_16X // Anisotropic filtering 16x } // Color blending modes (pre-defined) - [CCode (cname = "rlBlendMode", has_type_id = false, cprefix="RL_")] + [CCode (cname = "rlBlendMode", has_type_id = false, cprefix = "RL_BLEND_")] public enum BlendMode { - BLEND_ALPHA, // Blend textures considering alpha (default) - BLEND_ADDITIVE, // Blend textures adding colors - BLEND_MULTIPLIED, // Blend textures multiplying colors - BLEND_ADD_COLORS, // Blend textures adding colors (alternative) - BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) - BLEND_ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha - BLEND_CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendFactors()) - BLEND_CUSTOM_SEPARATE // Blend textures using custom src/dst factors (use rlSetBlendFactorsSeparate()) + ALPHA, // Blend textures considering alpha (default) + ADDITIVE, // Blend textures adding colors + MULTIPLIED, // Blend textures multiplying colors + ADD_COLORS, // Blend textures adding colors (alternative) + SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) + ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha + CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendFactors()) + CUSTOM_SEPARATE // Blend textures using custom src/dst factors (use rlSetBlendFactorsSeparate()) } // Shader location point type - [CCode (cname = "rlShaderLocationIndex", has_type_id = false, cprefix="RL_")] + [CCode (cname = "rlShaderLocationIndex", has_type_id = false, cprefix = "RL_SHADER_LOC_")] public enum ShaderLocationIndex { - SHADER_LOC_VERTEX_POSITION, // Shader location: vertex attribute: position - SHADER_LOC_VERTEX_TEXCOORD01, // Shader location: vertex attribute: texcoord01 - SHADER_LOC_VERTEX_TEXCOORD02, // Shader location: vertex attribute: texcoord02 - SHADER_LOC_VERTEX_NORMAL, // Shader location: vertex attribute: normal - SHADER_LOC_VERTEX_TANGENT, // Shader location: vertex attribute: tangent - SHADER_LOC_VERTEX_COLOR, // Shader location: vertex attribute: color - SHADER_LOC_MATRIX_MVP, // Shader location: matrix uniform: model-view-projection - SHADER_LOC_MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) - SHADER_LOC_MATRIX_PROJECTION, // Shader location: matrix uniform: projection - SHADER_LOC_MATRIX_MODEL, // Shader location: matrix uniform: model (transform) - SHADER_LOC_MATRIX_NORMAL, // Shader location: matrix uniform: normal - SHADER_LOC_VECTOR_VIEW, // Shader location: vector uniform: view - SHADER_LOC_COLOR_DIFFUSE, // Shader location: vector uniform: diffuse color - SHADER_LOC_COLOR_SPECULAR, // Shader location: vector uniform: specular color - SHADER_LOC_COLOR_AMBIENT, // Shader location: vector uniform: ambient color - SHADER_LOC_MAP_ALBEDO, // Shader location: sampler2d texture: albedo (same as: RL_SHADER_LOC_MAP_DIFFUSE) - SHADER_LOC_MAP_METALNESS, // Shader location: sampler2d texture: metalness (same as: RL_SHADER_LOC_MAP_SPECULAR) - SHADER_LOC_MAP_NORMAL, // Shader location: sampler2d texture: normal - SHADER_LOC_MAP_ROUGHNESS, // Shader location: sampler2d texture: roughness - SHADER_LOC_MAP_OCCLUSION, // Shader location: sampler2d texture: occlusion - SHADER_LOC_MAP_EMISSION, // Shader location: sampler2d texture: emission - SHADER_LOC_MAP_HEIGHT, // Shader location: sampler2d texture: height - SHADER_LOC_MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap - SHADER_LOC_MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance - SHADER_LOC_MAP_PREFILTER, // Shader location: samplerCube texture: prefilter - SHADER_LOC_MAP_BRDF // Shader location: sampler2d texture: brdf + VERTEX_POSITION, // Shader location: vertex attribute: position + VERTEX_TEXCOORD01, // Shader location: vertex attribute: texcoord01 + VERTEX_TEXCOORD02, // Shader location: vertex attribute: texcoord02 + VERTEX_NORMAL, // Shader location: vertex attribute: normal + VERTEX_TANGENT, // Shader location: vertex attribute: tangent + VERTEX_COLOR, // Shader location: vertex attribute: color + MATRIX_MVP, // Shader location: matrix uniform: model-view-projection + MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) + MATRIX_PROJECTION, // Shader location: matrix uniform: projection + MATRIX_MODEL, // Shader location: matrix uniform: model (transform) + MATRIX_NORMAL, // Shader location: matrix uniform: normal + VECTOR_VIEW, // Shader location: vector uniform: view + COLOR_DIFFUSE, // Shader location: vector uniform: diffuse color + COLOR_SPECULAR, // Shader location: vector uniform: specular color + COLOR_AMBIENT, // Shader location: vector uniform: ambient color + MAP_ALBEDO, // Shader location: sampler2d texture: albedo (same as: RL_SHADER_LOC_MAP_DIFFUSE) + MAP_METALNESS, // Shader location: sampler2d texture: metalness (same as: RL_SHADER_LOC_MAP_SPECULAR) + MAP_NORMAL, // Shader location: sampler2d texture: normal + MAP_ROUGHNESS, // Shader location: sampler2d texture: roughness + MAP_OCCLUSION, // Shader location: sampler2d texture: occlusion + MAP_EMISSION, // Shader location: sampler2d texture: emission + MAP_HEIGHT, // Shader location: sampler2d texture: height + MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap + MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance + MAP_PREFILTER, // Shader location: samplerCube texture: prefilter + MAP_BRDF; // Shader location: sampler2d texture: brdf + + [CCode (cname = "RL_SHADER_LOC_MAP_DIFFUSE")] + public const ShaderLocationIndex MAP_DIFFUSE; + + [CCode (cname = "RL_SHADER_LOC_MAP_SPECULAR")] + public const ShaderLocationIndex MAP_SPECULAR; } - - [CCode (cname = "RL_SHADER_LOC_MAP_DIFFUSE")] - public const int SHADER_LOC_MAP_DIFFUSE; - - [CCode (cname = "RL_SHADER_LOC_MAP_SPECULAR")] - public const int SHADER_LOC_MAP_SPECULAR; - - // Shader uniform data type - [CCode (cname = "rlShaderUniformDataType", has_type_id = false)] + [CCode (cname = "rlShaderUniformDataType", cprefix = "RL_SHADER_", has_type_id = false)] public enum ShaderUniformDataType { - SHADER_UNIFORM_FLOAT, // Shader uniform type: float - SHADER_UNIFORM_VEC2, // Shader uniform type: vec2 (2 float) - SHADER_UNIFORM_VEC3, // Shader uniform type: vec3 (3 float) - SHADER_UNIFORM_VEC4, // Shader uniform type: vec4 (4 float) - SHADER_UNIFORM_INT, // Shader uniform type: int - SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) - SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) - SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int) - SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d + UNIFORM_FLOAT, // Shader uniform type: float + UNIFORM_VEC2, // Shader uniform type: vec2 (2 float) + UNIFORM_VEC3, // Shader uniform type: vec3 (3 float) + UNIFORM_VEC4, // Shader uniform type: vec4 (4 float) + UNIFORM_INT, // Shader uniform type: int + UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) + UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) + UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int) + UINT, // Shader uniform type: unsigned int + UIVEC2, // Shader uniform type: uivec2 (2 unsigned int) + UIVEC3, // Shader uniform type: uivec3 (3 unsigned int) + UIVEC4, // Shader uniform type: uivec4 (4 unsigned int) + SAMPLER2D // Shader uniform type: sampler2d } // Shader attribute data types - [CCode (cname = "rlShaderAttributeDataType", has_type_id = false)] + [CCode (cname = "rlShaderAttributeDataType", cprefix = "RL_SHADER_ATTRIB_", has_type_id = false)] public enum ShaderAttributeDataType { - SHADER_ATTRIB_FLOAT, // Shader attribute type: float - SHADER_ATTRIB_VEC2, // Shader attribute type: vec2 (2 float) - SHADER_ATTRIB_VEC3, // Shader attribute type: vec3 (3 float) - SHADER_ATTRIB_VEC4 // Shader attribute type: vec4 (4 float) + FLOAT, // Shader attribute type: float + VEC2, // Shader attribute type: vec2 (2 float) + VEC3, // Shader attribute type: vec3 (3 float) + VEC4 // Shader attribute type: vec4 (4 float) } // Framebuffer attachment type - [CCode (cname = "rlFramebufferAttachType", has_type_id = false)] + [CCode (cname = "rlFramebufferAttachType", cprefix = "RL_ATTACHMENT_", has_type_id = false)] public enum FramebufferAttachType { - ATTACHMENT_COLOR_CHANNEL0, // Framebuffer attachment type: color 0 - ATTACHMENT_COLOR_CHANNEL1, // Framebuffer attachment type: color 1 - ATTACHMENT_COLOR_CHANNEL2, // Framebuffer attachment type: color 2 - ATTACHMENT_COLOR_CHANNEL3, // Framebuffer attachment type: color 3 - ATTACHMENT_COLOR_CHANNEL4, // Framebuffer attachment type: color 4 - ATTACHMENT_COLOR_CHANNEL5, // Framebuffer attachment type: color 5 - ATTACHMENT_COLOR_CHANNEL6, // Framebuffer attachment type: color 6 - ATTACHMENT_COLOR_CHANNEL7, // Framebuffer attachment type: color 7 - ATTACHMENT_DEPTH, // Framebuffer attachment type: depth - ATTACHMENT_STENCIL // Framebuffer attachment type: stencil + COLOR_CHANNEL0, // Framebuffer attachment type: color 0 + COLOR_CHANNEL1, // Framebuffer attachment type: color 1 + COLOR_CHANNEL2, // Framebuffer attachment type: color 2 + COLOR_CHANNEL3, // Framebuffer attachment type: color 3 + COLOR_CHANNEL4, // Framebuffer attachment type: color 4 + COLOR_CHANNEL5, // Framebuffer attachment type: color 5 + COLOR_CHANNEL6, // Framebuffer attachment type: color 6 + COLOR_CHANNEL7, // Framebuffer attachment type: color 7 + DEPTH, // Framebuffer attachment type: depth + STENCIL // Framebuffer attachment type: stencil } // Framebuffer texture attachment type - [CCode (cname = "rlFramebufferAttachTextureType", has_type_id = false)] + [CCode (cname = "rlFramebufferAttachTextureType", cprefix = "RL_ATTACHMENT_", has_type_id = false)] public enum FramebufferAttachTextureType { - ATTACHMENT_CUBEMAP_POSITIVE_X, // Framebuffer texture attachment type: cubemap, +X side - ATTACHMENT_CUBEMAP_NEGATIVE_X, // Framebuffer texture attachment type: cubemap, -X side - ATTACHMENT_CUBEMAP_POSITIVE_Y, // Framebuffer texture attachment type: cubemap, +Y side - ATTACHMENT_CUBEMAP_NEGATIVE_Y, // Framebuffer texture attachment type: cubemap, -Y side - ATTACHMENT_CUBEMAP_POSITIVE_Z, // Framebuffer texture attachment type: cubemap, +Z side - ATTACHMENT_CUBEMAP_NEGATIVE_Z, // Framebuffer texture attachment type: cubemap, -Z side - ATTACHMENT_TEXTURE2D, // Framebuffer texture attachment type: texture2d - ATTACHMENT_RENDERBUFFER // Framebuffer texture attachment type: renderbuffer + CUBEMAP_POSITIVE_X, // Framebuffer texture attachment type: cubemap, +X side + CUBEMAP_NEGATIVE_X, // Framebuffer texture attachment type: cubemap, -X side + CUBEMAP_POSITIVE_Y, // Framebuffer texture attachment type: cubemap, +Y side + CUBEMAP_NEGATIVE_Y, // Framebuffer texture attachment type: cubemap, -Y side + CUBEMAP_POSITIVE_Z, // Framebuffer texture attachment type: cubemap, +Z side + CUBEMAP_NEGATIVE_Z, // Framebuffer texture attachment type: cubemap, -Z side + TEXTURE2D, // Framebuffer texture attachment type: texture2d + RENDERBUFFER // Framebuffer texture attachment type: renderbuffer } // Face culling mode - [CCode (cname = "rlCullMode", has_type_id = false)] + [CCode (cname = "rlCullMode", cprefix = "RL_CULL_", has_type_id = false)] public enum CullMode { - RL_CULL_FACE_FRONT, - RL_CULL_FACE_BACK + FACE_FRONT, + FACE_BACK } - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Functions Declaration - Matrix operations - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ [CCode (cname = "rlMatrixMode")] - public static void rl_matrix_mode (int mode); // Choose the current matrix to be transformed + public static void rl_matrix_mode (int mode); // Choose the current matrix to be transformed [CCode (cname = "rlPushMatrix")] - public static void rl_push_matrix (); // Push the current matrix to stack + public static void rl_push_matrix (); // Push the current matrix to stack [CCode (cname = "rlPopMatrix")] - public static void rl_pop_matrix (); // Pop latest inserted matrix from stack + public static void rl_pop_matrix (); // Pop latest inserted matrix from stack [CCode (cname = "rlLoadIdentity")] - public static void rl_load_identity (); // Reset current matrix to identity matrix + public static void rl_load_identity (); // Reset current matrix to identity matrix [CCode (cname = "rlTranslatef")] - public static void rl_translatef (float x, float y, float z); // Multiply the current matrix by a translation matrix + public static void rl_translatef (float x, float y, float z); // Multiply the current matrix by a translation matrix [CCode (cname = "rlRotatef")] - public static void rl_rotatref (float angle, float x, float y, float z); // Multiply the current matrix by a rotation matrix + public static void rl_rotatref (float angle, float x, float y, float z); // Multiply the current matrix by a rotation matrix [CCode (cname = "rlScalef")] - public static void rl_scalef (float x, float y, float z); // Multiply the current matrix by a scaling matrix + public static void rl_scalef (float x, float y, float z); // Multiply the current matrix by a scaling matrix [CCode (cname = "rlMultMatrixf")] - public static void rl_multiply_matrixf (float[] matrixf); // Multiply the current matrix by another matrix + public static void rl_multiply_matrixf (float[] matrixf); // Multiply the current matrix by another matrix [CCode (cname = "rlFrustum")] public static void rl_frustum (double left, double right, double bottom, double top, double znear, double zfar); @@ -510,94 +534,102 @@ namespace Rlgl { public static void rl_ortho (double left, double right, double bottom, double top, double znear, double zfar); [CCode (cname = "rlViewport")] - public static void rl_viewport (int x, int y, int width, int height); // Set the viewport area + public static void rl_viewport (int x, int y, int width, int height); // Set the viewport area + + [CCode (cname = "rlSetClipPlanes")] + public static void rl_set_clip_planes (double near_plane, double far_plane); // Set clip planes distances + + [CCode (cname = "rlGetCullDistanceNear")] + public static double rl_get_cull_distance_near (); // Get cull plane distance near - //------------------------------------------------------------------------------------ + [CCode (cname = "rlGetCullDistanceFar")] + public static double rl_get_cull_distance_far (); // Get cull plane distance far + + // ------------------------------------------------------------------------------------ // Functions Declaration - Vertex level operations - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ [CCode (cname = "rlBegin")] - public static void rl_begin (int mode); // Initialize drawing mode (how to organize vertex) + public static void rl_begin (int mode); // Initialize drawing mode (how to organize vertex) [CCode (cname = "rlEnd")] - public static void rl_end (); // Finish vertex providing + public static void rl_end (); // Finish vertex providing [CCode (cname = "rlVertex2i")] - public static void rl_vertex2i (int x, int y); // Define one vertex (position) - 2 int + public static void rl_vertex2i (int x, int y); // Define one vertex (position) - 2 int [CCode (cname = "rlVertex2f")] - public static void rl_vertex2f (float x, float y); // Define one vertex (position) - 2 float + public static void rl_vertex2f (float x, float y); // Define one vertex (position) - 2 float [CCode (cname = "rlVertex3f")] - public static void rl_vertex3f (float x, float y, float z); // Define one vertex (position) - 3 float + public static void rl_vertex3f (float x, float y, float z); // Define one vertex (position) - 3 float [CCode (cname = "rlTexCoord2f")] - public static void rl_tex_coord2f (float x, float y); // Define one vertex (texture coordinate) - 2 float + public static void rl_tex_coord2f (float x, float y); // Define one vertex (texture coordinate) - 2 float [CCode (cname = "rlNormal3f")] - public static void rl_normal3f (float x, float y, float z); // Define one vertex (normal) - 3 float + public static void rl_normal3f (float x, float y, float z); // Define one vertex (normal) - 3 float [CCode (cname = "rlColor4ub")] - public static void rl_color4ub (uchar r, uchar g, uchar b, uchar a); // Define one vertex (color) - 4 byte + public static void rl_color4ub (uchar r, uchar g, uchar b, uchar a); // Define one vertex (color) - 4 byte [CCode (cname = "rlColor3f")] - public static void rl_color3f (float x, float y, float z); // Define one vertex (color) - 3 float + public static void rl_color3f (float x, float y, float z); // Define one vertex (color) - 3 float [CCode (cname = "rlColor4f")] - public static void rl_color4f (float x, float y, float z, float w); // Define one vertex (color) - 4 float + public static void rl_color4f (float x, float y, float z, float w); // Define one vertex (color) - 4 float - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Functions Declaration - OpenGL style functions (common to 1.1, 3.3+, ES2) // NOTE: This functions are used to completely abstract raylib code from OpenGL layer, // some of them are direct wrappers over OpenGL calls, some others are custom - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Vertex buffers state [CCode (cname = "rlEnableVertexArray")] - public static bool rl_enable_vertex_array (uint vaoId); // Enable vertex array (VAO, if supported) + public static bool rl_enable_vertex_array (uint vaoId); // Enable vertex array (VAO, if supported) [CCode (cname = "rlDisableVertexArray")] - public static void rl_disable_vertex_array (); // Disable vertex array (VAO, if supported) + public static void rl_disable_vertex_array (); // Disable vertex array (VAO, if supported) [CCode (cname = "rlEnableVertexBuffer")] - public static void rl_enable_vertex_buffer (uint id); // Enable vertex buffer (VBO) + public static void rl_enable_vertex_buffer (uint id); // Enable vertex buffer (VBO) [CCode (cname = "rlDisableVertexBuffer")] - public static void rl_disable_vertex_buffer (); // Disable vertex buffer (VBO) + public static void rl_disable_vertex_buffer (); // Disable vertex buffer (VBO) [CCode (cname = "rlEnableVertexBufferElement")] - public static void rl_enable_vertex_buffer_element (uint id);// Enable vertex buffer element (VBO element) + public static void rl_enable_vertex_buffer_element (uint id); // Enable vertex buffer element (VBO element) [CCode (cname = "rlDisableVertexBufferElement")] - public static void rl_disable_vertex_buffer_element (); // Disable vertex buffer element (VBO element) + public static void rl_disable_vertex_buffer_element (); // Disable vertex buffer element (VBO element) [CCode (cname = "rlEnableVertexAttribute")] public static void rl_enable_vertex_attribute (uint index); // Enable vertex attribute index [CCode (cname = "rlDisableVertexAttribute")] - public static void rl_disable_vertex_attribute (uint index);// Disable vertex attribute index -#if GRAPHICS_API_OPENGL_11 + public static void rl_disable_vertex_attribute (uint index); // Disable vertex attribute index + [CCode (cname = "rlEnableStatePointer")] - public static void rl_enable_state_pointer (int attribute_type, void* buffer); // Enable attribute state pointer + public static void rl_enable_state_pointer (int attribute_type, void* buffer); // Enable attribute state pointer [CCode (cname = "rlDisableStatePointer")] - public static void rl_disable_state_pointer (int attribute_type); // Disable attribute state pointer -#endif + public static void rl_disable_state_pointer (int attribute_type); // Disable attribute state pointer // Textures state [CCode (cname = "rlActiveTextureSlot")] - public static void rl_active_texture_slot (int slot); // Select and active a texture slot + public static void rl_active_texture_slot (int slot); // Select and active a texture slot [CCode (cname = "rlEnableTexture")] - public static void rl_enable_texture (uint id); // Enable texture + public static void rl_enable_texture (uint id); // Enable texture [CCode (cname = "rlDisableTexture")] - public static void rl_disable_texture (); // Disable texture + public static void rl_disable_texture (); // Disable texture [CCode (cname = "rlEnableTextureCubemap")] - public static void rl_enable_texture_cubemap (uint id); // Enable texture cubemap + public static void rl_enable_texture_cubemap (uint id); // Enable texture cubemap [CCode (cname = "rlDisableTextureCubemap")] - public static void rl_disable_texture_cubemap (); // Disable texture cubemap + public static void rl_disable_texture_cubemap (); // Disable texture cubemap [CCode (cname = "rlTextureParameters")] public static void rl_texture_parameters (uint id, int parameter, int value); // Set texture parameters (filter, wrap) @@ -607,97 +639,122 @@ namespace Rlgl { // Shader state [CCode (cname = "rlEnableShader")] - public static void rl_enable_shader (uint id); // Enable shader program + public static void rl_enable_shader (uint id); // Enable shader program [CCode (cname = "rlDisableShader")] - public static void rl_disable_shader (); // Disable shader program + public static void rl_disable_shader (); // Disable shader program // Framebuffer state [CCode (cname = "rlEnableFramebuffer")] - public static void rl_enable_framebuffer (uint id); // Enable render texture (fbo) + public static void rl_enable_framebuffer (uint id); // Enable render texture (fbo) [CCode (cname = "rlDisableFramebuffer")] - public static void rl_disable_framebuffer (); // Disable render texture (fbo), return to default framebuffer + public static void rl_disable_framebuffer (); // Disable render texture (fbo), return to default framebuffer + + [CCode (cname = "rlGetActiveFramebuffer")] + public static uint rl_get_active_framebuffer (); [CCode (cname = "rlActiveDrawBuffers")] - public static void rl_active_draw_buffers (int count); // Activate multiple draw color buffers + public static void rl_active_draw_buffers (int count); // Activate multiple draw color buffers + + [CCode (cname = "rlBlitFramebuffer")] + public static void rl_blit_framebuffer (int src_x, int src_y, int src_width, int src_height, int dst_x, int dst_y, + int dst_width, int dst_height, int buffer_mask); // Blit active framebuffer to main framebuffer + + [CCode (cname = "rlBindFramebuffer")] + public static void rl_bind_framebuffer (uint target, uint framebuffer); // Bind framebuffer (FBO) // General render state [CCode (cname = "rlEnableColorBlend")] - public static void rl_enable_color_blend (); // Enable color blending + public static void rl_enable_color_blend (); // Enable color blending [CCode (cname = "rlDisableColorBlend")] - public static void rl_disable_color_blend (); // Disable color blending + public static void rl_disable_color_blend (); // Disable color blending [CCode (cname = "rlEnableDepthTest")] - public static void rl_enable_depth_test (); // Enable depth test + public static void rl_enable_depth_test (); // Enable depth test [CCode (cname = "rlDisableDepthTest")] - public static void rl_disable_depth_test (); // Disable depth test + public static void rl_disable_depth_test (); // Disable depth test [CCode (cname = "rlEnableDepthMask")] - public static void rl_enable_depth_mask (); // Enable depth write + public static void rl_enable_depth_mask (); // Enable depth write [CCode (cname = "rlDisableDepthMask")] - public static void rl_disable_depth_mask (); // Disable depth write + public static void rl_disable_depth_mask (); // Disable depth write [CCode (cname = "rlEnableBackfaceCulling")] - public static void rl_enable_backface_culling (); // Enable backface culling + public static void rl_enable_backface_culling (); // Enable backface culling [CCode (cname = "rlDisableBackfaceCulling")] - public static void rl_disable_backface_culling (); // Disable backface culling + public static void rl_disable_backface_culling (); // Disable backface culling + + [CCode (cname = "rlColorMask")] + public static void rl_color_mask (bool r, bool g, bool b, bool a); // Color mask control [CCode (cname = "rlSetCullFace")] - public static void rl_set_cull_face (int mode); // Set face culling mode + public static void rl_set_cull_face (int mode); // Set face culling mode [CCode (cname = "rlEnableScissorTest")] - public static void rl_enable_scissor_test (); // Enable scissor test + public static void rl_enable_scissor_test (); // Enable scissor test [CCode (cname = "rlDisableScissorTest")] - public static void rl_disable_scissor_test (); // Disable scissor test + public static void rl_disable_scissor_test (); // Disable scissor test [CCode (cname = "rlScissor")] public static void rl_scissor (int x, int y, int width, int height); // Scissor test + [CCode (cname = "rlEnablePointMode")] + public static void rl_enable_point_mode (); // Enable point mode + + [CCode (cname = "rlDisablePointMode")] + public static void rl_disable_point_mode (); // Disable point mode + + [CCode (cname = "rlSetPointSize")] + public static void rl_set_point_size (float size); // Set the point drawing size + + [CCode (cname = "rlGetPointSize")] + public static float rl_get_point_size (); // Get the point drawing size + [CCode (cname = "rlEnableWireMode")] - public static void rl_enable_wire_mode (); // Enable wire mode + public static void rl_enable_wire_mode (); // Enable wire mode [CCode (cname = "rlDisableWireMode")] - public static void rl_disable_wire_mode (); // Disable wire mode + public static void rl_disable_wire_mode (); // Disable wire mode [CCode (cname = "rlSetLineWidth")] - public static void rl_set_line_width (float width); // Set the line drawing width + public static void rl_set_line_width (float width); // Set the line drawing width [CCode (cname = "rlGetLineWidth")] - public static float rl_get_line_width (); // Get the line drawing width + public static float rl_get_line_width (); // Get the line drawing width [CCode (cname = "rlEnableSmoothLines")] - public static void rl_enable_smooth_lines (); // Enable line aliasing + public static void rl_enable_smooth_lines (); // Enable line aliasing [CCode (cname = "rlDisableSmoothLines")] - public static void rl_disable_smooth_lines (); // Disable line aliasing + public static void rl_disable_smooth_lines (); // Disable line aliasing [CCode (cname = "rlEnableStereoRender")] - public static void rl_enable_stereo_render (); // Enable stereo rendering + public static void rl_enable_stereo_render (); // Enable stereo rendering [CCode (cname = "rlDisableStereoRender")] - public static void rl_disable_stereo_render (); // Disable stereo rendering + public static void rl_disable_stereo_render (); // Disable stereo rendering [CCode (cname = "rlIsStereoRenderEnabled")] - public static bool rl_is_stereo_render_enabled (); // Check if stereo render is enabled + public static bool rl_is_stereo_render_enabled (); // Check if stereo render is enabled [CCode (cname = "rlClearColor")] public static void rl_clear_color (uchar r, uchar g, uchar b, uchar a); // Clear color buffer with color [CCode (cname = "rlClearScreenBuffers")] - public static void rl_clear_screen_buffers (); // Clear used screen buffers (color and depth) + public static void rl_clear_screen_buffers (); // Clear used screen buffers (color and depth) [CCode (cname = "rlCheckErrors")] - public static void rl_check_errors (); // Check and log OpenGL error codes + public static void rl_check_errors (); // Check and log OpenGL error codes [CCode (cname = "rlSetBlendMode")] - public static void rl_set_blend_mode (int mode); // Set blending mode + public static void rl_set_blend_mode (int mode); // Set blending mode [CCode (cname = "rlSetBlendFactors")] public static void rl_set_blend_factors (int source_factor, int desitination_factor, int equation); // Set blending mode factor and equation (using OpenGL factors) @@ -705,85 +762,86 @@ namespace Rlgl { [CCode (cname = "rlSetBlendFactorsSeparate")] public static void rl_set_blend_factors_separate (int source_rgb, int destination_rgb, int source_alpha, int desitination_alpha, int eq_rgb, int eq_alpha); // Set blending mode factors and equations separately (using OpenGL factors) - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // Functions Declaration - rlgl functionality - //------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------ // rlgl initialization functions [CCode (cname = "rlglInit")] - public static void rlgl_init (int width, int height); // Initialize rlgl (buffers, shaders, textures, states) + public static void rlgl_init (int width, int height); // Initialize rlgl (buffers, shaders, textures, states) [CCode (cname = "rlglClose")] - public static void rlgl_close (); // De-initialize rlgl (buffers, shaders, textures) + public static void rlgl_close (); // De-initialize rlgl (buffers, shaders, textures) [CCode (cname = "rlLoadExtensions")] - public static void rl_load_extensions (void* loader); // Load OpenGL extensions (loader function required) + public static void rl_load_extensions (void* loader); // Load OpenGL extensions (loader function required) + + [CCode (cname = "rlGetProcAddress")] + public static void * rl_get_proc_address (string proc_name); // Get OpenGL procedure address [CCode (cname = "rlGetVersion")] - public static int get_version (); // Get current OpenGL version + public static int get_version (); // Get current OpenGL version [CCode (cname = "rlSetFramebufferWidth")] - public static void rl_set_framebuffer_width (int width); // Set current framebuffer width + public static void rl_set_framebuffer_width (int width); // Set current framebuffer width [CCode (cname = "rlGetFramebufferWidth")] - public static int get_framebuffer_width (); // Get default framebuffer width + public static int get_framebuffer_width (); // Get default framebuffer width [CCode (cname = "rlSetFramebufferHeight")] - public static void rl_set_framebuffer_height (int height); // Set current framebuffer height + public static void rl_set_framebuffer_height (int height); // Set current framebuffer height [CCode (cname = "rlGetFramebufferHeight")] - public static int get_framebuffer_height (); // Get default framebuffer height - + public static int get_framebuffer_height (); // Get default framebuffer height [CCode (cname = "rlGetTextureIdDefault")] - public static uint get_texture_id_default (); // Get default texture id + public static uint get_texture_id_default (); // Get default texture id - [CCode (cname = "rlGetlocashader_idDefault")] - public static uint get_shader_id_default (); // Get default shader id + [CCode (cname = "rlGetShaderIdDefault")] + public static uint get_shader_id_default (); // Get default shader id - [CCode (cname = "rlGetShaderLocsDefault")] - public static int[] rl_get_shader_locations_default (); // Get default shader locations + [CCode (cname = "rlGetShaderLocsDefault", array_length = false)] + public static int[] rl_get_shader_locations_default (); // Get default shader locations // Render batch management // NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode // but this render batch API is exposed in case of custom batches are required [CCode (cname = "rlLoadRenderBatch")] - public static RenderBatch rl_load_render_batch (int buffer_count, int buffer_elements); // Load a render batch system + public static RenderBatch rl_load_render_batch (int buffer_count, int buffer_elements); // Load a render batch system [CCode (cname = "rlUnloadRenderBatch")] - public static void rl_unload_render_batch (RenderBatch batch); // Unload render batch system + public static void rl_unload_render_batch (RenderBatch batch); // Unload render batch system [CCode (cname = "rlDrawRenderBatch")] - public static void rl_draw_render_batch (RenderBatch batch); // Draw render batch data (Update->Draw->Reset) + public static void rl_draw_render_batch (RenderBatch batch); // Draw render batch data (Update->Draw->Reset) [CCode (cname = "rlSetRenderBatchActive")] - public static void rl_set_render_batch_active (RenderBatch batch); // Set the active render batch for rlgl (NULL for default internal) + public static void rl_set_render_batch_active (RenderBatch batch); // Set the active render batch for rlgl (NULL for default internal) [CCode (cname = "rlDrawRenderBatchActive")] - public static void rl_draw_render_batch_active (); // Update and draw internal render batch + public static void rl_draw_render_batch_active (); // Update and draw internal render batch [CCode (cname = "rlCheckRenderBatchLimit")] - public static bool rl_check_render_batch_limit (int vertex_count); // Check internal buffer overflow for a given number of vertex - + public static bool rl_check_render_batch_limit (int vertex_count); // Check internal buffer overflow for a given number of vertex [CCode (cname = "rlSetTexture")] - public static void rl_set_texture (uint id); // Set current texture for render batch and check buffers limits + public static void rl_set_texture (uint id); // Set current texture for render batch and check buffers limits - //------------------------------------------------------------------------------------------------------------------------ + // ------------------------------------------------------------------------------------------------------------------------ // Vertex buffers management [CCode (cname = "rlLoadVertexArray")] - public static uint load_vertex_array (); // Load vertex array (vao) if supported + public static uint load_vertex_array (); // Load vertex array (vao) if supported [CCode (cname = "rlLoadVertexBuffer")] - public static uint load_vertex_buffer (void* buffer, int size, bool is_dynamic); // Load a vertex buffer attribute + public static uint load_vertex_buffer (void* buffer, int size, bool is_dynamic); // Load a vertex buffer attribute [CCode (cname = "rlLoadVertexBufferElement")] - public static uint load_vertex_buffer_element (void* buffer, int size, bool is_dynamic); // Load a new attributes element buffer + public static uint load_vertex_buffer_element (void* buffer, int size, bool is_dynamic); // Load a new attributes element buffer [CCode (cname = "rlUpdateVertexBuffer")] - public static void rl_update_vertex_buffer (uint buffer_id, void* data, int data_size, int offset); // Update GPU buffer with new data + public static void rl_update_vertex_buffer (uint buffer_id, void* data, int data_size, int offset); // Update GPU buffer with new data [CCode (cname = "rlUpdateVertexBufferElements")] - public static void rl_update_vertex_buffer_elements (uint id, void* data, int data_size, int offset); // Update vertex buffer elements with new data + public static void rl_update_vertex_buffer_elements (uint id, void* data, int data_size, int offset); // Update vertex buffer elements with new data [CCode (cname = "rlUnloadVertexArray")] public static void rl_unload_vertex_array (uint vao_id); @@ -817,95 +875,108 @@ namespace Rlgl { public static uint rl_load_texture (void* data, int width, int height, int format, int mipmap_count); // Load texture in GPU [CCode (cname = "rlLoadTextureDepth")] - public static uint rl_load_texture_depth (int width, int height, bool use_render_buffer); // Load depth texture/renderbuffer (to be attached to fbo) + public static uint rl_load_texture_depth (int width, int height, bool use_render_buffer); // Load depth texture/renderbuffer (to be attached to fbo) [CCode (cname = "rlLoadTextureCubemap")] - public static uint rl_load_texture_cubemap (void* data, int size, int format); // Load texture cubemap + public static uint rl_load_texture_cubemap (void* data, int size, int format); // Load texture cubemap [CCode (cname = "rlUpdateTexture")] - public static void rl_update_texture (uint id, int offset_x, int offset_y, int width, int height, int format, void* data); // Update GPU texture with new data + public static void rl_update_texture (uint id, int offset_x, int offset_y, int width, int height, int format, void* data); // Update GPU texture with new data [CCode (cname = "rlGetGlTextureFormats")] - public static void rl_get_gl_texture_formats (int format, out uint gl_internal_format, out uint gl_format, out uint gl_type); // Get OpenGL internal formats + public static void rl_get_gl_texture_formats (int format, out uint gl_internal_format, out uint gl_format, out uint gl_type); // Get OpenGL internal formats [CCode (cname = "rlGetPixelFormatName")] - public static string rl_get_pixel_format_name (uint format); // Get name string for pixel format + public static string rl_get_pixel_format_name (uint format); // Get name string for pixel format [CCode (cname = "rlUnloadTexture")] - public static void rl_unload_texture (uint id); // Unload texture from GPU memory + public static void rl_unload_texture (uint id); // Unload texture from GPU memory [CCode (cname = "rlGenTextureMipmaps")] public static void rl_gen_texture_mipmaps (uint id, int width, int height, int format, out int mipmaps); // Generate mipmap data for selected texture [CCode (cname = "rlReadTexturePixels")] - public static void* rl_read_texture_pixels (uint id, int width, int height, int format); // Read texture pixel data + public static void * rl_read_texture_pixels (uint id, int width, int height, int format); // Read texture pixel data [CCode (cname = "rlReadScreenPixels")] - public static uchar[] rl_read_screen_pixels (int width, int height); // Read screen pixel data (color buffer) + public static uchar[] rl_read_screen_pixels (int width, int height); // Read screen pixel data (color buffer) // Framebuffer management (fbo) [CCode (cname = "rlLoadFramebuffer")] - public static uint rl_load_framebuffer (int width, int height); // Load an empty framebuffer + public static uint rl_load_framebuffer (int width, int height); // Load an empty framebuffer [CCode (cname = "rlFramebufferAttach")] - public static void rl_framebuffer_attach (uint fbo_id, uint texture_id, int attach_type, int texture_type, int mipmap_level); // Attach texture/renderbuffer to a framebuffer + public static void rl_framebuffer_attach (uint fbo_id, uint texture_id, int attach_type, int texture_type, int mipmap_level); // Attach texture/renderbuffer to a framebuffer [CCode (cname = "rlFramebufferComplete")] - public static bool rl_framebuffer_complete (uint id); // Verify framebuffer is complete + public static bool rl_framebuffer_complete (uint id); // Verify framebuffer is complete [CCode (cname = "rlUnloadFramebuffer")] - public static void rl_unload_framebuffer (uint id); // Delete framebuffer from GPU + public static void rl_unload_framebuffer (uint id); // Delete framebuffer from GPU - // Shaders management - [CCode (cname = "rlLoadShaderCode")] - public static uint rl_load_shader_code (string vertex_shader, string fragment_shader); // Load shader from code strings + // WARNING: Copy and resize framebuffer functionality only defined for software backend + [CCode (cname = "rlCopyFramebuffer")] + public static void rl_copy_framebuffer (int x, int y, int width, int height, int format, void *pixels); // Copy framebuffer pixel data to internal buffer + + [CCode (cname = "rlResizeFramebuffer")] + public static void rl_resize_framebuffer (int width, int height); // Resize internal framebuffer - [CCode (cname = "rlCompileShader")] - public static uint rl_compile_shader (string shader_code, int type); // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) + // Shaders management + [CCode (cname = "rlLoadShader")] + public static uint rl_load_shader (string code, int type); // Load (compile) custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) [CCode (cname = "rlLoadShaderProgram")] - public static uint rl_load_shader_program (uint vertex_shader_id, uint fragment_shader_id); // Load custom shader program + public static uint rl_load_shader_program (string vertex_shader_code, string fragment_shader_ode); // Load shader from code strings + + [CCode (cname = "rlLoadShaderProgramEx")] + public static uint rl_load_shader_program_ext (uint vertex_shader_id, uint fragment_shader_id); // Load shader program, using already loaded shader ids + + [CCode (cname = "rlLoadShaderProgramCompute")] + public static uint rl_load_shader_program_compute (uint compute_shader_id); // Load compute shader program + + [CCode (cname = "rlUnloadShader")] + public static void rl_unload_shader (uint id); // Unload shader, loaded with rl_load_shader () [CCode (cname = "rlUnloadShaderProgram")] - public static void rl_unload_shader_program (uint id); // Unload shader program + public static void rl_unload_shader_program (uint id); // Unload shader program [CCode (cname = "rlGetLocationUniform")] public static int rl_get_location_uniform (uint shader_location_id, string uniform_name); // Get shader location uniform [CCode (cname = "rlGetLocationAttrib")] - public static int rl_get_location_attribute (uint shader_location_id, string attribute_name); // Get shader location attribute + public static int rl_get_location_attribute (uint shader_location_id, string attribute_name); // Get shader location attribute [CCode (cname = "rlSetUniform")] - public static void rl_set_uniform (int location_index, void* value, int uniform_type, int count); // Set shader value uniform + public static void rl_set_uniform (int location_index, void* value, int uniform_type, int count); // Set shader value uniform [CCode (cname = "rlSetUniformMatrix")] - public static void rl_set_uniform_matrix (int location_index, Matrix matrix); // Set shader value matrix + public static void rl_set_uniform_matrix (int location_index, Matrix matrix); // Set shader value matrix + + [CCode (cname = "rlSetUniformMatrices")] + public static void rl_set_uniform_matrices (int location_index, Matrix[] matrix); // Set shader value matrices [CCode (cname = "rlSetUniformSampler")] - public static void rl_set_uniform_sampler (int location_index, uint texture_id); // Set shader value sampler + public static void rl_set_uniform_sampler (int location_index, uint texture_id); // Set shader value sampler [CCode (cname = "rlSetShader", array_length = false)] - public static void rl_set_shader (uint id, int[] locs); // Set shader currently active (id and locations) + public static void rl_set_shader (uint id, int[] locs); // Set shader currently active (id and locations) // Compute shader management - [CCode (cname = "rlLoadComputeShaderProgram")] - public static uint rl_load_compute_shader_program (uint shader_location_id); // Load compute shader program - [CCode (cname = "rlComputeShaderDispatch")] - public static void rl_compute_shader_dispatch (uint group_x, uint group_y, uint group_z); // Dispatch compute shader (equivalent to *draw* for graphics pipeline) + public static void rl_compute_shader_dispatch (uint group_x, uint group_y, uint group_z); // Dispatch compute shader (equivalent to *draw* for graphics pipeline) // Shader buffer storage object management (ssbo) [CCode (cname = "rlLoadShaderBuffer")] public static uint rl_load_shader_buffer (uint size, void* data, int usage_hint); // Load shader storage buffer object (SSBO) [CCode (cname = "rlUnloadShaderBuffer")] - public static void rl_unload_shader_buffer (uint ssbo_id); // Unload shader storage buffer object (SSBO) + public static void rl_unload_shader_buffer (uint ssbo_id); // Unload shader storage buffer object (SSBO) [CCode (cname = "rlUpdateShaderBuffer")] public static void rl_update_shader_buffer (uint id, void* data, uint data_size, uint offset); // Update SSBO buffer data [CCode (cname = "rlBindShaderBuffer")] - public static void rl_bind_shader_buffer (uint id, uint index); // Bind SSBO buffer + public static void rl_bind_shader_buffer (uint id, uint index); // Bind SSBO buffer [CCode (cname = "rlReadShaderBuffer")] public static void rl_read_shader_buffer (uint id, void* destination, uint count, uint offset); // Read SSBO buffer data (GPU->CPU) @@ -914,44 +985,44 @@ namespace Rlgl { public static void rl_copy_shader_buffer (uint destination_id, uint src_id, uint destination_offset, uint src_offset, uint count); // Copy SSBO data between buffers [CCode (cname = "rlGetShaderBufferSize")] - public static uint rl_get_shader_buffer_size (uint id); // Get SSBO buffer size + public static uint rl_get_shader_buffer_size (uint id); // Get SSBO buffer size // Buffer management [CCode (cname = "rlBindImageTexture")] - public static void rl_bind_image_texture(uint id, uint index, int format, bool is_read_only); // Bind image texture + public static void rl_bind_image_texture (uint id, uint index, int format, bool is_read_only); // Bind image texture // Matrix state management [CCode (cname = "rlGetMatrixModelview")] - public static Matrix rl_get_matrix_modelview (); // Get internal modelview matrix + public static Matrix rl_get_matrix_modelview (); // Get internal modelview matrix [CCode (cname = "rlGetMatrixProjection")] - public static Matrix rl_get_matrix_projection (); // Get internal projection matrix + public static Matrix rl_get_matrix_projection (); // Get internal projection matrix [CCode (cname = "rlGetMatrixTransform")] - public static Matrix rl_get_matrix_transform (); // Get internal accumulated transform matrix + public static Matrix rl_get_matrix_transform (); // Get internal accumulated transform matrix [CCode (cname = "rlGetMatrixProjectionStereo")] - public static Matrix rl_get_matrix_projection_stereo (int eye); // Get internal projection matrix for stereo render (selected eye) + public static Matrix rl_get_matrix_projection_stereo (int eye); // Get internal projection matrix for stereo render (selected eye) [CCode (cname = "rlGetMatrixViewOffsetStereo")] - public static Matrix rl_get_matrix_view_offset_stereo (int eye); // Get internal view offset matrix for stereo render (selected eye) + public static Matrix rl_get_matrix_view_offset_stereo (int eye); // Get internal view offset matrix for stereo render (selected eye) [CCode (cname = "rlSetMatrixProjection")] - public static void rl_set_matrix_projection (Matrix projection); // Set a custom projection matrix (replaces internal projection matrix) + public static void rl_set_matrix_projection (Matrix projection); // Set a custom projection matrix (replaces internal projection matrix) [CCode (cname = "rlSetMatrixModelview")] - public static void rl_set_matrix_modelview (Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) + public static void rl_set_matrix_modelview (Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) [CCode (cname = "rlSetMatrixProjectionStereo")] - public static void rl_set_matrix_projection_stereo (Matrix right, Matrix left); // Set eyes projection matrices for stereo rendering + public static void rl_set_matrix_projection_stereo (Matrix right, Matrix left); // Set eyes projection matrices for stereo rendering [CCode (cname = "rlSetMatrixViewOffsetStereo")] - public static void rl_set_matrix_view_offset_stereo (Matrix right, Matrix left); // Set eyes view offsets matrices for stereo rendering + public static void rl_set_matrix_view_offset_stereo (Matrix right, Matrix left); // Set eyes view offsets matrices for stereo rendering // Quick and dirty cube/quad buffers load->draw->unload [CCode (cname = "rlLoadDrawCube")] - public static void rl_load_draw_cube (); // Load and draw a cube + public static void rl_load_draw_cube (); // Load and draw a cube [CCode (cname = "rlLoadDrawQuad")] - public static void rl_load_draw_quad (); // Load and draw a quad + public static void rl_load_draw_quad (); // Load and draw a quad }