From 8e04b7098af58c36d9b8cb9ed84eca3d47f1d048 Mon Sep 17 00:00:00 2001 From: Nikolas Date: Fri, 3 Apr 2026 18:13:05 +0200 Subject: [PATCH] Bump raylib/zig versions --- .gitignore | 2 + build.zig | 3 + build.zig.zon | 10 +- lib/generate_functions.py | 1 + lib/preludes/raygui-prelude.zig | 43 +- lib/preludes/raylib-prelude.zig | 56 +- lib/preludes/raymath-prelude.zig | 2 +- lib/preludes/rlgl-prelude.zig | 10 +- lib/raygui-ext.zig | 4 +- lib/raygui.h | 655 +++++++++++++----------- lib/raygui.zig | 43 +- lib/raylib-ext.zig | 26 +- lib/raylib.h | 216 ++++---- lib/raylib.zig | 177 ++++--- lib/raymath-ext.zig | 2 + lib/raymath.h | 236 +++++++-- lib/raymath.zig | 10 +- lib/rlgl-ext.zig | 15 +- lib/rlgl.h | 842 ++++++++++++++++--------------- lib/rlgl.zig | 57 ++- 20 files changed, 1383 insertions(+), 1027 deletions(-) diff --git a/.gitignore b/.gitignore index 3c99eaa..613eaff 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ zig-cache/ .zig-cache/ zig-out/ +zig-pkg/ + .idea/ Project/* libraylib.a diff --git a/build.zig b/build.zig index 768800e..85aaf35 100644 --- a/build.zig +++ b/build.zig @@ -39,6 +39,7 @@ fn getRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.buil const raygui_dep = b.dependency("raygui", .{ .target = target, .optimize = optimize, + .link_libc = true, }); rl.addRaygui(b, raylib, raygui_dep, options); @@ -55,6 +56,7 @@ fn getModule(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.buil .root_source_file = b.path("lib/raylib.zig"), .target = target, .optimize = optimize, + .link_libc = true, }); } @@ -66,6 +68,7 @@ const gui = struct { .imports = &.{.{ .name = "raylib-zig", .module = raylib }}, .target = target, .optimize = optimize, + .link_libc = true, }); } }; diff --git a/build.zig.zon b/build.zig.zon index c1f7c03..93eacf1 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -4,12 +4,12 @@ .fingerprint = 0xc4cfa8c610114f28, .dependencies = .{ .raylib = .{ - .url = "git+https://github.com/raysan5/raylib#9f831428e6be0eba8762a154e3e9139d4f071970", - .hash = "raylib-5.6.0-dev-whq8uL592gQ782dF95oci4S61qrNVYK3MhpUpNwFgZ1J", + .url = "git+https://github.com/raysan5/raylib#f36533cbd8feead845a2e0b4568ec0484a15cd10", + .hash = "raylib-5.6.0-dev-whq8uGJqKQUEDd38DCov-XG29PYzw3kM_LNbPUkcDGyM", }, .raygui = .{ - .url = "git+https://github.com/raysan5/raygui#9cdfec460b43a17264af3c181c46f62bf107ac17", - .hash = "N-V-__8AALUbbwDKkSH4nbf3Ml_dTWo9qbELvle5i9eQZMuo", + .url = "git+https://github.com/raysan5/raygui#3b2855842ab578a034f827c38cf8f62c042fc983", + .hash = "N-V-__8AAHvybwBw1kyBGn0BW_s1RqIpycNjLf_XbE-fpLUF", }, .emsdk = .{ .url = "git+https://github.com/emscripten-core/emsdk#4.0.9", @@ -20,7 +20,7 @@ .hash = "zemscripten-0.2.0-dev-sRlDqFJSAAB8hgnRt5DDMKP3zLlDtMnUDwYRJVCa5lGY", }, }, - .minimum_zig_version = "0.15.1", + .minimum_zig_version = "0.16.0-dev.3070+b22eb176b", .paths = .{ "build.zig", "build.zig.zon", diff --git a/lib/generate_functions.py b/lib/generate_functions.py index 55e3ef5..a1899e5 100755 --- a/lib/generate_functions.py +++ b/lib/generate_functions.py @@ -75,6 +75,7 @@ MANUAL = [ "ComputeCRC32", "ComputeMD5", "ComputeSHA1", + "ComputeSHA256", "SetWindowIcons", "CheckCollisionPointPoly", "ColorToInt", diff --git a/lib/preludes/raygui-prelude.zig b/lib/preludes/raygui-prelude.zig index 83924cd..8426fd6 100644 --- a/lib/preludes/raygui-prelude.zig +++ b/lib/preludes/raygui-prelude.zig @@ -4,7 +4,7 @@ const std = @import("std"); pub const cdef = @import("raygui-ext.zig"); test { - std.testing.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); } pub const RayguiError = error{GetIcons}; @@ -120,6 +120,7 @@ pub const SliderProperty = enum(c_int) { pub const ProgressBarProperty = enum(c_int) { progress_padding = 16, + progress_side, }; pub const ScrollBarProperty = enum(c_int) { @@ -411,22 +412,22 @@ pub const IconName = enum(c_int) { slicing = 231, manual_control = 232, collision = 233, - icon_234 = 234, - icon_235 = 235, - icon_236 = 236, - icon_237 = 237, - icon_238 = 238, - icon_239 = 239, - icon_240 = 240, - icon_241 = 241, - icon_242 = 242, - icon_243 = 243, - icon_244 = 244, - icon_245 = 245, - icon_246 = 246, - icon_247 = 247, - icon_248 = 248, - icon_249 = 249, + circle_add = 234, + circle_add_fill = 235, + circle_warning = 236, + circle_warning_fill = 237, + box_more = 238, + box_more_fill = 239, + box_minus = 240, + box_minus_fill = 241, + union_ = 242, + intersection = 243, + difference = 244, + sphere = 245, + cylinder = 246, + cone = 247, + ellipsoid = 248, + capsule = 249, icon_250 = 250, icon_251 = 251, icon_252 = 252, @@ -472,13 +473,13 @@ pub fn loadIcons(fileName: [*c]const u8, loadIconsName: bool) [*c][*c]u8 { } /// Tab Bar control, returns TAB to be closed or -1 -pub fn tabBar(bounds: Rectangle, text: [][*:0]const u8, active: *i32) i32 { - return @as(i32, cdef.GuiTabBar(bounds, @as([*c][*c]const u8, @ptrCast(text)), @as(c_int, @intCast(text.len)), @as([*c]c_int, @ptrCast(active)))); +pub fn tabBar(bounds: Rectangle, text: [][*:0]u8, active: *i32) i32 { + return @as(i32, cdef.GuiTabBar(bounds, @as([*c][*c]u8, @ptrCast(text)), @as(c_int, @intCast(text.len)), @as([*c]c_int, @ptrCast(active)))); } /// List View with extended parameters -pub fn listViewEx(bounds: Rectangle, text: [][*:0]const u8, scrollIndex: *i32, active: *i32, focus: *i32) i32 { - return @as(i32, cdef.GuiListViewEx(bounds, @as([*c][*c]const u8, @ptrCast(text)), @as(c_int, @intCast(text.len)), @as([*c]c_int, @ptrCast(scrollIndex)), @as([*c]c_int, @ptrCast(active)), @as([*c]c_int, @ptrCast(focus)))); +pub fn listViewEx(bounds: Rectangle, text: [][*:0]u8, scrollIndex: *i32, active: *i32, focus: *i32) i32 { + return @as(i32, cdef.GuiListViewEx(bounds, @as([*c][*c]u8, @ptrCast(text)), @as(c_int, @intCast(text.len)), @as([*c]c_int, @ptrCast(scrollIndex)), @as([*c]c_int, @ptrCast(active)), @as([*c]c_int, @ptrCast(focus)))); } /// Panel control, useful to group controls diff --git a/lib/preludes/raylib-prelude.zig b/lib/preludes/raylib-prelude.zig index 7185884..905316f 100644 --- a/lib/preludes/raylib-prelude.zig +++ b/lib/preludes/raylib-prelude.zig @@ -11,7 +11,7 @@ pub const math = @import("raymath.zig"); const C = std.builtin.CallingConvention.c; test { - std.testing.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); } pub const RaylibError = error{ @@ -1401,6 +1401,8 @@ pub const Camera2D = extern struct { pub const Mesh = extern struct { vertexCount: c_int, triangleCount: c_int, + + // Vertex attributes data vertices: [*c]f32, texcoords: [*c]f32, texcoords2: [*c]f32, @@ -1408,12 +1410,18 @@ pub const Mesh = extern struct { tangents: [*c]f32, colors: [*c]u8, indices: [*c]c_ushort, + + // Skin data for animation + boneCount: c_int, + boneIndices: [*c]u16, + boneWeights: [*c]f32, + + // Runtime animation vertex data (CPU skinning) + // NOTE: In case of GPU skinning, not used, pointers are NULL animVertices: [*c]f32, animNormals: [*c]f32, - boneIds: [*c]u8, - boneWeights: [*c]f32, - boneMatrices: [*c]Matrix, - boneCount: c_int, + + // OpenGL identifiers vaoId: c_int, vboId: [*c]c_int, @@ -1476,11 +1484,19 @@ pub const Transform = extern struct { scale: Vector3, }; +pub const ModelAnimPose = [*c]Transform; + pub const BoneInfo = extern struct { name: [32]u8, parent: c_int, }; +pub const ModelSkeleton = extern struct { + boneCount: c_int, + bones: [*c]BoneInfo, + bindPose: ModelAnimPose +}; + pub const Model = extern struct { transform: Matrix, meshCount: c_int, @@ -1488,9 +1504,11 @@ pub const Model = extern struct { meshes: [*c]Mesh, materials: [*c]Material, meshMaterial: [*c]c_int, - boneCount: c_int, - bones: [*c]BoneInfo, - bindPose: [*c]Transform, + + // Animation data + skeleton: ModelSkeleton, + currentPose: ModelAnimPose, + boneMatrices: [*c]Matrix, /// Load model from file (meshes and materials) pub fn init(fileName: [:0]const u8) RaylibError!Model { @@ -1529,12 +1547,12 @@ pub const Model = extern struct { }; pub const ModelAnimation = extern struct { - boneCount: c_int, - frameCount: c_int, - bones: [*c]BoneInfo, - framePoses: [*c][*c]Transform, name: [32]u8, + boneCount: c_int, + keyframeCount: c_int, + keyframePoses: [*c]ModelAnimPose, + /// Unload animation data pub fn unload(self: ModelAnimation) void { rl.unloadModelAnimation(self); @@ -1640,7 +1658,6 @@ pub const VrStereoConfig = extern struct { }; pub const FilePathList = extern struct { - capacity: c_uint, count: c_uint, paths: [*c][*c]u8, }; @@ -1662,7 +1679,7 @@ pub const AutomationEventList = extern struct { } }; -pub const ConfigFlags = packed struct { +pub const ConfigFlags = packed struct(u32) { __reserved: bool = false, fullscreen_mode: bool = false, window_resizable: bool = false, @@ -1918,8 +1935,8 @@ pub const ShaderLocationIndex = enum(c_int) { map_brdf = 25, vertex_boneids = 26, vertex_boneweights = 27, - bone_matrices = 28, - shader_loc_vertex_instance_tx = 29, + matrix_bonetransforms = 28, + matrix_instancetransforms = 29, // }; @@ -2010,7 +2027,7 @@ pub const BlendMode = enum(c_int) { custom_separate = 7, }; -pub const Gesture = packed struct { +pub const Gesture = packed struct(u16) { tap: bool = false, doubletap: bool = false, hold: bool = false, @@ -2138,6 +2155,11 @@ pub fn computeSHA1(data: []u8) [5]u32 { return res[0..5].*; } +pub fn computeSHA256(data: []u8) [8]u32 { + const res: [*]c_uint = cdef.ComputeSHA256(@as([*c]u8, @ptrCast(data)), @as(c_int, @intCast(data.len))); + return res[0..8].*; +} + /// Load image from file into CPU memory (RAM) pub fn loadImage(fileName: [:0]const u8) RaylibError!Image { const image = cdef.LoadImage(@as([*c]const u8, @ptrCast(fileName))); diff --git a/lib/preludes/raymath-prelude.zig b/lib/preludes/raymath-prelude.zig index c92eb7e..7d762f2 100644 --- a/lib/preludes/raymath-prelude.zig +++ b/lib/preludes/raymath-prelude.zig @@ -6,7 +6,7 @@ const std = @import("std"); pub const cdef = @import("raymath-ext.zig"); test { - std.testing.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); } const Matrix = rl.Matrix; diff --git a/lib/preludes/rlgl-prelude.zig b/lib/preludes/rlgl-prelude.zig index db93589..6cc08d6 100644 --- a/lib/preludes/rlgl-prelude.zig +++ b/lib/preludes/rlgl-prelude.zig @@ -6,7 +6,7 @@ const std = @import("std"); pub const cdef = @import("rlgl-ext.zig"); test { - std.testing.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); } const Matrix = rl.Matrix; @@ -39,7 +39,7 @@ pub const rlRenderBatch = extern struct { }; pub const rlGlVersion = enum(c_int) { - rl_opengl_11_software = 0, + rl_opengl_software = 0, rl_opengl_11 = 1, rl_opengl_21 = 2, rl_opengl_33 = 3, @@ -268,6 +268,6 @@ pub const rl_default_shader_attrib_location_color = @as(i32, 3); pub const rl_default_shader_attrib_location_tangent = @as(i32, 4); pub const rl_default_shader_attrib_location_texcoord2 = @as(i32, 5); pub const rl_default_shader_attrib_location_indices = @as(i32, 6); -pub const rl_default_shader_attrib_location_boneids = @as(i32, 7); -pub const rl_default_shader_attrib_location_boneweights = @as(i32, 5); -pub const rl_default_shader_attrib_location_instance_tx = @as(i32, 9); +pub const rl_default_shader_attrib_location_boneindices = @as(i32, 7); +pub const rl_default_shader_attrib_location_boneweights = @as(i32, 8); +pub const rl_default_shader_attrib_location_instancetransform = @as(i32, 9); diff --git a/lib/raygui-ext.zig b/lib/raygui-ext.zig index f2b35e0..80a063f 100644 --- a/lib/raygui-ext.zig +++ b/lib/raygui-ext.zig @@ -30,7 +30,7 @@ pub extern "c" fn GuiWindowBox(bounds: rl.Rectangle, title: [*c]const u8) c_int; pub extern "c" fn GuiGroupBox(bounds: rl.Rectangle, text: [*c]const u8) c_int; pub extern "c" fn GuiLine(bounds: rl.Rectangle, text: [*c]const u8) c_int; pub extern "c" fn GuiPanel(bounds: rl.Rectangle, text: [*c]const u8) c_int; -pub extern "c" fn GuiTabBar(bounds: rl.Rectangle, text: [*c][*c]const u8, count: c_int, active: [*c]c_int) c_int; +pub extern "c" fn GuiTabBar(bounds: rl.Rectangle, text: [*c][*c]u8, count: c_int, active: [*c]c_int) c_int; pub extern "c" fn GuiScrollPanel(bounds: rl.Rectangle, text: [*c]const u8, content: rl.Rectangle, scroll: [*c]rl.Vector2, view: [*c]rl.Rectangle) c_int; pub extern "c" fn GuiLabel(bounds: rl.Rectangle, text: [*c]const u8) c_int; pub extern "c" fn GuiButton(bounds: rl.Rectangle, text: [*c]const u8) c_int; @@ -52,7 +52,7 @@ pub extern "c" fn GuiStatusBar(bounds: rl.Rectangle, text: [*c]const u8) c_int; pub extern "c" fn GuiDummyRec(bounds: rl.Rectangle, text: [*c]const u8) c_int; pub extern "c" fn GuiGrid(bounds: rl.Rectangle, text: [*c]const u8, spacing: f32, subdivs: c_int, mouseCell: [*c]rl.Vector2) c_int; pub extern "c" fn GuiListView(bounds: rl.Rectangle, text: [*c]const u8, scrollIndex: [*c]c_int, active: [*c]c_int) c_int; -pub extern "c" fn GuiListViewEx(bounds: rl.Rectangle, text: [*c][*c]const u8, count: c_int, scrollIndex: [*c]c_int, active: [*c]c_int, focus: [*c]c_int) c_int; +pub extern "c" fn GuiListViewEx(bounds: rl.Rectangle, text: [*c][*c]u8, count: c_int, scrollIndex: [*c]c_int, active: [*c]c_int, focus: [*c]c_int) c_int; pub extern "c" fn GuiMessageBox(bounds: rl.Rectangle, title: [*c]const u8, message: [*c]const u8, buttons: [*c]const u8) c_int; pub extern "c" fn GuiTextInputBox(bounds: rl.Rectangle, title: [*c]const u8, message: [*c]const u8, buttons: [*c]const u8, text: [*c]u8, textMaxSize: c_int, secretViewActive: [*c]bool) c_int; pub extern "c" fn GuiColorPicker(bounds: rl.Rectangle, text: [*c]const u8, color: [*c]rl.Color) c_int; diff --git a/lib/raygui.h b/lib/raygui.h index 68b6f25..72f7108 100644 --- a/lib/raygui.h +++ b/lib/raygui.h @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raygui v4.5-dev - A simple and easy-to-use immediate-mode gui library +* 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 @@ -77,14 +77,14 @@ * * static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)]; * -* guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB +* 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 set we have the EXTENDED properties (by default guiStyle[16..23]), those -* properties are actually common to all controls and can not be overwritten individually (like BASE ones) +* 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. @@ -141,13 +141,14 @@ * Draw text bounds rectangles for debug * * VERSIONS HISTORY: -* 5.0-dev (2025) Current dev version... +* 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 @@ -165,6 +166,7 @@ * 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() @@ -271,7 +273,7 @@ * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria * * DEPENDENCIES: -* raylib 5.0 - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* 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 @@ -316,7 +318,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5) +* 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. @@ -351,9 +353,12 @@ // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll #if defined(_WIN32) #if defined(BUILD_LIBTYPE_SHARED) - #define RAYGUIAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) + #define RAYGUIAPI __declspec(dllexport) // Building the library as a Win32 shared library (.dll) #elif defined(USE_LIBTYPE_SHARED) - #define RAYGUIAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) + #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 @@ -369,9 +374,48 @@ // 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__) + #define RAYGUI_LOG(...) printf(__VA_ARGS__) #else - #define RAYGUI_LOG(...) + #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 //---------------------------------------------------------------------------------- @@ -567,7 +611,7 @@ typedef enum { //---------------------------------------------------------------------------------- // DEFAULT extended properties // NOTE: Those properties are common to all controls or global -// WARNING: We only have 8 slots for those properties by default!!! -> New global control: TEXT? +// 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 @@ -604,6 +648,7 @@ typedef enum { // ProgressBar typedef enum { PROGRESS_PADDING = 16, // ProgressBar internal padding + PROGRESS_SIDE, // ProgressBar increment side: 0-left->right, 1-right-left } GuiProgressBarProperty; // ScrollBar @@ -730,7 +775,7 @@ RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls -RAYGUIAPI int GuiTabBar(Rectangle bounds, const char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1 +RAYGUIAPI int 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 @@ -758,7 +803,7 @@ RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int sub // Advance controls set RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control -RAYGUIAPI int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters +RAYGUIAPI int 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) @@ -1010,28 +1055,28 @@ typedef enum { ICON_SLICING = 231, ICON_MANUAL_CONTROL = 232, ICON_COLLISION = 233, - ICON_234 = 234, - ICON_235 = 235, - ICON_236 = 236, - ICON_237 = 237, - ICON_238 = 238, - ICON_239 = 239, - ICON_240 = 240, - ICON_241 = 241, - ICON_242 = 242, - ICON_243 = 243, - ICON_244 = 244, - ICON_245 = 245, - ICON_246 = 246, - ICON_247 = 247, - ICON_248 = 248, - ICON_249 = 249, + ICON_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, + ICON_255 = 255 } GuiIconName; #endif @@ -1051,11 +1096,11 @@ typedef enum { #if defined(RAYGUI_IMPLEMENTATION) -#include // required for: isspace() [GuiTextBox()] #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) @@ -1078,7 +1123,7 @@ typedef enum { // Check if two rectangles are equal, used to validate a slider bounds as an id #ifndef CHECK_BOUNDS_ID - #define CHECK_BOUNDS_ID(src, dst) ((src.x == dst.x) && (src.y == dst.y) && (src.width == dst.width) && (src.height == dst.height)) + #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) @@ -1091,7 +1136,7 @@ typedef enum { // 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) +// 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) @@ -1341,22 +1386,22 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = 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 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_234 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_235 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_236 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_237 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_238 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_239 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_240 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_241 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_242 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_243 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_244 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_245 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_246 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_247 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_248 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_249 + 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 @@ -1450,12 +1495,12 @@ static bool IsMouseButtonReleased(int button); static bool IsKeyDown(int key); static bool IsKeyPressed(int key); -static int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() +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 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() //------------------------------------------------------------------------------- @@ -1484,7 +1529,7 @@ static Color GetColor(int hexValue); // Returns a Color struct fr static int ColorToInt(Color color); // Returns hexadecimal value for a Color static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' -static const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings +static 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 @@ -1499,32 +1544,32 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) +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); // Gui draw text using default font -static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style -static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings +static 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 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 +static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor //---------------------------------------------------------------------------------- // Gui Setup Functions Definition //---------------------------------------------------------------------------------- // Enable gui global state -// NOTE: We check for STATE_DISABLED to avoid messing custom global state setups +// 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: We check for STATE_NORMAL to avoid messing custom global state setups +// 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 @@ -1557,9 +1602,8 @@ void GuiSetFont(Font font) { if (font.texture.id > 0) { - // NOTE: If we try to setup a font but default style has not been - // lazily loaded before, it will be overwritten, so we need to force - // default style loading first + // 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; @@ -1613,13 +1657,14 @@ int GuiWindowBox(Rectangle bounds, const char *title) //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 - 1, bounds.width, bounds.height - (float)statusBarHeight + 1 }; - Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT - vPadding, + 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 @@ -1629,8 +1674,8 @@ int GuiWindowBox(Rectangle bounds, const char *title) // Draw control //-------------------------------------------------------------------- - GuiStatusBar(statusBar, title); // Draw window header as status bar 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); @@ -1741,9 +1786,9 @@ int GuiPanel(Rectangle bounds, const char *text) // Tab Bar control // NOTE: Using GuiToggle() for the TABS -int GuiTabBar(Rectangle bounds, const char **text, int count, int *active) +int GuiTabBar(Rectangle bounds, char **text, int count, int *active) { - #define RAYGUI_TABBAR_ITEM_WIDTH 160 + #define RAYGUI_TABBAR_ITEM_WIDTH 148 int result = -1; //GuiState state = guiState; @@ -1776,17 +1821,17 @@ int GuiTabBar(Rectangle bounds, const char **text, int count, int *active) if (i == (*active)) { toggle = true; - GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle); + GuiToggle(tabBounds, text[i], &toggle); } else { toggle = false; - GuiToggle(tabBounds, GuiIconText(12, text[i]), &toggle); + GuiToggle(tabBounds, text[i], &toggle); if (toggle) *active = i; } // Close tab with middle mouse button pressed - if (CheckCollisionPointRec(GetMousePosition(), tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; + if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); @@ -1885,37 +1930,37 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; // Check button state if (CheckCollisionPointRec(mousePoint, bounds)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; #if defined(SUPPORT_SCROLLBAR_KEY_INPUT) if (hasHorizontalScrollBar) { - if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (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 (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + 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 wheelMove = GetMouseWheelMove(); + float scrollDelta = GUI_SCROLL_DELTA; // Set scrolling speed with mouse wheel based on ratio between bounds and content - Vector2 mouseWheelSpeed = { content.width/bounds.width, content.height/bounds.height }; - if (mouseWheelSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED; - if (mouseWheelSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) mouseWheelSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + 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 && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_LEFT_SHIFT))) scrollPos.x += wheelMove*mouseWheelSpeed.x; - else scrollPos.y += wheelMove*mouseWheelSpeed.y; // Vertical scroll + 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 } } @@ -2001,15 +2046,15 @@ int GuiButton(Rectangle bounds, const char *text) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; // Check button state if (CheckCollisionPointRec(mousePoint, bounds)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1; + if (GUI_BUTTON_RELEASED) result = 1; } } //-------------------------------------------------------------------- @@ -2031,7 +2076,7 @@ int GuiLabelButton(Rectangle bounds, const char *text) GuiState state = guiState; bool pressed = false; - // NOTE: We force bounds.width to be all text + // 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; @@ -2039,15 +2084,15 @@ int GuiLabelButton(Rectangle bounds, const char *text) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; // Check checkbox state if (CheckCollisionPointRec(mousePoint, bounds)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true; + if (GUI_BUTTON_RELEASED) pressed = true; } } //-------------------------------------------------------------------- @@ -2073,13 +2118,13 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; // Check toggle button state if (CheckCollisionPointRec(mousePoint, bounds)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else if (GUI_BUTTON_RELEASED) { state = STATE_NORMAL; *active = !(*active); @@ -2126,7 +2171,7 @@ int GuiToggleGroup(Rectangle bounds, const char *text, int *active) // Get substrings items from text (items pointers) int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 }; int itemCount = 0; - const char **items = GuiTextSplit(text, ';', &itemCount, rows); + char **items = GuiTextSplit(text, ';', &itemCount, rows); int prevRow = rows[0]; @@ -2170,7 +2215,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) // Get substrings items from text (items pointers) int itemCount = 0; - const char **items = NULL; + char **items = NULL; if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); @@ -2184,12 +2229,12 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; if (CheckCollisionPointRec(mousePoint, bounds)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; - else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else if (GUI_BUTTON_RELEASED) { state = STATE_PRESSED; (*active)++; @@ -2255,7 +2300,7 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; Rectangle totalBounds = { (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT)? textBounds.x : bounds.x, @@ -2267,10 +2312,10 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) // Check checkbox state if (CheckCollisionPointRec(mousePoint, totalBounds)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_RELEASED) { *checked = !(*checked); result = 1; @@ -2314,7 +2359,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - const char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount, NULL); if (*active < 0) *active = 0; else if (*active > (itemCount - 1)) *active = itemCount - 1; @@ -2323,18 +2368,18 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) { - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_PRESSED) { *active += 1; if (*active >= itemCount) *active = 0; // Cyclic combobox } - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; } } @@ -2380,7 +2425,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - const char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount, NULL); Rectangle boundsOpen = bounds; boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); @@ -2392,7 +2437,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; if (editMode) { @@ -2401,11 +2446,11 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod // Check if mouse has been pressed or released outside limits if (!CheckCollisionPointRec(mousePoint, boundsOpen)) { - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) result = 1; + if (GUI_BUTTON_PRESSED || GUI_BUTTON_RELEASED) result = 1; } // Check if already selected item has been pressed again - if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1; + if (CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED) result = 1; // Check focused and selected item for (int i = 0; i < itemCount; i++) @@ -2417,7 +2462,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod if (CheckCollisionPointRec(mousePoint, itemBounds)) { itemFocused = i; - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_RELEASED) { itemSelected = i; result = 1; // Item selected @@ -2432,7 +2477,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod { if (CheckCollisionPointRec(mousePoint, bounds)) { - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_PRESSED) { result = 1; state = STATE_PRESSED; @@ -2497,16 +2542,16 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) - #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 30 // Frames to wait for autocursor movement + #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 2 // Frames delay for autocursor movement + #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 + bool multiline = false; // TODO: Consider multiline text input int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); @@ -2514,7 +2559,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) 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 + int textIndexOffset = 0; // Text index offset to start drawing in the box // Cursor rectangle // NOTE: Position X value should be updated @@ -2547,13 +2592,13 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) !guiControlExclusiveMode && // No gui slider on dragging (wrapMode == TEXT_WRAP_NONE)) // No wrap mode { - Vector2 mousePosition = GetMousePosition(); + 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 (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_UP) || IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_BACKSPACE) || IsKeyDown(KEY_DELETE)) autoCursorCounter++; + 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); @@ -2563,7 +2608,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; // If text does not fit in the textbox and current cursor position is out of bounds, - // we add an index offset to text for drawing only what requires depending on cursor + // adding an index offset to text for drawing only what requires depending on cursor while (textWidth >= textBounds.width) { int nextCodepointSize = 0; @@ -2574,15 +2619,15 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textWidth = GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex); } - int codepoint = GetCharPressed(); // Get Unicode codepoint - if (multiline && IsKeyPressed(KEY_ENTER)) codepoint = (int)'\n'; + 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 Paste action - if (IsKeyPressed(KEY_V) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) + // 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) @@ -2590,7 +2635,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) int pasteLength = 0; int pasteCodepoint; int pasteCodepointSize; - // count how many codepoints to copy, stopping at the first unwanted control character + + // Count how many codepoints to copy, stopping at the first unwanted control character while (true) { pasteCodepoint = GetCodepointNext(pasteText + pasteLength, &pasteCodepointSize); @@ -2598,6 +2644,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) if (!(multiline && (pasteCodepoint == (int)'\n')) && !(pasteCodepoint >= 32)) break; pasteLength += pasteCodepointSize; } + if (pasteLength > 0) { // Move forward data from cursor position @@ -2612,10 +2659,10 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) } } } - // Add codepoint to text, at current cursor position - // NOTE: Make sure we do not overflow buffer size 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]; @@ -2630,18 +2677,19 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) } // Move cursor to start - if ((textLength > 0) && IsKeyPressed(KEY_HOME)) textBoxCursorIndex = 0; + if ((textLength > 0) && GUI_KEY_PRESSED(KEY_HOME)) textBoxCursorIndex = 0; // Move cursor to end - if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_END)) textBoxCursorIndex = textLength; + if ((textLength > textBoxCursorIndex) && GUI_KEY_PRESSED(KEY_END)) textBoxCursorIndex = textLength; // Delete related codepoints from text, after current cursor position - if ((textLength > textBoxCursorIndex) && IsKeyPressed(KEY_DELETE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) + 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); @@ -2654,11 +2702,12 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) accCodepointSize += nextCodepointSize; nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); } + // Check whitespace to delete (ASCII only) while (offset < textLength) { - if (!isspace(nextCodepoint & 0xff)) - break; + if (!isspace(nextCodepoint & 0xff)) break; + offset += nextCodepointSize; accCodepointSize += nextCodepointSize; nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); @@ -2669,9 +2718,10 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= accCodepointSize; } - // Delete single codepoint from text, after current cursor position - else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_DELETE) || (IsKeyDown(KEY_DELETE) && autoCursorShouldTrigger))) + 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); @@ -2682,12 +2732,12 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) } // Delete related codepoints from text, before current cursor position - if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_BACKSPACE) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) + 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; - int prevCodepoint; + int prevCodepointSize = 0; + int prevCodepoint = 0; // Check whitespace to delete (ASCII only) while (offset > 0) @@ -2698,6 +2748,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) 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); @@ -2716,9 +2767,10 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= accCodepointSize; textBoxCursorIndex -= accCodepointSize; } - // Delete single codepoint from text, before current cursor position - else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_BACKSPACE) || (IsKeyDown(KEY_BACKSPACE) && autoCursorShouldTrigger))) + 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); @@ -2731,12 +2783,12 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) } // Move cursor position with keys - if ((textBoxCursorIndex > 0) && IsKeyPressed(KEY_LEFT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) + 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; - int prevCodepoint; + //int accCodepointSize = 0; + int prevCodepointSize = 0; + int prevCodepoint = 0; // Check whitespace to skip (ASCII only) while (offset > 0) @@ -2745,7 +2797,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) if (!isspace(prevCodepoint & 0xff)) break; offset -= prevCodepointSize; - accCodepointSize += prevCodepointSize; + //accCodepointSize += prevCodepointSize; } // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace) @@ -2757,22 +2809,22 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; offset -= prevCodepointSize; - accCodepointSize += prevCodepointSize; + //accCodepointSize += prevCodepointSize; } textBoxCursorIndex = offset; } - else if ((textBoxCursorIndex > 0) && (IsKeyPressed(KEY_LEFT) || (IsKeyDown(KEY_LEFT) && autoCursorShouldTrigger))) + 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) && IsKeyPressed(KEY_RIGHT) && (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL))) + 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 accCodepointSize = 0; int nextCodepointSize; int nextCodepoint; @@ -2785,7 +2837,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; offset += nextCodepointSize; - accCodepointSize += nextCodepointSize; + //accCodepointSize += nextCodepointSize; nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); } @@ -2795,13 +2847,13 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) if (!isspace(nextCodepoint & 0xff)) break; offset += nextCodepointSize; - accCodepointSize += nextCodepointSize; + //accCodepointSize += nextCodepointSize; nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); } textBoxCursorIndex = offset; } - else if ((textLength > textBoxCursorIndex) && (IsKeyPressed(KEY_RIGHT) || (IsKeyDown(KEY_RIGHT) && autoCursorShouldTrigger))) + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_RIGHT) || (GUI_KEY_DOWN(KEY_RIGHT) && autoCursorShouldTrigger))) { int nextCodepointSize = 0; GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); @@ -2838,14 +2890,14 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) // Check if mouse cursor is at the last position int textEndWidth = GuiGetTextWidth(text + textIndexOffset); - if (GetMousePosition().x >= (textBounds.x + textEndWidth - glyphWidth/2)) + 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) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + if ((mouseCursor.x >= 0) && GUI_BUTTON_PRESSED) { cursor.x = mouseCursor.x; textBoxCursorIndex = mouseCursorIndex; @@ -2858,8 +2910,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) //if (multiline) cursor.y = GetTextLines() // Finish text editing on ENTER or mouse click outside bounds - if ((!multiline && IsKeyPressed(KEY_ENTER)) || - (!CheckCollisionPointRec(mousePosition, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + 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 @@ -2872,7 +2924,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { state = STATE_FOCUSED; - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_PRESSED) { textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes @@ -2966,12 +3018,12 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; // Check spinner state if (CheckCollisionPointRec(mousePoint, bounds)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; } } @@ -3024,7 +3076,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in int result = 0; GuiState state = guiState; - char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; + char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 }; snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); Rectangle textBounds = { 0 }; @@ -3041,8 +3093,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); - + Vector2 mousePoint = GUI_POINTER_POSITION; bool valueHasChanged = false; if (editMode) @@ -3052,18 +3103,16 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in int keyCount = (int)strlen(textValue); // Add or remove minus symbol - if (IsKeyPressed(KEY_MINUS)) + if (GUI_KEY_PRESSED(KEY_MINUS)) { if (textValue[0] == '-') { - for (int i = 0 ; i < keyCount; i++) - { - textValue[i] = textValue[i + 1]; - } + for (int i = 0 ; i < keyCount; i++) textValue[i] = textValue[i + 1]; + keyCount--; valueHasChanged = true; } - else if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS -1) + else if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) { if (keyCount == 0) { @@ -3080,39 +3129,35 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in } } - // Only allow keys in range [48..57] - if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) + // Add new digit to text value + if ((keyCount >= 0) && (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) && (GuiGetTextWidth(textValue) < bounds.width)) { - if (GuiGetTextWidth(textValue) < bounds.width) - { - int key = GetCharPressed(); - if ((key >= 48) && (key <= 57)) - { - textValue[keyCount] = (char)key; - keyCount++; - valueHasChanged = true; - } - } - } + int key = GUI_INPUT_KEY; - // Delete text - if (keyCount > 0) - { - if (IsKeyPressed(KEY_BACKSPACE)) + // Only allow keys in range [48..57] + if ((key >= 48) && (key <= 57)) { - keyCount--; - textValue[keyCount] = '\0'; + 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: We are not clamp values until user input finishes + // NOTE: Values are not clamped until user input finishes //if (*value > maxValue) *value = maxValue; //else if (*value < minValue) *value = minValue; - if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + if ((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; @@ -3128,7 +3173,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1; + if (GUI_BUTTON_PRESSED) result = 1; } } } @@ -3189,7 +3234,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; bool valueHasChanged = false; @@ -3200,30 +3245,29 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float int keyCount = (int)strlen(textValue); // Add or remove minus symbol - if (IsKeyPressed(KEY_MINUS)) + if (GUI_KEY_PRESSED(KEY_MINUS)) { if (textValue[0] == '-') { - for (int i = 0; i < keyCount; i++) + for (int i = 0; i < keyCount; i++) textValue[i] = textValue[i + 1]; + + keyCount--; + valueHasChanged = true; + } + else if (keyCount < (RAYGUI_VALUEBOX_MAX_CHARS - 1)) { - 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'; + 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++; - } - for (int i = keyCount; i > -1; i--) - { - textValue[i + 1] = textValue[i]; - } - textValue[0] = '-'; - keyCount++; - valueHasChanged = true; + valueHasChanged = true; } } @@ -3232,7 +3276,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float { if (GuiGetTextWidth(textValue) < bounds.width) { - int key = GetCharPressed(); + int key = GUI_INPUT_KEY; if (((key >= 48) && (key <= 57)) || (key == '.') || ((keyCount == 0) && (key == '+')) || // NOTE: Sign can only be in first position @@ -3247,7 +3291,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float } // Pressed backspace - if (IsKeyPressed(KEY_BACKSPACE)) + if (GUI_KEY_PRESSED(KEY_BACKSPACE)) { if (keyCount > 0) { @@ -3259,14 +3303,14 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float if (valueHasChanged) *value = TextToFloat(textValue); - if ((IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) result = 1; + 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 (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) result = 1; + if (GUI_BUTTON_PRESSED) result = 1; } } } @@ -3320,11 +3364,11 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_DOWN) { if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) { @@ -3341,7 +3385,7 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo } else if (CheckCollisionPointRec(mousePoint, bounds)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_DOWN) { state = STATE_PRESSED; guiControlExclusiveMode = true; @@ -3479,7 +3523,15 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight } // Draw slider internal progress bar (depends on state) - GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED))); + 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 @@ -3534,12 +3586,12 @@ int GuiDummyRec(Rectangle bounds, const char *text) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; // Check button state if (CheckCollisionPointRec(mousePoint, bounds)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = STATE_PRESSED; + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; } } @@ -3559,7 +3611,7 @@ int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *activ { int result = 0; int itemCount = 0; - const char **items = NULL; + char **items = NULL; if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); @@ -3569,7 +3621,7 @@ int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *activ } // List View control with extended parameters -int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollIndex, int *active, int *focus) +int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus) { int result = 0; GuiState state = guiState; @@ -3577,7 +3629,7 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd int itemFocused = (focus == NULL)? -1 : *focus; int itemSelected = (active == NULL)? -1 : *active; - // Check if we need a scroll bar + // 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; @@ -3601,7 +3653,7 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; // Check mouse inside list view if (CheckCollisionPointRec(mousePoint, bounds)) @@ -3614,7 +3666,7 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd if (CheckCollisionPointRec(mousePoint, itemBounds)) { itemFocused = startIndex + i; - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_PRESSED) { if (itemSelected == (startIndex + i)) itemSelected = -1; else itemSelected = startIndex + i; @@ -3628,8 +3680,8 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd if (useScrollBar) { - int wheelMove = (int)GetMouseWheelMove(); - startIndex -= wheelMove; + float scrollDelta = GUI_SCROLL_DELTA; + startIndex -= (int)scrollDelta; if (startIndex < 0) startIndex = 0; else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; @@ -3658,7 +3710,7 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd { 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED))); + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED))); } else { @@ -3666,18 +3718,18 @@ int GuiListViewEx(Rectangle bounds, const char **text, int count, int *scrollInd { // 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_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: We want items focused, despite not returned! + 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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_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(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL))); + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL))); } } @@ -3764,11 +3816,11 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_DOWN) { if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) { @@ -3787,7 +3839,7 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) } else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_DOWN) { state = STATE_PRESSED; guiControlExclusiveMode = true; @@ -3849,11 +3901,11 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_DOWN) { if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) { @@ -3872,7 +3924,7 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) } else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_DOWN) { state = STATE_PRESSED; guiControlExclusiveMode = true; @@ -3885,12 +3937,12 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) } else state = STATE_FOCUSED; - /*if (IsKeyDown(KEY_UP)) + /*if (GUI_KEY_DOWN(KEY_UP)) { hue -= 2.0f; if (hue <= 0.0f) hue = 0.0f; } - else if (IsKeyDown(KEY_DOWN)) + else if (GUI_KEY_DOWN(KEY_DOWN)) { hue += 2.0f; if (hue >= 360.0f) hue = 360.0f; @@ -4007,11 +4059,11 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_DOWN) { if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) { @@ -4041,7 +4093,7 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) } else if (CheckCollisionPointRec(mousePoint, bounds)) { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_DOWN) { state = STATE_PRESSED; guiControlExclusiveMode = true; @@ -4097,7 +4149,7 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button int buttonCount = 0; - const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + 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; @@ -4156,7 +4208,7 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co int result = -1; int buttonCount = 0; - const char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + 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; @@ -4197,6 +4249,9 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); } + int prevTextBoxAlignment = GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT); + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + if (secretViewActive != NULL) { static char stars[] = "****************"; @@ -4210,6 +4265,8 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co 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); @@ -4230,7 +4287,7 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co // Grid control // NOTE: Returns grid mouse-hover selected cell // About drawing lines at subpixel spacing, simple put, not easy solution: -// https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster +// 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 @@ -4241,7 +4298,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect int result = 0; GuiState state = guiState; - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; Vector2 currentMouseCell = { -1, -1 }; float spaceWidth = spacing/(float)subdivs; @@ -4409,11 +4466,14 @@ void GuiLoadStyle(const char *fileName) if (fileDataSize > 0) { unsigned char *fileData = (unsigned char *)RAYGUI_CALLOC(fileDataSize, sizeof(unsigned char)); - fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile); + if (fileData != NULL) + { + fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile); - GuiLoadStyleFromMemory(fileData, fileDataSize); + GuiLoadStyleFromMemory(fileData, fileDataSize); - RAYGUI_FREE(fileData); + RAYGUI_FREE(fileData); + } } fclose(rgsFile); @@ -4424,7 +4484,7 @@ void GuiLoadStyle(const char *fileName) // Load style default over global style void GuiLoadStyleDefault(void) { - // We set this variable first to avoid cyclic function calls + // Setting this flag first to avoid cyclic function calls // when calling GuiSetStyle() and GuiGetStyle() guiStyleLoaded = true; @@ -4453,7 +4513,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property - GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 15); // DEFAULT, 15 pixels between lines + GuiSetStyle(DEFAULT, TEXT_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 @@ -4519,7 +4579,7 @@ void GuiLoadStyleDefault(void) // NOTE: Default raylib font character 95 is a white square Rectangle whiteChar = guiFont.recs[95]; - // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering + // 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 }); } } @@ -5036,14 +5096,14 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) } // Get text icon if provided and move text cursor -// NOTE: We support up to 999 values for iconId +// 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 we have an icon! + 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' + char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' int pos = 1; while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) @@ -5075,28 +5135,20 @@ static const char **GetTextLines(const char *text, int *count) static const char *lines[RAYGUI_MAX_TEXT_LINES] = { 0 }; for (int i = 0; i < RAYGUI_MAX_TEXT_LINES; i++) lines[i] = NULL; // Init NULL pointers to substrings - int textSize = (int)strlen(text); + int textLength = (int)strlen(text); lines[0] = text; - int len = 0; *count = 1; - //int lineSize = 0; // Stores current line size, not returned - for (int i = 0, k = 0; (i < textSize) && (*count < RAYGUI_MAX_TEXT_LINES); i++) + for (int i = 0; (i < textLength) && (*count < RAYGUI_MAX_TEXT_LINES); i++) { - if (text[i] == '\n') + if ((text[i] == '\n') && ((i + 1) < textLength)) { - //lineSize = len; - k++; - lines[k] = &text[i + 1]; // WARNING: next value is valid? - len = 0; + lines[*count] = &text[i + 1]; *count += 1; } - else len++; } - //lines[*count - 1].size = len; - return lines; } @@ -5147,7 +5199,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // - For every line, wordwrap mode is checked (useful for GuitextBox(), read-only) // Get text lines (using '\n' as delimiter) to be processed individually - // WARNING: We can't use GuiTextSplit() function because it can be already used + // 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); @@ -5158,7 +5210,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); // Wrap-mode only available in read-only mode, no for text editing // TODO: WARNING: This totalHeight is not valid for vertical alignment in case of word-wrap - float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_SIZE)/2); + float 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++) @@ -5171,7 +5223,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; float textBoundsWidthOffset = 0.0f; - // NOTE: We get text size after icon has been processed + // 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]); @@ -5206,8 +5258,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C default: break; } - // NOTE: Make sure we get pixel-perfect coordinates, - // In case of decimals we got weird text positioning + // 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); //--------------------------------------------------------------------------------- @@ -5217,7 +5269,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C #if !defined(RAYGUI_NO_ICONS) if (iconId >= 0) { - // NOTE: We consider icon height, probably different than text size + // 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); @@ -5243,8 +5295,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C int codepoint = GetCodepointNext(&lines[i][c], &codepointSize); int index = GetGlyphIndex(guiFont, codepoint); - // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) - // but we need to draw all of the bad bytes using the '?' symbol moving one byte + // 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 @@ -5259,7 +5311,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset) { textOffsetX = 0.0f; - textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); + textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); if (tempWrapCharMode) // Wrap at char level when too long words { @@ -5288,7 +5340,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset) { textOffsetX = 0.0f; - textOffsetY += GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); + textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); } } @@ -5338,8 +5390,9 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } } - if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING); - else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + if (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)); //--------------------------------------------------------------------------------- } @@ -5380,13 +5433,19 @@ static void GuiTooltip(Rectangle controlRec) if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); - GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, NULL); + 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, GuiGetStyle(DEFAULT, TEXT_SIZE) + 8.0f }, guiTooltipPtr); + 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); } @@ -5394,7 +5453,7 @@ static void GuiTooltip(Rectangle controlRec) // Split controls text into multiple strings // Also check for multiple columns (required by GuiToggleGroup()) -static const char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow) +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, @@ -5413,8 +5472,8 @@ static const char **GuiTextSplit(const char *text, char delimiter, int *count, i #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 #endif - static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data) - static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) + 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; @@ -5422,7 +5481,7 @@ static const char **GuiTextSplit(const char *text, char delimiter, int *count, i if (textRow != NULL) textRow[0] = 0; - // Count how many substrings we have on text and point to every one + // 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]; @@ -5643,11 +5702,11 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) //-------------------------------------------------------------------- if ((state != STATE_DISABLED) && !guiLocked) { - Vector2 mousePoint = GetMousePosition(); + Vector2 mousePoint = GUI_POINTER_POSITION; if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) && + if (GUI_BUTTON_DOWN && !CheckCollisionPointRec(mousePoint, arrowUpLeft) && !CheckCollisionPointRec(mousePoint, arrowDownRight)) { @@ -5670,11 +5729,11 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) state = STATE_FOCUSED; // Handle mouse wheel - int wheel = (int)GetMouseWheelMove(); - if (wheel != 0) value += wheel; + float scrollDelta = GUI_SCROLL_DELTA; + if (scrollDelta != 0) value += (int)scrollDelta; // Handle mouse button down - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + if (GUI_BUTTON_PRESSED) { guiControlExclusiveMode = true; guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts @@ -5696,13 +5755,13 @@ static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) /* if (isVertical) { - if (IsKeyDown(KEY_DOWN)) value += 5; - else if (IsKeyDown(KEY_UP)) value -= 5; + if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; + else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; } else { - if (IsKeyDown(KEY_RIGHT)) value += 5; - else if (IsKeyDown(KEY_LEFT)) value -= 5; + if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; + else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; } */ } @@ -5813,7 +5872,7 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co } // Split string into multiple strings -const char **TextSplit(const char *text, char delimiter, int *count) +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, @@ -5839,7 +5898,7 @@ const char **TextSplit(const char *text, char delimiter, int *count) { counter = 1; - // Count how many substrings we have on text and point to every one + // 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]; @@ -5872,7 +5931,7 @@ static int TextToInteger(const char *text) text++; } - for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0'); + for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0'); return value*sign; } @@ -5947,9 +6006,9 @@ static const char *CodepointToUTF8(int codepoint, int *byteSize) } // Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found -// When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned +// 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 +// 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) { diff --git a/lib/raygui.zig b/lib/raygui.zig index 837089d..55ed6c4 100644 --- a/lib/raygui.zig +++ b/lib/raygui.zig @@ -4,7 +4,7 @@ const std = @import("std"); pub const cdef = @import("raygui-ext.zig"); test { - std.testing.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); } pub const RayguiError = error{GetIcons}; @@ -120,6 +120,7 @@ pub const SliderProperty = enum(c_int) { pub const ProgressBarProperty = enum(c_int) { progress_padding = 16, + progress_side, }; pub const ScrollBarProperty = enum(c_int) { @@ -411,22 +412,22 @@ pub const IconName = enum(c_int) { slicing = 231, manual_control = 232, collision = 233, - icon_234 = 234, - icon_235 = 235, - icon_236 = 236, - icon_237 = 237, - icon_238 = 238, - icon_239 = 239, - icon_240 = 240, - icon_241 = 241, - icon_242 = 242, - icon_243 = 243, - icon_244 = 244, - icon_245 = 245, - icon_246 = 246, - icon_247 = 247, - icon_248 = 248, - icon_249 = 249, + circle_add = 234, + circle_add_fill = 235, + circle_warning = 236, + circle_warning_fill = 237, + box_more = 238, + box_more_fill = 239, + box_minus = 240, + box_minus_fill = 241, + union_ = 242, + intersection = 243, + difference = 244, + sphere = 245, + cylinder = 246, + cone = 247, + ellipsoid = 248, + capsule = 249, icon_250 = 250, icon_251 = 251, icon_252 = 252, @@ -472,13 +473,13 @@ pub fn loadIcons(fileName: [*c]const u8, loadIconsName: bool) [*c][*c]u8 { } /// Tab Bar control, returns TAB to be closed or -1 -pub fn tabBar(bounds: Rectangle, text: [][*:0]const u8, active: *i32) i32 { - return @as(i32, cdef.GuiTabBar(bounds, @as([*c][*c]const u8, @ptrCast(text)), @as(c_int, @intCast(text.len)), @as([*c]c_int, @ptrCast(active)))); +pub fn tabBar(bounds: Rectangle, text: [][*:0]u8, active: *i32) i32 { + return @as(i32, cdef.GuiTabBar(bounds, @as([*c][*c]u8, @ptrCast(text)), @as(c_int, @intCast(text.len)), @as([*c]c_int, @ptrCast(active)))); } /// List View with extended parameters -pub fn listViewEx(bounds: Rectangle, text: [][*:0]const u8, scrollIndex: *i32, active: *i32, focus: *i32) i32 { - return @as(i32, cdef.GuiListViewEx(bounds, @as([*c][*c]const u8, @ptrCast(text)), @as(c_int, @intCast(text.len)), @as([*c]c_int, @ptrCast(scrollIndex)), @as([*c]c_int, @ptrCast(active)), @as([*c]c_int, @ptrCast(focus)))); +pub fn listViewEx(bounds: Rectangle, text: [][*:0]u8, scrollIndex: *i32, active: *i32, focus: *i32) i32 { + return @as(i32, cdef.GuiListViewEx(bounds, @as([*c][*c]u8, @ptrCast(text)), @as(c_int, @intCast(text.len)), @as([*c]c_int, @ptrCast(scrollIndex)), @as([*c]c_int, @ptrCast(active)), @as([*c]c_int, @ptrCast(focus)))); } /// Panel control, useful to group controls diff --git a/lib/raylib-ext.zig b/lib/raylib-ext.zig index 3b89bc5..39acb82 100644 --- a/lib/raylib-ext.zig +++ b/lib/raylib-ext.zig @@ -108,15 +108,11 @@ pub extern "c" fn UnloadRandomSequence(sequence: [*c]c_int) void; pub extern "c" fn TakeScreenshot(fileName: [*c]const u8) void; pub extern "c" fn SetConfigFlags(flags: rl.ConfigFlags) void; pub extern "c" fn OpenURL(url: [*c]const u8) void; -pub extern "c" fn TraceLog(logLevel: rl.TraceLogLevel, text: [*c]const u8, ...) void; pub extern "c" fn SetTraceLogLevel(logLevel: rl.TraceLogLevel) void; +pub extern "c" fn TraceLog(logLevel: rl.TraceLogLevel, text: [*c]const u8, ...) void; pub extern "c" fn MemAlloc(size: c_uint) *anyopaque; pub extern "c" fn MemRealloc(ptr: *anyopaque, size: c_uint) *anyopaque; pub extern "c" fn MemFree(ptr: *anyopaque) void; -pub extern "c" fn SetLoadFileDataCallback(callback: rl.LoadFileDataCallback) void; -pub extern "c" fn SetSaveFileDataCallback(callback: rl.SaveFileDataCallback) void; -pub extern "c" fn SetLoadFileTextCallback(callback: rl.LoadFileTextCallback) void; -pub extern "c" fn SetSaveFileTextCallback(callback: rl.SaveFileTextCallback) void; pub extern "c" fn LoadFileData(fileName: [*c]const u8, dataSize: [*c]c_int) [*c]u8; pub extern "c" fn UnloadFileData(data: [*c]u8) void; pub extern "c" fn SaveFileData(fileName: [*c]const u8, data: *anyopaque, dataSize: c_int) bool; @@ -124,6 +120,10 @@ pub extern "c" fn ExportDataAsCode(data: [*c]const u8, dataSize: c_int, fileName pub extern "c" fn LoadFileText(fileName: [*c]const u8) [*c]u8; pub extern "c" fn UnloadFileText(text: [*c]u8) void; pub extern "c" fn SaveFileText(fileName: [*c]const u8, text: [*c]const u8) bool; +pub extern "c" fn SetLoadFileDataCallback(callback: rl.LoadFileDataCallback) void; +pub extern "c" fn SetSaveFileDataCallback(callback: rl.SaveFileDataCallback) void; +pub extern "c" fn SetLoadFileTextCallback(callback: rl.LoadFileTextCallback) void; +pub extern "c" fn SetSaveFileTextCallback(callback: rl.SaveFileTextCallback) void; pub extern "c" fn FileRename(fileName: [*c]const u8, fileRename_: [*c]const u8) c_int; pub extern "c" fn FileRemove(fileName: [*c]const u8) c_int; pub extern "c" fn FileCopy(srcPath: [*c]const u8, dstPath: [*c]const u8) c_int; @@ -143,7 +143,7 @@ pub extern "c" fn GetPrevDirectoryPath(dirPath: [*c]const u8) [*c]const u8; pub extern "c" fn GetWorkingDirectory() [*c]const u8; pub extern "c" fn GetApplicationDirectory() [*c]const u8; pub extern "c" fn MakeDirectory(dirPath: [*c]const u8) c_int; -pub extern "c" fn ChangeDirectory(dir: [*c]const u8) bool; +pub extern "c" fn ChangeDirectory(dirPath: [*c]const u8) bool; pub extern "c" fn IsPathFile(path: [*c]const u8) bool; pub extern "c" fn IsFileNameValid(fileName: [*c]const u8) bool; pub extern "c" fn LoadDirectoryFiles(dirPath: [*c]const u8) rl.FilePathList; @@ -152,6 +152,8 @@ pub extern "c" fn UnloadDirectoryFiles(files: rl.FilePathList) void; pub extern "c" fn IsFileDropped() bool; pub extern "c" fn LoadDroppedFiles() rl.FilePathList; pub extern "c" fn UnloadDroppedFiles(files: rl.FilePathList) void; +pub extern "c" fn GetDirectoryFileCount(dirPath: [*c]const u8) c_uint; +pub extern "c" fn GetDirectoryFileCountEx(basePath: [*c]const u8, filter: [*c]const u8, scanSubdirs: bool) c_uint; pub extern "c" fn CompressData(data: [*c]const u8, dataSize: c_int, compDataSize: [*c]c_int) [*c]u8; pub extern "c" fn DecompressData(compData: [*c]const u8, compDataSize: c_int, dataSize: [*c]c_int) [*c]u8; pub extern "c" fn EncodeDataBase64(data: [*c]const u8, dataSize: c_int, outputSize: [*c]c_int) [*c]u8; @@ -159,6 +161,7 @@ pub extern "c" fn DecodeDataBase64(text: [*c]const u8, outputSize: [*c]c_int) [* pub extern "c" fn ComputeCRC32(data: [*c]u8, dataSize: c_int) c_uint; pub extern "c" fn ComputeMD5(data: [*c]u8, dataSize: c_int) [*c]c_uint; pub extern "c" fn ComputeSHA1(data: [*c]u8, dataSize: c_int) [*c]c_uint; +pub extern "c" fn ComputeSHA256(data: [*c]u8, dataSize: c_int) [*c]c_uint; pub extern "c" fn LoadAutomationEventList(fileName: [*c]const u8) rl.AutomationEventList; pub extern "c" fn UnloadAutomationEventList(list: rl.AutomationEventList) void; pub extern "c" fn ExportAutomationEventList(list: rl.AutomationEventList, fileName: [*c]const u8) bool; @@ -420,6 +423,7 @@ pub extern "c" fn DrawTextCodepoints(font: rl.Font, codepoints: [*c]const c_int, pub extern "c" fn SetTextLineSpacing(spacing: c_int) void; pub extern "c" fn MeasureText(text: [*c]const u8, fontSize: c_int) c_int; pub extern "c" fn MeasureTextEx(font: rl.Font, text: [*c]const u8, fontSize: f32, spacing: f32) rl.Vector2; +pub extern "c" fn MeasureTextCodepoints(font: rl.Font, codepoints: [*c]const c_int, length: c_int, fontSize: f32, spacing: f32) rl.Vector2; pub extern "c" fn GetGlyphIndex(font: rl.Font, codepoint: c_int) c_int; pub extern "c" fn GetGlyphInfo(font: rl.Font, codepoint: c_int) rl.GlyphInfo; pub extern "c" fn GetGlyphAtlasRec(font: rl.Font, codepoint: c_int) rl.Rectangle; @@ -442,8 +446,11 @@ pub extern "c" fn TextSubtext(text: [*c]const u8, position: c_int, length: c_int pub extern "c" fn TextRemoveSpaces(text: [*c]const u8) [*c]const u8; pub extern "c" fn GetTextBetween(text: [*c]const u8, begin: [*c]const u8, end: [*c]const u8) [*c]u8; pub extern "c" fn TextReplace(text: [*c]const u8, search: [*c]const u8, replacement: [*c]const u8) [*c]u8; +pub extern "c" fn TextReplaceAlloc(text: [*c]const u8, search: [*c]const u8, replacement: [*c]const u8) [*c]u8; pub extern "c" fn TextReplaceBetween(text: [*c]const u8, begin: [*c]const u8, end: [*c]const u8, replacement: [*c]const u8) [*c]u8; +pub extern "c" fn TextReplaceBetweenAlloc(text: [*c]const u8, begin: [*c]const u8, end: [*c]const u8, replacement: [*c]const u8) [*c]u8; pub extern "c" fn TextInsert(text: [*c]const u8, insert: [*c]const u8, position: c_int) [*c]u8; +pub extern "c" fn TextInsertAlloc(text: [*c]const u8, insert: [*c]const u8, position: c_int) [*c]u8; pub extern "c" fn TextJoin(textList: [*c][*c]u8, count: c_int, delimiter: [*c]const u8) [*c]u8; pub extern "c" fn TextSplit(text: [*c]const u8, delimiter: u8, count: [*c]c_int) [*c][*c]u8; pub extern "c" fn TextAppend(text: [*c]u8, append: [*c]const u8, position: [*c]c_int) void; @@ -485,8 +492,6 @@ pub extern "c" fn DrawModel(model: rl.Model, position: rl.Vector3, scale: f32, t pub extern "c" fn DrawModelEx(model: rl.Model, position: rl.Vector3, rotationAxis: rl.Vector3, rotationAngle: f32, scale: rl.Vector3, tint: rl.Color) void; pub extern "c" fn DrawModelWires(model: rl.Model, position: rl.Vector3, scale: f32, tint: rl.Color) void; pub extern "c" fn DrawModelWiresEx(model: rl.Model, position: rl.Vector3, rotationAxis: rl.Vector3, rotationAngle: f32, scale: rl.Vector3, tint: rl.Color) void; -pub extern "c" fn DrawModelPoints(model: rl.Model, position: rl.Vector3, scale: f32, tint: rl.Color) void; -pub extern "c" fn DrawModelPointsEx(model: rl.Model, position: rl.Vector3, rotationAxis: rl.Vector3, rotationAngle: f32, scale: rl.Vector3, tint: rl.Color) void; pub extern "c" fn DrawBoundingBox(box: rl.BoundingBox, color: rl.Color) void; pub extern "c" fn DrawBillboard(camera: rl.Camera, texture: rl.Texture2D, position: rl.Vector3, scale: f32, tint: rl.Color) void; pub extern "c" fn DrawBillboardRec(camera: rl.Camera, texture: rl.Texture2D, source: rl.Rectangle, position: rl.Vector3, size: rl.Vector2, tint: rl.Color) void; @@ -518,9 +523,8 @@ pub extern "c" fn UnloadMaterial(material: rl.Material) void; pub extern "c" fn SetMaterialTexture(material: [*c]rl.Material, mapType: rl.MaterialMapIndex, texture: rl.Texture2D) void; pub extern "c" fn SetModelMeshMaterial(model: [*c]rl.Model, meshId: c_int, materialId: c_int) void; pub extern "c" fn LoadModelAnimations(fileName: [*c]const u8, animCount: [*c]c_int) [*c]rl.ModelAnimation; -pub extern "c" fn UpdateModelAnimation(model: rl.Model, anim: rl.ModelAnimation, frame: c_int) void; -pub extern "c" fn UpdateModelAnimationBones(model: rl.Model, anim: rl.ModelAnimation, frame: c_int) void; -pub extern "c" fn UnloadModelAnimation(anim: rl.ModelAnimation) void; +pub extern "c" fn UpdateModelAnimation(model: rl.Model, anim: rl.ModelAnimation, frame: f32) void; +pub extern "c" fn UpdateModelAnimationEx(model: rl.Model, animA: rl.ModelAnimation, frameA: f32, animB: rl.ModelAnimation, frameB: f32, blend: f32) void; pub extern "c" fn UnloadModelAnimations(animations: [*c]rl.ModelAnimation, animCount: c_int) void; pub extern "c" fn IsModelAnimationValid(model: rl.Model, anim: rl.ModelAnimation) bool; pub extern "c" fn CheckCollisionSpheres(center1: rl.Vector3, radius1: f32, center2: rl.Vector3, radius2: f32) bool; diff --git a/lib/raylib.h b/lib/raylib.h index c57efc2..c6aad86 100644 --- a/lib/raylib.h +++ b/lib/raylib.h @@ -1,16 +1,16 @@ /********************************************************************************************** * -* raylib v5.6-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) +* raylib v6.0 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) * * FEATURES: * - NO external dependencies, all required libraries included with raylib -* - Multiplatform: Windows, Linux, FreeBSD, OpenBSD, NetBSD, DragonFly, -* MacOS, Haiku, Android, Raspberry Pi, DRM native, HTML5 +* - Multiplatform: Windows, Linux, macOS, FreeBSD, Web, Android, Raspberry Pi, DRM native... * - Written in plain C code (C99) in PascalCase/camelCase notation * - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3, ES2, ES3 - choose at compile) -* - Unique OpenGL abstraction layer (usable as standalone module): [rlgl] +* - Software renderer optional, for systems with no GPU: [rlsw] +* - Custom OpenGL abstraction layer (usable as standalone module): [rlgl] * - Multiple Fonts formats supported (TTF, OTF, FNT, BDF, Sprite fonts) -* - Outstanding texture formats support, including compressed formats (DXT, ETC, ASTC) +* - Many texture formats supportted, including compressed formats (DXT, ETC, ASTC) * - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more! * - Flexible Materials system, supporting classic maps and PBR maps * - Animated 3D models supported (skeletal bones animation) (IQM, M3D, GLTF) @@ -26,14 +26,12 @@ * - One default Shader is loaded on rlglInit()->rlLoadShaderDefault() [rlgl] (OpenGL 3.3 or ES2) * - One default RenderBatch is loaded on rlglInit()->rlLoadRenderBatch() [rlgl] (OpenGL 3.3 or ES2) * -* DEPENDENCIES (included): -* [rcore][GLFW] rglfw (Camilla Löwy - github.com/glfw/glfw) for window/context management and input -* [rcore][RGFW] rgfw (ColleagueRiley - github.com/ColleagueRiley/RGFW) for window/context management and input -* [rlgl] glad/glad_gles2 (David Herberth - github.com/Dav1dde/glad) for OpenGL 3.3 extensions loading +* DEPENDENCIES: +* [rcore] Depends on the selected platform backend, check rcore.c header for details +* [rlgl] glad/glad_gles2 (David Herberth - github.com/Dav1dde/glad) for OpenGL extensions loading * [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management * * OPTIONAL DEPENDENCIES (included): -* [rcore] msf_gif (Miles Fogle) for GIF recording * [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm * [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm * [rcore] rprand (Ramon Santamaria) for pseudo-random numbers generation @@ -42,6 +40,7 @@ * [rtextures] stb_image_write (Sean Barret) for image writing (BMP, TGA, PNG, JPG) * [rtextures] stb_image_resize2 (Sean Barret) for image resizing algorithms * [rtextures] stb_perlin (Sean Barret) for Perlin Noise image generation +* [rtextures] rltexgpu (Ramon Santamaria) for GPU-compressed texture formats * [rtext] stb_truetype (Sean Barret) for ttf fonts loading * [rtext] stb_rect_pack (Sean Barret) for rectangles packing * [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation @@ -63,7 +62,7 @@ * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: * -* Copyright (c) 2013-2025 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-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. @@ -87,10 +86,10 @@ #include // Required for: va_list - Only used by TraceLogCallback -#define RAYLIB_VERSION_MAJOR 5 -#define RAYLIB_VERSION_MINOR 6 +#define RAYLIB_VERSION_MAJOR 6 +#define RAYLIB_VERSION_MINOR 0 #define RAYLIB_VERSION_PATCH 0 -#define RAYLIB_VERSION "5.6-dev" +#define RAYLIB_VERSION "6.0" // Function specifiers in case library is build/used as a shared library // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll @@ -100,13 +99,13 @@ #define __declspec(x) __attribute__((x)) #endif #if defined(BUILD_LIBTYPE_SHARED) - #define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) + #define RLAPI __declspec(dllexport) // Building the library as a Win32 shared library (.dll) #elif defined(USE_LIBTYPE_SHARED) - #define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) + #define RLAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) #endif #else #if defined(BUILD_LIBTYPE_SHARED) - #define RLAPI __attribute__((visibility("default"))) // We are building as a Unix shared library (.so/.dylib) + #define RLAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib) #endif #endif @@ -158,10 +157,10 @@ #error "C++11 or later is required. Add -std=c++11" #endif -// NOTE: We set some defines with some data types declared by raylib +// NOTE: Set some defines with some data types declared by raylib // Other modules (raymath, rlgl) also require some of those types, so, // to be able to use those other modules as standalone (not depending on raylib) -// this defines are very useful for internal check and avoid type (re)definitions +// this defines are useful for internal check and avoid type (re)definitions #define RL_COLOR_TYPE #define RL_RECTANGLE_TYPE #define RL_VECTOR2_TYPE @@ -335,10 +334,10 @@ typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D // Camera2D, defines position/orientation in 2d space typedef struct Camera2D { - Vector2 offset; // Camera offset (displacement from target) - Vector2 target; // Camera target (rotation and zoom origin) - float rotation; // Camera rotation in degrees - float zoom; // Camera zoom (scaling), should be 1.0f by default + Vector2 offset; // Camera offset (screen space offset from window origin) + Vector2 target; // Camera target (world space target point that is mapped to screen space offset) + float rotation; // Camera rotation in degrees (pivots around target) + float zoom; // Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale } Camera2D; // Mesh, vertex data and vao/vbo @@ -352,16 +351,18 @@ typedef struct Mesh { float *texcoords2; // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5) float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) - unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) - unsigned short *indices; // Vertex indices (in case vertex data comes indexed) + unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) + unsigned short *indices; // Vertex indices (in case vertex data comes indexed) - // Animation vertex data + // Skin data for animation + int boneCount; // Number of bones (MAX: 256 bones) + unsigned char *boneIndices; // Vertex bone indices, up to 4 bones influence by vertex (skinning) (shader-location = 6) + float *boneWeights; // 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 float *animVertices; // Animated vertex positions (after bones transformations) float *animNormals; // Animated normals (after bones transformations) - unsigned char *boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6) - float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7) - Matrix *boneMatrices; // Bones animated transformation matrices - int boneCount; // Number of bones // OpenGL identifiers unsigned int vaoId; // OpenGL Vertex Array Object id @@ -395,12 +396,22 @@ typedef struct Transform { Vector3 scale; // Scale } Transform; +// Anim pose, an array of Transform[] +typedef Transform *ModelAnimPose; + // Bone, skeletal animation bone typedef struct BoneInfo { char name[32]; // Bone name int parent; // Bone parent } BoneInfo; +// Skeleton, animation bones hierarchy +typedef struct ModelSkeleton { + int boneCount; // Number of bones + BoneInfo *bones; // Bones information (skeleton) + ModelAnimPose bindPose; // Bones base transformation (Transform[]) +} ModelSkeleton; + // Model, meshes, materials and animation data typedef struct Model { Matrix transform; // Local transform matrix @@ -412,18 +423,20 @@ typedef struct Model { int *meshMaterial; // Mesh material number // Animation data - int boneCount; // Number of bones - BoneInfo *bones; // Bones information (skeleton) - Transform *bindPose; // Bones base transformation (pose) + ModelSkeleton skeleton; // Skeleton for animation + + // Runtime animation data (CPU/GPU skinning) + ModelAnimPose currentPose; // Current animation pose (Transform[]) + Matrix *boneMatrices; // Bones animated transformation matrices } Model; -// ModelAnimation +// ModelAnimation, contains a full animation sequence typedef struct ModelAnimation { - int boneCount; // Number of bones - int frameCount; // Number of animation frames - BoneInfo *bones; // Bones information (skeleton) - Transform **framePoses; // Poses array by frame char name[32]; // Animation name + + int boneCount; // Number of bones (per pose) + int keyframeCount; // Number of animation key frames + ModelAnimPose *keyframePoses; // Animation sequence keyframe poses [keyframe][pose] } ModelAnimation; // Ray, ray for raycasting @@ -513,7 +526,6 @@ typedef struct VrStereoConfig { // File path list typedef struct FilePathList { - unsigned int capacity; // Filepaths max entries unsigned int count; // Filepaths entries count char **paths; // Filepaths entries } FilePathList; @@ -571,8 +583,7 @@ typedef enum { } TraceLogLevel; // Keyboard keys (US keyboard layout) -// NOTE: Use GetKeyPressed() to allow redefining -// required keys for alternative layouts +// NOTE: Use GetKeyPressed() to allow redefining required keys for alternative layouts typedef enum { KEY_NULL = 0, // Key: NULL, used for no key pressed // Alphanumeric keys @@ -723,7 +734,7 @@ typedef enum { // Gamepad buttons typedef enum { - GAMEPAD_BUTTON_UNKNOWN = 0, // Unknown button, just for error checking + GAMEPAD_BUTTON_UNKNOWN = 0, // Unknown button, for error checking GAMEPAD_BUTTON_LEFT_FACE_UP, // Gamepad left DPAD up button GAMEPAD_BUTTON_LEFT_FACE_RIGHT, // Gamepad left DPAD right button GAMEPAD_BUTTON_LEFT_FACE_DOWN, // Gamepad left DPAD down button @@ -772,6 +783,8 @@ typedef enum { #define MATERIAL_MAP_SPECULAR MATERIAL_MAP_METALNESS // Shader location index +// NOTE: Some locations are tried to be set automatically on shader loading, +// but only if default attributes/uniforms names are found, check config.h for names typedef enum { SHADER_LOC_VERTEX_POSITION = 0, // Shader location: vertex attribute: position SHADER_LOC_VERTEX_TEXCOORD01, // Shader location: vertex attribute: texcoord01 @@ -794,15 +807,15 @@ typedef enum { 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_HEIGHT, // Shader location: sampler2d texture: heightmap 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 - SHADER_LOC_VERTEX_BONEIDS, // Shader location: vertex attribute: boneIds - SHADER_LOC_VERTEX_BONEWEIGHTS, // Shader location: vertex attribute: boneWeights - SHADER_LOC_BONE_MATRICES, // Shader location: array of matrices uniform: boneMatrices - SHADER_LOC_VERTEX_INSTANCE_TX // Shader location: vertex attribute: instanceTransform + SHADER_LOC_VERTEX_BONEIDS, // Shader location: vertex attribute: bone indices + SHADER_LOC_VERTEX_BONEWEIGHTS, // Shader location: vertex attribute: bone weights + SHADER_LOC_MATRIX_BONETRANSFORMS, // Shader location: matrix attribute: bone transforms (animation) + SHADER_LOC_VERTEX_INSTANCETRANSFORM // Shader location: vertex attribute: instance transforms } ShaderLocationIndex; #define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO @@ -866,7 +879,7 @@ typedef enum { // NOTE 1: Filtering considers mipmaps if available in the texture // NOTE 2: Filter is accordingly set for minification and magnification typedef enum { - TEXTURE_FILTER_POINT = 0, // No filter, just pixel approximation + TEXTURE_FILTER_POINT = 0, // No filter, pixel approximation TEXTURE_FILTER_BILINEAR, // Linear filtering TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x @@ -1076,47 +1089,41 @@ RLAPI Matrix GetCameraMatrix(Camera camera); // Get c RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Get camera 2d transform matrix // Timing-related functions -RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) -RLAPI float GetFrameTime(void); // Get time in seconds for last frame drawn (delta time) -RLAPI double GetTime(void); // Get elapsed time in seconds since InitWindow() -RLAPI int GetFPS(void); // Get current FPS +RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) +RLAPI float GetFrameTime(void); // Get time in seconds for last frame drawn (delta time) +RLAPI double GetTime(void); // Get elapsed time in seconds since InitWindow() +RLAPI int GetFPS(void); // Get current FPS // Custom frame control functions // NOTE: Those functions are intended for advanced 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 -RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing) -RLAPI void PollInputEvents(void); // Register all input events -RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution) +RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing) +RLAPI void PollInputEvents(void); // Register all input events +RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution) // Random values generation functions -RLAPI void SetRandomSeed(unsigned int seed); // Set the seed for the random number generator -RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included) +RLAPI void SetRandomSeed(unsigned int seed); // Set the seed for the random number generator +RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included) RLAPI int *LoadRandomSequence(unsigned int count, int min, int max); // Load random values sequence, no values repeated -RLAPI void UnloadRandomSequence(int *sequence); // Unload random values sequence +RLAPI void UnloadRandomSequence(int *sequence); // Unload random values sequence // Misc. functions -RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format) -RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS) -RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available) +RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format) +RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS) +RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available) -// NOTE: Following functions implemented in module [utils] -//------------------------------------------------------------------ -RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) -RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level -RLAPI void *MemAlloc(unsigned int size); // Internal memory allocator -RLAPI void *MemRealloc(void *ptr, unsigned int size); // Internal memory reallocator -RLAPI void MemFree(void *ptr); // Internal memory free +// Logging system +RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level +RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) +RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log -// Set custom callbacks -// WARNING: Callbacks setup is intended for advanced users -RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log -RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader -RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver -RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader -RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver +// Memory management, using internal allocators +RLAPI void *MemAlloc(unsigned int size); // Internal memory allocator +RLAPI void *MemRealloc(void *ptr, unsigned int size); // Internal memory reallocator +RLAPI void MemFree(void *ptr); // Internal memory free -// Files management functions +// File system management functions RLAPI unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read) RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData() RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write), returns true on success @@ -1124,9 +1131,14 @@ RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText() RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success -//------------------------------------------------------------------ -// File system functions +// File access custom callbacks +// WARNING: Callbacks setup is intended for advanced users +RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader +RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver +RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader +RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver + RLAPI int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists) RLAPI int FileRemove(const char *fileName); // Remove file (if exists) RLAPI int FileCopy(const char *srcPath, const char *dstPath); // Copy file from one path to another, dstPath created if it doesn't exist @@ -1146,24 +1158,27 @@ RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previ RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string) RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success -RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success +RLAPI bool ChangeDirectory(const char *dirPath); // Change working directory, return true on success RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS -RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths -RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result +RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan +RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: "*.*", "FILES*", "DIRS*" RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths +RLAPI unsigned int GetDirectoryFileCount(const char *dirPath); // Get the file count in a directory +RLAPI unsigned int GetDirectoryFileCountEx(const char *basePath, const char *filter, bool scanSubdirs); // Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result // Compression/Encoding functionality RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree() RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree() RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string (includes NULL terminator), memory must be MemFree() RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize); // Decode Base64 string (expected NULL terminated), memory must be MemFree() -RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code -RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes) -RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes) +RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code +RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes) +RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes) +RLAPI unsigned int *ComputeSHA256(unsigned char *data, int dataSize); // Compute SHA256 hash code, returns static int[8] (32 bytes) // Automation events functionality RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS @@ -1344,7 +1359,7 @@ RLAPI Image LoadImageFromScreen(void); RLAPI bool IsImageValid(Image image); // Check if an image is valid (data and parameters) RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success -RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer +RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer, memory must be MemFree() RLAPI bool ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes, returns true on success // Image generation functions @@ -1415,8 +1430,8 @@ RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color c RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image -RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center) -RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image +RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center) +RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source) RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination) RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination) @@ -1495,6 +1510,7 @@ RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int codepointCou RLAPI void SetTextLineSpacing(int spacing); // Set vertical line spacing when drawing with line-breaks RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font +RLAPI Vector2 MeasureTextCodepoints(Font font, const int *codepoints, int length, float fontSize, float spacing); // Measure string size for an existing array of codepoints for Font RLAPI int GetGlyphIndex(Font font, int codepoint); // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint); // Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint); // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found @@ -1512,7 +1528,7 @@ RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size); // Text strings management functions (no UTF-8 strings, only byte chars) // WARNING 1: Most of these functions use internal static buffers[], it's recommended to store returned data on user-side for re-use -// WARNING 2: Some strings allocate memory internally for the returned strings, those strings must be free by user using MemFree() +// WARNING 2: Some functions allocate memory internally for the returned strings, those strings must be freed by user using MemFree() RLAPI char **LoadTextLines(const char *text, int *count); // Load text as separate lines ('\n') RLAPI void UnloadTextLines(char **text, int lineCount); // Unload text lines RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied @@ -1522,9 +1538,12 @@ RLAPI const char *TextFormat(const char *text, ...); RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string RLAPI const char *TextRemoveSpaces(const char *text); // Remove text spaces, concat words RLAPI char *GetTextBetween(const char *text, const char *begin, const char *end); // Get text between two strings -RLAPI char *TextReplace(const char *text, const char *search, const char *replacement); // Replace text string (WARNING: memory must be freed!) -RLAPI char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings (WARNING: memory must be freed!) -RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!) +RLAPI char *TextReplace(const char *text, const char *search, const char *replacement); // Replace text string with new string +RLAPI char *TextReplaceAlloc(const char *text, const char *search, const char *replacement); // Replace text string with new string, memory must be MemFree() +RLAPI char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings +RLAPI char *TextReplaceBetweenAlloc(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings, memory must be MemFree() +RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a defined byte position +RLAPI char *TextInsertAlloc(const char *text, const char *insert, int position); // Insert text in a defined byte position, memory must be MemFree() RLAPI char *TextJoin(char **textList, int count, const char *delimiter); // Join text strings with delimiter RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor @@ -1580,8 +1599,6 @@ RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters -RLAPI void DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points -RLAPI void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source @@ -1621,9 +1638,8 @@ RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Model animations loading/unloading functions RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount); // Load model animations from file -RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose (CPU) -RLAPI void UpdateModelAnimationBones(Model model, ModelAnimation anim, int frame); // Update model animation mesh bone matrices (GPU skinning) -RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data +RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, float frame); // Update model animation pose (vertex buffers and bone matrices) +RLAPI void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, ModelAnimation animB, float frameB, float blend); // Update model animation pose, blending two animations RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match @@ -1657,7 +1673,7 @@ RLAPI Sound LoadSound(const char *fileName); // Load so RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data RLAPI Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data RLAPI bool IsSoundValid(Sound sound); // Checks if a sound is valid (data loaded and buffers initialized) -RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (data and frame count should fit in sound) +RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (default data format: 32 bit float, stereo) RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadSound(Sound sound); // Unload sound RLAPI void UnloadSoundAlias(Sound alias); // Unload a sound alias (does not deallocate sample data) @@ -1672,7 +1688,7 @@ RLAPI void ResumeSound(Sound sound); // Resume RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) -RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (0.5 is center) +RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (-1.0 left, 0.0 center, 1.0 right) RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave RLAPI void WaveCrop(Wave *wave, int initFrame, int finalFrame); // Crop a wave to defined frames range RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format @@ -1693,7 +1709,7 @@ RLAPI void ResumeMusicStream(Music music); // Resume RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds) RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) -RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (0.5 is center) +RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (-1.0 left, 0.0 center, 1.0 right) RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) @@ -1710,7 +1726,7 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check i RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) -RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (0.5 is centered) +RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (-1.0 to 1.0 range, 0.0 is centered) RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data diff --git a/lib/raylib.zig b/lib/raylib.zig index ef849a5..9d6000b 100644 --- a/lib/raylib.zig +++ b/lib/raylib.zig @@ -11,7 +11,7 @@ pub const math = @import("raymath.zig"); const C = std.builtin.CallingConvention.c; test { - std.testing.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); } pub const RaylibError = error{ @@ -1401,6 +1401,8 @@ pub const Camera2D = extern struct { pub const Mesh = extern struct { vertexCount: c_int, triangleCount: c_int, + + // Vertex attributes data vertices: [*c]f32, texcoords: [*c]f32, texcoords2: [*c]f32, @@ -1408,12 +1410,18 @@ pub const Mesh = extern struct { tangents: [*c]f32, colors: [*c]u8, indices: [*c]c_ushort, + + // Skin data for animation + boneCount: c_int, + boneIndices: [*c]u16, + boneWeights: [*c]f32, + + // Runtime animation vertex data (CPU skinning) + // NOTE: In case of GPU skinning, not used, pointers are NULL animVertices: [*c]f32, animNormals: [*c]f32, - boneIds: [*c]u8, - boneWeights: [*c]f32, - boneMatrices: [*c]Matrix, - boneCount: c_int, + + // OpenGL identifiers vaoId: c_int, vboId: [*c]c_int, @@ -1476,11 +1484,19 @@ pub const Transform = extern struct { scale: Vector3, }; +pub const ModelAnimPose = [*c]Transform; + pub const BoneInfo = extern struct { name: [32]u8, parent: c_int, }; +pub const ModelSkeleton = extern struct { + boneCount: c_int, + bones: [*c]BoneInfo, + bindPose: ModelAnimPose +}; + pub const Model = extern struct { transform: Matrix, meshCount: c_int, @@ -1488,9 +1504,11 @@ pub const Model = extern struct { meshes: [*c]Mesh, materials: [*c]Material, meshMaterial: [*c]c_int, - boneCount: c_int, - bones: [*c]BoneInfo, - bindPose: [*c]Transform, + + // Animation data + skeleton: ModelSkeleton, + currentPose: ModelAnimPose, + boneMatrices: [*c]Matrix, /// Load model from file (meshes and materials) pub fn init(fileName: [:0]const u8) RaylibError!Model { @@ -1529,12 +1547,12 @@ pub const Model = extern struct { }; pub const ModelAnimation = extern struct { - boneCount: c_int, - frameCount: c_int, - bones: [*c]BoneInfo, - framePoses: [*c][*c]Transform, name: [32]u8, + boneCount: c_int, + keyframeCount: c_int, + keyframePoses: [*c]ModelAnimPose, + /// Unload animation data pub fn unload(self: ModelAnimation) void { rl.unloadModelAnimation(self); @@ -1640,7 +1658,6 @@ pub const VrStereoConfig = extern struct { }; pub const FilePathList = extern struct { - capacity: c_uint, count: c_uint, paths: [*c][*c]u8, }; @@ -1662,7 +1679,7 @@ pub const AutomationEventList = extern struct { } }; -pub const ConfigFlags = packed struct { +pub const ConfigFlags = packed struct(u32) { __reserved: bool = false, fullscreen_mode: bool = false, window_resizable: bool = false, @@ -1919,8 +1936,8 @@ pub const ShaderLocationIndex = enum(c_int) { map_brdf = 25, vertex_boneids = 26, vertex_boneweights = 27, - bone_matrices = 28, - shader_loc_vertex_instance_tx = 29, + matrix_bonetransforms = 28, + matrix_instancetransforms = 29, // }; @@ -2011,7 +2028,7 @@ pub const BlendMode = enum(c_int) { custom_separate = 7, }; -pub const Gesture = packed struct { +pub const Gesture = packed struct(u16) { tap: bool = false, doubletap: bool = false, hold: bool = false, @@ -2139,6 +2156,11 @@ pub fn computeSHA1(data: []u8) [5]u32 { return res[0..5].*; } +pub fn computeSHA256(data: []u8) [8]u32 { + const res: [*]c_uint = cdef.ComputeSHA256(@as([*c]u8, @ptrCast(data)), @as(c_int, @intCast(data.len))); + return res[0..8].*; +} + /// Load image from file into CPU memory (RAM) pub fn loadImage(fileName: [:0]const u8) RaylibError!Image { const image = cdef.LoadImage(@as([*c]const u8, @ptrCast(fileName))); @@ -3128,26 +3150,6 @@ pub fn memFree(ptr: *anyopaque) void { cdef.MemFree(ptr); } -/// Set custom file binary data loader -pub fn setLoadFileDataCallback(callback: LoadFileDataCallback) void { - cdef.SetLoadFileDataCallback(callback); -} - -/// Set custom file binary data saver -pub fn setSaveFileDataCallback(callback: SaveFileDataCallback) void { - cdef.SetSaveFileDataCallback(callback); -} - -/// Set custom file text data loader -pub fn setLoadFileTextCallback(callback: LoadFileTextCallback) void { - cdef.SetLoadFileTextCallback(callback); -} - -/// Set custom file text data saver -pub fn setSaveFileTextCallback(callback: SaveFileTextCallback) void { - cdef.SetSaveFileTextCallback(callback); -} - /// Load file data as byte array (read) pub fn loadFileData(fileName: []const u8) RaylibError![]u8 { var _len: i32 = 0; @@ -3176,6 +3178,26 @@ pub fn saveFileText(fileName: [:0]const u8, text: [:0]const u8) bool { return cdef.SaveFileText(@as([*c]const u8, @ptrCast(fileName)), @as([*c]const u8, @ptrCast(text))); } +/// Set custom file binary data loader +pub fn setLoadFileDataCallback(callback: LoadFileDataCallback) void { + cdef.SetLoadFileDataCallback(callback); +} + +/// Set custom file binary data saver +pub fn setSaveFileDataCallback(callback: SaveFileDataCallback) void { + cdef.SetSaveFileDataCallback(callback); +} + +/// Set custom file text data loader +pub fn setLoadFileTextCallback(callback: LoadFileTextCallback) void { + cdef.SetLoadFileTextCallback(callback); +} + +/// Set custom file text data saver +pub fn setSaveFileTextCallback(callback: SaveFileTextCallback) void { + cdef.SetSaveFileTextCallback(callback); +} + /// Rename file (if exists) pub fn fileRename(fileName: [:0]const u8, fileRename_: [:0]const u8) i32 { return @as(i32, cdef.FileRename(@as([*c]const u8, @ptrCast(fileName)), @as([*c]const u8, @ptrCast(fileRename_)))); @@ -3272,8 +3294,8 @@ pub fn makeDirectory(dirPath: [:0]const u8) i32 { } /// Change working directory, return true on success -pub fn changeDirectory(dir: [:0]const u8) bool { - return cdef.ChangeDirectory(@as([*c]const u8, @ptrCast(dir))); +pub fn changeDirectory(dirPath: [:0]const u8) bool { + return cdef.ChangeDirectory(@as([*c]const u8, @ptrCast(dirPath))); } /// Check if a given path is a file or a directory @@ -3286,12 +3308,12 @@ pub fn isFileNameValid(fileName: [:0]const u8) bool { return cdef.IsFileNameValid(@as([*c]const u8, @ptrCast(fileName))); } -/// Load directory filepaths +/// Load directory filepaths, files and directories, no subdirs scan pub fn loadDirectoryFiles(dirPath: [:0]const u8) FilePathList { return cdef.LoadDirectoryFiles(@as([*c]const u8, @ptrCast(dirPath))); } -/// Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result +/// Load directory filepaths with extension filtering and subdir scan; some filters available: "*.*", "FILES*", "DIRS*" pub fn loadDirectoryFilesEx(basePath: [:0]const u8, filter: [:0]const u8, scanSubdirs: bool) FilePathList { return cdef.LoadDirectoryFilesEx(@as([*c]const u8, @ptrCast(basePath)), @as([*c]const u8, @ptrCast(filter)), scanSubdirs); } @@ -3316,6 +3338,16 @@ pub fn unloadDroppedFiles(files: FilePathList) void { cdef.UnloadDroppedFiles(files); } +/// Get the file count in a directory +pub fn getDirectoryFileCount(dirPath: [:0]const u8) u32 { + return @as(u32, cdef.GetDirectoryFileCount(@as([*c]const u8, @ptrCast(dirPath)))); +} + +/// Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result +pub fn getDirectoryFileCountEx(basePath: [:0]const u8, filter: [:0]const u8, scanSubdirs: bool) u32 { + return @as(u32, cdef.GetDirectoryFileCountEx(@as([*c]const u8, @ptrCast(basePath)), @as([*c]const u8, @ptrCast(filter)), scanSubdirs)); +} + /// Compress data (DEFLATE algorithm), memory must be MemFree() pub fn compressData(data: []const u8, dataSize: i32) RaylibError![]u8 { var _len: i32 = 0; @@ -3948,7 +3980,7 @@ pub fn exportImage(image: Image, fileName: [:0]const u8) bool { return cdef.ExportImage(image, @as([*c]const u8, @ptrCast(fileName))); } -/// Export image to memory buffer +/// Export image to memory buffer, memory must be MemFree() pub fn exportImageToMemory(image: Image, fileType: []const u8) RaylibError![]u8 { var _len: i32 = 0; const _ptr = cdef.ExportImageToMemory(image, @as([*c]const u8, @ptrCast(fileType)), @as([*c]c_int, @ptrCast(&_len))); @@ -4489,6 +4521,11 @@ pub fn measureTextEx(font: Font, text: [:0]const u8, fontSize: f32, spacing: f32 return cdef.MeasureTextEx(font, @as([*c]const u8, @ptrCast(text)), fontSize, spacing); } +/// Measure string size for an existing array of codepoints for Font +pub fn measureTextCodepoints(font: Font, codepoints: []const c_int, length: i32, fontSize: f32, spacing: f32) Vector2 { + return cdef.MeasureTextCodepoints(font, @as([*c]const c_int, @ptrCast(codepoints)), @as(c_int, length), fontSize, spacing); +} + /// Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found pub fn getGlyphIndex(font: Font, codepoint: i32) i32 { return @as(i32, cdef.GetGlyphIndex(font, @as(c_int, codepoint))); @@ -4577,21 +4614,36 @@ pub fn getTextBetween(text: [:0]const u8, begin: [:0]const u8, end: [:0]const u8 return std.mem.span(cdef.GetTextBetween(@as([*c]const u8, @ptrCast(text)), @as([*c]const u8, @ptrCast(begin)), @as([*c]const u8, @ptrCast(end)))); } -/// Replace text string (WARNING: memory must be freed!) +/// Replace text string with new string pub fn textReplace(text: [:0]const u8, search: [:0]const u8, replacement: [:0]const u8) [:0]u8 { return std.mem.span(cdef.TextReplace(@as([*c]const u8, @ptrCast(text)), @as([*c]const u8, @ptrCast(search)), @as([*c]const u8, @ptrCast(replacement)))); } -/// Replace text between two specific strings (WARNING: memory must be freed!) +/// Replace text string with new string, memory must be MemFree() +pub fn textReplaceAlloc(text: [:0]const u8, search: [:0]const u8, replacement: [:0]const u8) [:0]u8 { + return std.mem.span(cdef.TextReplaceAlloc(@as([*c]const u8, @ptrCast(text)), @as([*c]const u8, @ptrCast(search)), @as([*c]const u8, @ptrCast(replacement)))); +} + +/// Replace text between two specific strings pub fn textReplaceBetween(text: [:0]const u8, begin: [:0]const u8, end: [:0]const u8, replacement: [:0]const u8) [:0]u8 { return std.mem.span(cdef.TextReplaceBetween(@as([*c]const u8, @ptrCast(text)), @as([*c]const u8, @ptrCast(begin)), @as([*c]const u8, @ptrCast(end)), @as([*c]const u8, @ptrCast(replacement)))); } -/// Insert text in a position (WARNING: memory must be freed!) +/// Replace text between two specific strings, memory must be MemFree() +pub fn textReplaceBetweenAlloc(text: [:0]const u8, begin: [:0]const u8, end: [:0]const u8, replacement: [:0]const u8) [:0]u8 { + return std.mem.span(cdef.TextReplaceBetweenAlloc(@as([*c]const u8, @ptrCast(text)), @as([*c]const u8, @ptrCast(begin)), @as([*c]const u8, @ptrCast(end)), @as([*c]const u8, @ptrCast(replacement)))); +} + +/// Insert text in a defined byte position pub fn textInsert(text: [:0]const u8, insert: [:0]const u8, position: i32) [:0]u8 { return std.mem.span(cdef.TextInsert(@as([*c]const u8, @ptrCast(text)), @as([*c]const u8, @ptrCast(insert)), @as(c_int, position))); } +/// Insert text in a defined byte position, memory must be MemFree() +pub fn textInsertAlloc(text: [:0]const u8, insert: [:0]const u8, position: i32) [:0]u8 { + return std.mem.span(cdef.TextInsertAlloc(@as([*c]const u8, @ptrCast(text)), @as([*c]const u8, @ptrCast(insert)), @as(c_int, position))); +} + /// Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings pub fn textSplit(text: []const u8, delimiter: u8) RaylibError![][:0]u8 { var _len: i32 = 0; @@ -4780,16 +4832,6 @@ pub fn drawModelWiresEx(model: Model, position: Vector3, rotationAxis: Vector3, cdef.DrawModelWiresEx(model, position, rotationAxis, rotationAngle, scale, tint); } -/// Draw a model as points -pub fn drawModelPoints(model: Model, position: Vector3, scale: f32, tint: Color) void { - cdef.DrawModelPoints(model, position, scale, tint); -} - -/// Draw a model as points with extended parameters -pub fn drawModelPointsEx(model: Model, position: Vector3, rotationAxis: Vector3, rotationAngle: f32, scale: Vector3, tint: Color) void { - cdef.DrawModelPointsEx(model, position, rotationAxis, rotationAngle, scale, tint); -} - /// Draw bounding box (wires) pub fn drawBoundingBox(box: BoundingBox, color: Color) void { cdef.DrawBoundingBox(box, color); @@ -4933,19 +4975,14 @@ pub fn loadModelAnimations(fileName: []const u8) RaylibError![]ModelAnimation { return _ptr[0..@as(usize, @intCast(_len))]; } -/// Update model animation pose (CPU) -pub fn updateModelAnimation(model: Model, anim: ModelAnimation, frame: i32) void { - cdef.UpdateModelAnimation(model, anim, @as(c_int, frame)); +/// Update model animation pose (vertex buffers and bone matrices) +pub fn updateModelAnimation(model: Model, anim: ModelAnimation, frame: f32) void { + cdef.UpdateModelAnimation(model, anim, frame); } -/// Update model animation mesh bone matrices (GPU skinning) -pub fn updateModelAnimationBones(model: Model, anim: ModelAnimation, frame: i32) void { - cdef.UpdateModelAnimationBones(model, anim, @as(c_int, frame)); -} - -/// Unload animation data -pub fn unloadModelAnimation(anim: ModelAnimation) void { - cdef.UnloadModelAnimation(anim); +/// Update model animation pose, blending two animations +pub fn updateModelAnimationEx(model: Model, animA: ModelAnimation, frameA: f32, animB: ModelAnimation, frameB: f32, blend: f32) void { + cdef.UpdateModelAnimationEx(model, animA, frameA, animB, frameB, blend); } /// Check model animation skeleton match @@ -5038,7 +5075,7 @@ pub fn isSoundValid(sound: Sound) bool { return cdef.IsSoundValid(sound); } -/// Update sound buffer with new data (data and frame count should fit in sound) +/// Update sound buffer with new data (default data format: 32 bit float, stereo) pub fn updateSound(sound: Sound, data: *const anyopaque, sampleCount: i32) void { cdef.UpdateSound(sound, data, @as(c_int, sampleCount)); } @@ -5103,7 +5140,7 @@ pub fn setSoundPitch(sound: Sound, pitch: f32) void { cdef.SetSoundPitch(sound, pitch); } -/// Set pan for a sound (0.5 is center) +/// Set pan for a sound (-1.0 left, 0.0 center, 1.0 right) pub fn setSoundPan(sound: Sound, pan: f32) void { cdef.SetSoundPan(sound, pan); } @@ -5183,7 +5220,7 @@ pub fn setMusicPitch(music: Music, pitch: f32) void { cdef.SetMusicPitch(music, pitch); } -/// Set pan for a music (0.5 is center) +/// Set pan for a music (-1.0 left, 0.0 center, 1.0 right) pub fn setMusicPan(music: Music, pan: f32) void { cdef.SetMusicPan(music, pan); } @@ -5253,7 +5290,7 @@ pub fn setAudioStreamPitch(stream: AudioStream, pitch: f32) void { cdef.SetAudioStreamPitch(stream, pitch); } -/// Set pan for audio stream (0.5 is centered) +/// Set pan for audio stream (-1.0 to 1.0 range, 0.0 is centered) pub fn setAudioStreamPan(stream: AudioStream, pan: f32) void { cdef.SetAudioStreamPan(stream, pan); } diff --git a/lib/raymath-ext.zig b/lib/raymath-ext.zig index 74b5b15..fc4d94c 100644 --- a/lib/raymath-ext.zig +++ b/lib/raymath-ext.zig @@ -109,6 +109,7 @@ pub extern "c" fn MatrixIdentity() rl.Matrix; pub extern "c" fn MatrixAdd(left: rl.Matrix, right: rl.Matrix) rl.Matrix; pub extern "c" fn MatrixSubtract(left: rl.Matrix, right: rl.Matrix) rl.Matrix; pub extern "c" fn MatrixMultiply(left: rl.Matrix, right: rl.Matrix) rl.Matrix; +pub extern "c" fn MatrixMultiplyValue(left: rl.Matrix, value: f32) rl.Matrix; pub extern "c" fn MatrixTranslate(x: f32, y: f32, z: f32) rl.Matrix; pub extern "c" fn MatrixRotate(axis: rl.Vector3, angle: f32) rl.Matrix; pub extern "c" fn MatrixRotateX(angle: f32) rl.Matrix; @@ -146,4 +147,5 @@ pub extern "c" fn QuaternionFromEuler(pitch: f32, yaw: f32, roll: f32) rl.Quater pub extern "c" fn QuaternionToEuler(q: rl.Quaternion) rl.Vector3; pub extern "c" fn QuaternionTransform(q: rl.Quaternion, mat: rl.Matrix) rl.Quaternion; pub extern "c" fn QuaternionEquals(p: rl.Quaternion, q: rl.Quaternion) c_int; +pub extern "c" fn MatrixCompose(translation: rl.Vector3, rotation: rl.Quaternion, scale: rl.Vector3) rl.Matrix; pub extern "c" fn MatrixDecompose(mat: rl.Matrix, translation: [*c]rl.Vector3, rotation: [*c]rl.Quaternion, scale: [*c]rl.Vector3) void; diff --git a/lib/raymath.h b/lib/raymath.h index 65a20de..8a0cce1 100644 --- a/lib/raymath.h +++ b/lib/raymath.h @@ -19,20 +19,25 @@ * * CONFIGURATION: * #define RAYMATH_IMPLEMENTATION -* Generates the implementation of the library into the included file. +* 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. +* or source files without problems. But only ONE file should hold the implementation * * #define RAYMATH_STATIC_INLINE -* Define static inline functions code, so #include header suffices for use. -* This may use up lots of memory. +* Define static inline functions code, so #include header suffices for use +* This may use up lots of memory * * #define RAYMATH_DISABLE_CPP_OPERATORS * Disables C++ operator overloads for raymath types. * +* #define RAYMATH_USE_SIMD_INTRINSICS 1 +* Try to enable SIMD intrinsics for MatrixMultiply() +* Note that users enabling it must be aware of the target platform where application will +* run to support the selected SIMD intrinsic, for now, only SSE is supported +* * LICENSE: zlib/libpng * -* Copyright (c) 2015-2025 Ramon Santamaria (@raysan5) +* Copyright (c) 2015-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. @@ -61,11 +66,11 @@ // Function specifiers definition #if defined(RAYMATH_IMPLEMENTATION) #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) - #define RMAPI __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll) + #define RMAPI __declspec(dllexport) extern inline // Building raylib as a Win32 shared library (.dll) #elif defined(BUILD_LIBTYPE_SHARED) - #define RMAPI __attribute__((visibility("default"))) // We are building raylib as a Unix shared library (.so/.dylib) + #define RMAPI __attribute__((visibility("default"))) // Building raylib as a Unix shared library (.so/.dylib) #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) - #define RMAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll) + #define RMAPI __declspec(dllimport) // Using raylib as a Win32 shared library (.dll) #else #define RMAPI extern inline // Provide external definition #endif @@ -79,7 +84,6 @@ #endif #endif - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -160,16 +164,51 @@ typedef struct Matrix { #endif // NOTE: Helper types to be used instead of array return types for *ToFloat functions +#if !defined(RL_FLOAT3_TYPE) typedef struct float3 { float v[3]; } float3; +#define RL_FLOAT3_TYPE +#endif +#if !defined(RL_FLOAT16_TYPE) typedef struct float16 { float v[16]; } float16; +#define RL_FLOAT16_TYPE +#endif #include // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabsf() +#if RAYMATH_USE_SIMD_INTRINSICS + // SIMD is used on the most costly raymath function MatrixMultiply() + // NOTE: Only SSE intrinsics support implemented + // TODO: Consider support for other SIMD instrinsics: + // - SSEx, AVX, AVX2, FMA, NEON, RVV + /* + #if defined(__SSE4_2__) + #include + #define RAYMATH_SSE42_ENABLED + #elif defined(__SSE4_1__) + #include + #define RAYMATH_SSE41_ENABLED + #elif defined(__SSSE3__) + #include + #define RAYMATH_SSSE3_ENABLED + #elif defined(__SSE3__) + #include + #define RAYMATH_SSE3_ENABLED + #elif defined(__SSE2__) || (defined(_M_AMD64) || defined(_M_X64)) // SSE2 x64 + #include + #define RAYMATH_SSE2_ENABLED + #endif + */ + #if defined(__SSE__) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1)) + #include + #define RAYMATH_SSE_ENABLED + #endif +#endif + //---------------------------------------------------------------------------------- // Module Functions Definition - Utils math //---------------------------------------------------------------------------------- @@ -528,15 +567,9 @@ RMAPI Vector2 Vector2ClampValue(Vector2 v, float min, float max) { length = sqrtf(length); - float scale = 1; // By default, 1 as the neutral element. - if (length < min) - { - scale = min/length; - } - else if (length > max) - { - scale = max/length; - } + float scale = 1; // By default, 1 as the neutral element + if (length < min) scale = min/length; + else if (length > max) scale = max/length; result.x = v.x*scale; result.y = v.y*scale; @@ -562,7 +595,7 @@ RMAPI int Vector2Equals(Vector2 p, Vector2 q) // v: normalized direction of the incoming ray // n: normalized normal vector of the interface of two optical media // r: ratio of the refractive index of the medium from where the ray comes -// to the refractive index of the medium on the other side of the surface +// to the refractive index of the medium on the other side of the surface RMAPI Vector2 Vector2Refract(Vector2 v, Vector2 n, float r) { Vector2 result = { 0 }; @@ -1050,7 +1083,7 @@ RMAPI Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) } // Projects a Vector3 from screen space into object space -// NOTE: We are avoiding calling other raymath functions despite available +// NOTE: Self-contained function, no other raymath functions are called RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) { Vector3 result = { 0 }; @@ -1176,15 +1209,9 @@ RMAPI Vector3 Vector3ClampValue(Vector3 v, float min, float max) { length = sqrtf(length); - float scale = 1; // By default, 1 as the neutral element. - if (length < min) - { - scale = min/length; - } - else if (length > max) - { - scale = max/length; - } + float scale = 1; // By default, 1 as the neutral element + if (length < min) scale = min/length; + else if (length > max) scale = max/length; result.x = v.x*scale; result.y = v.y*scale; @@ -1212,7 +1239,7 @@ RMAPI int Vector3Equals(Vector3 p, Vector3 q) // v: normalized direction of the incoming ray // n: normalized normal vector of the interface of two optical media // r: ratio of the refractive index of the medium from where the ray comes -// to the refractive index of the medium on the other side of the surface +// to the refractive index of the medium on the other side of the surface RMAPI Vector3 Vector3Refract(Vector3 v, Vector3 n, float r) { Vector3 result = { 0 }; @@ -1484,7 +1511,7 @@ RMAPI float MatrixDeterminant(Matrix mat) a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; */ // Using Laplace expansion (https://en.wikipedia.org/wiki/Laplace_expansion), - // previous operation can be simplified to 40 multiplications, decreasing matrix + // previous operation can be simplified to 40 multiplications, decreasing matrix // size from 4x4 to 2x2 using minors // Cache the matrix values (speed optimization) @@ -1648,6 +1675,63 @@ RMAPI Matrix MatrixMultiply(Matrix left, Matrix right) { Matrix result = { 0 }; +#if defined(RAYMATH_SSE_ENABLED) + // Load left side and right side + __m128 c0 = _mm_set_ps(right.m12, right.m8, right.m4, right.m0); + __m128 c1 = _mm_set_ps(right.m13, right.m9, right.m5, right.m1); + __m128 c2 = _mm_set_ps(right.m14, right.m10, right.m6, right.m2); + __m128 c3 = _mm_set_ps(right.m15, right.m11, right.m7, right.m3); + + // Transpose so c0..c3 become *rows* of the right matrix in semantic order + _MM_TRANSPOSE4_PS(c0, c1, c2, c3); + + float tmp[4] = { 0 }; + __m128 row; + + // Row 0 of result: [m0, m1, m2, m3] + row = _mm_mul_ps(_mm_set1_ps(left.m0), c0); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m1), c1)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m2), c2)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m3), c3)); + _mm_storeu_ps(tmp, row); + result.m0 = tmp[0]; + result.m1 = tmp[1]; + result.m2 = tmp[2]; + result.m3 = tmp[3]; + + // Row 1 of result: [m4, m5, m6, m7] + row = _mm_mul_ps(_mm_set1_ps(left.m4), c0); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m5), c1)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m6), c2)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m7), c3)); + _mm_storeu_ps(tmp, row); + result.m4 = tmp[0]; + result.m5 = tmp[1]; + result.m6 = tmp[2]; + result.m7 = tmp[3]; + + // Row 2 of result: [m8, m9, m10, m11] + row = _mm_mul_ps(_mm_set1_ps(left.m8), c0); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m9), c1)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m10), c2)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m11), c3)); + _mm_storeu_ps(tmp, row); + result.m8 = tmp[0]; + result.m9 = tmp[1]; + result.m10 = tmp[2]; + result.m11 = tmp[3]; + + // Row 3 of result: [m12, m13, m14, m15] + row = _mm_mul_ps(_mm_set1_ps(left.m12), c0); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m13), c1)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m14), c2)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m15), c3)); + _mm_storeu_ps(tmp, row); + result.m12 = tmp[0]; + result.m13 = tmp[1]; + result.m14 = tmp[2]; + result.m15 = tmp[3]; +#else result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12; result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13; result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14; @@ -1664,6 +1748,19 @@ RMAPI Matrix MatrixMultiply(Matrix left, Matrix right) result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13; result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14; result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15; +#endif + + return result; +} + +RMAPI Matrix MatrixMultiplyValue(Matrix left, float value) +{ + Matrix result = { + left.m0 * value, left.m4 * value, left.m8 * value, left.m12 * value, + left.m1 * value, left.m5 * value, left.m9 * value, left.m13 * value, + left.m2 * value, left.m6 * value, left.m10 * value, left.m14 * value, + left.m3 * value, left.m7 * value, left.m11 * value, left.m15 * value + }; return result; } @@ -2272,13 +2369,13 @@ RMAPI Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to) { Quaternion result = { 0 }; - float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to) + float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to) Vector3 cross = { from.y*to.z - from.z*to.y, from.z*to.x - from.x*to.z, from.x*to.y - from.y*to.x }; // Vector3CrossProduct(from, to) result.x = cross.x; result.y = cross.y; result.z = cross.z; - result.w = 1.0f + cos2Theta; + result.w = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z + cos2Theta*cos2Theta) + cos2Theta; // QuaternionNormalize(q); // NOTE: Normalize to essentially nlerp the original and identity to 0.5 @@ -2465,8 +2562,8 @@ RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle } else { - // This occurs when the angle is zero. - // Not a problem: just set an arbitrary normalized axis. + // This occurs when the angle is zero + // Not a problem, set an arbitrary normalized axis resAxis.x = 1.0f; } @@ -2552,7 +2649,38 @@ RMAPI int QuaternionEquals(Quaternion p, Quaternion q) return result; } +// Compose a transformation matrix from rotational, translational and scaling components +// TODO: This function is not following raymath conventions defined in header: NOT self-contained +RMAPI Matrix MatrixCompose(Vector3 translation, Quaternion rotation, Vector3 scale) +{ + // Initialize vectors + Vector3 right = { 1.0f, 0.0f, 0.0f }; + Vector3 up = { 0.0f, 1.0f, 0.0f }; + Vector3 forward = { 0.0f, 0.0f, 1.0f }; + + // Scale vectors + right = Vector3Scale(right, scale.x); + up = Vector3Scale(up, scale.y); + forward = Vector3Scale(forward , scale.z); + + // Rotate vectors + right = Vector3RotateByQuaternion(right, rotation); + up = Vector3RotateByQuaternion(up, rotation); + forward = Vector3RotateByQuaternion(forward, rotation); + + // Set result matrix output + Matrix result = { + right.x, up.x, forward.x, translation.x, + right.y, up.y, forward.y, translation.y, + right.z, up.z, forward.z, translation.z, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + return result; +} + // Decompose a transformation matrix into its rotational, translational and scaling components and remove shear +// TODO: This function is not following raymath conventions defined in header: NOT self-contained RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale) { float eps = (float)1e-9; @@ -2562,10 +2690,10 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio translation->y = mat.m13; translation->z = mat.m14; - // Matrix Columns - Rotation will be extracted into here. - Vector3 matColumns[3] = { { mat.m0, mat.m4, mat.m8 }, + // Matrix Columns - Rotation will be extracted into here + Vector3 matColumns[3] = {{ mat.m0, mat.m4, mat.m8 }, { mat.m1, mat.m5, mat.m9 }, - { mat.m2, mat.m6, mat.m10 } }; + { mat.m2, mat.m6, mat.m10 }}; // Shear Parameters XY, XZ, and YZ (extract and ignored) float shear[3] = { 0 }; @@ -2580,17 +2708,14 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].x)); stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].y)); stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].z)); - }; + } matColumns[0] = Vector3Scale(matColumns[0], 1.0f / stabilizer); matColumns[1] = Vector3Scale(matColumns[1], 1.0f / stabilizer); matColumns[2] = Vector3Scale(matColumns[2], 1.0f / stabilizer); // X Scale scl.x = Vector3Length(matColumns[0]); - if (scl.x > eps) - { - matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x); - } + if (scl.x > eps) matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x); // Compute XY shear and make col2 orthogonal shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]); @@ -2619,7 +2744,7 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio shear[2] /= scl.z; // Correct YZ shear } - // matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1. + // matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1 if (Vector3DotProduct(matColumns[0], Vector3CrossProduct(matColumns[1], matColumns[2])) < 0) { scl = Vector3Negate(scl); @@ -2954,6 +3079,11 @@ inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs) } // Matrix operators +static constexpr Matrix MatrixUnit = { 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 }; + inline Matrix operator + (const Matrix& lhs, const Matrix& rhs) { return MatrixAdd(lhs, rhs); @@ -2986,7 +3116,19 @@ inline const Matrix& operator *= (Matrix& lhs, const Matrix& rhs) lhs = MatrixMultiply(lhs, rhs); return lhs; } -//------------------------------------------------------------------------------- -#endif // C++ operators -#endif // RAYMATH_H +inline Matrix operator * (const Matrix& lhs, const float value) +{ + return MatrixMultiplyValue(lhs, value); +} + +inline const Matrix& operator *= (Matrix& lhs, const float value) +{ + lhs = MatrixMultiplyValue(lhs, value); + return lhs; +} + +//------------------------------------------------------------------------------- +#endif // C++ operators + +#endif // RAYMATH_H diff --git a/lib/raymath.zig b/lib/raymath.zig index 451df5e..20e8f5e 100644 --- a/lib/raymath.zig +++ b/lib/raymath.zig @@ -6,7 +6,7 @@ const std = @import("std"); pub const cdef = @import("raymath-ext.zig"); test { - std.testing.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); } const Matrix = rl.Matrix; @@ -447,6 +447,10 @@ pub fn matrixMultiply(left: Matrix, right: Matrix) Matrix { return cdef.MatrixMultiply(left, right); } +pub fn matrixMultiplyValue(left: Matrix, value: f32) Matrix { + return cdef.MatrixMultiplyValue(left, value); +} + pub fn matrixTranslate(x: f32, y: f32, z: f32) Matrix { return cdef.MatrixTranslate(x, y, z); } @@ -595,6 +599,10 @@ pub fn quaternionEquals(p: Quaternion, q: Quaternion) i32 { return @as(i32, cdef.QuaternionEquals(p, q)); } +pub fn matrixCompose(translation: Vector3, rotation: Quaternion, scale: Vector3) Matrix { + return cdef.MatrixCompose(translation, rotation, scale); +} + pub fn matrixDecompose(mat: Matrix, translation: *Vector3, rotation: *Quaternion, scale: *Vector3) void { cdef.MatrixDecompose(mat, @as([*c]Vector3, @ptrCast(translation)), @as([*c]Quaternion, @ptrCast(rotation)), @as([*c]Vector3, @ptrCast(scale))); } diff --git a/lib/rlgl-ext.zig b/lib/rlgl-ext.zig index de62a88..54d19f6 100644 --- a/lib/rlgl-ext.zig +++ b/lib/rlgl-ext.zig @@ -128,23 +128,24 @@ pub extern "c" fn rlGenTextureMipmaps(id: c_uint, width: c_int, height: c_int, f pub extern "c" fn rlReadTexturePixels(id: c_uint, width: c_int, height: c_int, format: c_int) *anyopaque; pub extern "c" fn rlReadScreenPixels(width: c_int, height: c_int) [*c]u8; pub extern "c" fn rlLoadFramebuffer() c_uint; -pub extern "c" fn rlFramebufferAttach(fboId: c_uint, texId: c_uint, attachType: c_int, texType: c_int, mipLevel: c_int) void; +pub extern "c" fn rlFramebufferAttach(id: c_uint, texId: c_uint, attachType: c_int, texType: c_int, mipLevel: c_int) void; pub extern "c" fn rlFramebufferComplete(id: c_uint) bool; pub extern "c" fn rlUnloadFramebuffer(id: c_uint) void; pub extern "c" fn rlCopyFramebuffer(x: c_int, y: c_int, width: c_int, height: c_int, format: c_int, pixels: *anyopaque) void; pub extern "c" fn rlResizeFramebuffer(width: c_int, height: c_int) void; -pub extern "c" fn rlLoadShaderCode(vsCode: [*c]const u8, fsCode: [*c]const u8) c_uint; -pub extern "c" fn rlCompileShader(shaderCode: [*c]const u8, ty: c_int) c_uint; -pub extern "c" fn rlLoadShaderProgram(vShaderId: c_uint, fShaderId: c_uint) c_uint; +pub extern "c" fn rlLoadShader(code: [*c]const u8, ty: c_int) c_uint; +pub extern "c" fn rlLoadShaderProgram(vsCode: [*c]const u8, fsCode: [*c]const u8) c_uint; +pub extern "c" fn rlLoadShaderProgramEx(vsId: c_uint, fsId: c_uint) c_uint; +pub extern "c" fn rlLoadShaderProgramCompute(csId: c_uint) c_uint; +pub extern "c" fn rlUnloadShader(id: c_uint) void; pub extern "c" fn rlUnloadShaderProgram(id: c_uint) void; -pub extern "c" fn rlGetLocationUniform(shaderId: c_uint, uniformName: [*c]const u8) c_int; -pub extern "c" fn rlGetLocationAttrib(shaderId: c_uint, attribName: [*c]const u8) c_int; +pub extern "c" fn rlGetLocationUniform(id: c_uint, uniformName: [*c]const u8) c_int; +pub extern "c" fn rlGetLocationAttrib(id: c_uint, attribName: [*c]const u8) c_int; pub extern "c" fn rlSetUniform(locIndex: c_int, value: *const anyopaque, uniformType: c_int, count: c_int) void; pub extern "c" fn rlSetUniformMatrix(locIndex: c_int, mat: rl.Matrix) void; pub extern "c" fn rlSetUniformMatrices(locIndex: c_int, mat: [*c]const rl.Matrix, count: c_int) void; pub extern "c" fn rlSetUniformSampler(locIndex: c_int, textureId: c_uint) void; pub extern "c" fn rlSetShader(id: c_uint, locs: [*c]c_int) void; -pub extern "c" fn rlLoadComputeShaderProgram(shaderId: c_uint) c_uint; pub extern "c" fn rlComputeShaderDispatch(groupX: c_uint, groupY: c_uint, groupZ: c_uint) void; pub extern "c" fn rlLoadShaderBuffer(size: c_uint, data: ?*const anyopaque, usageHint: c_int) c_uint; pub extern "c" fn rlUnloadShaderBuffer(ssboId: c_uint) void; diff --git a/lib/rlgl.h b/lib/rlgl.h index ecd3795..e97bad3 100644 --- a/lib/rlgl.h +++ b/lib/rlgl.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* rlgl v5.0 - A multi-OpenGL abstraction layer with an immediate-mode style API +* rlgl v6.0 - A multi-OpenGL abstraction layer with an immediate-mode style API * * DESCRIPTION: * An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0, ES 3.0) @@ -21,6 +21,7 @@ * Internal buffer (and resources) must be manually unloaded calling rlglClose() * * CONFIGURATION: +* #define GRAPHICS_API_OPENGL_SOFTWARE * #define GRAPHICS_API_OPENGL_11 * #define GRAPHICS_API_OPENGL_21 * #define GRAPHICS_API_OPENGL_33 @@ -36,17 +37,13 @@ * 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 RLGL_RENDER_TEXTURES_HINT -* Enable framebuffer objects (fbo) support (enabled by default) -* Some GPUs could not support them despite the OpenGL version -* -* #define RLGL_SHOW_GL_DETAILS_INFO +* #if RLGL_SHOW_GL_DETAILS_INFO * Show OpenGL extensions and capabilities detailed logs on init * -* #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT +* #if RLGL_ENABLE_OPENGL_DEBUG_CONTEXT * Enable debug context (only available on OpenGL 4.3) * -* rlgl capabilities could be customized just defining some internal +* rlgl capabilities could be customized defining some internal * values before library inclusion (default values listed): * * #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch elements limits @@ -68,7 +65,7 @@ * #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR * #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT * #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS "vertexBoneIds" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES * #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS * #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix @@ -76,7 +73,7 @@ * #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))) * #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) -* #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES "boneMatrices" // bone matrices +* #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) @@ -88,7 +85,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2025 Ramon Santamaria (@raysan5) +* 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. @@ -110,17 +107,17 @@ #ifndef RLGL_H #define RLGL_H -#define RLGL_VERSION "5.0" +#define RLGL_VERSION "6.0" // Function specifiers in case library is build/used as a shared library // NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll // NOTE: visibility(default) attribute makes symbols "visible" when compiled with -fvisibility=hidden #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) - #define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) + #define RLAPI __declspec(dllexport) // Building the library as a Win32 shared library (.dll) #elif defined(BUILD_LIBTYPE_SHARED) - #define RLAPI __attribute__((visibility("default"))) // We are building the library as a Unix shared library (.so/.dylib) + #define RLAPI __attribute__((visibility("default"))) // Building the library as a Unix shared library (.so/.dylib) #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) - #define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) + #define RLAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) #endif // Function specifiers definition @@ -131,7 +128,6 @@ // Support TRACELOG macros #ifndef TRACELOG #define TRACELOG(level, ...) (void)0 - #define TRACELOGD(...) (void)0 #endif // Allow custom memory allocators @@ -149,7 +145,7 @@ #endif // Security check in case no GRAPHICS_API_OPENGL_* defined -#if !defined(GRAPHICS_API_OPENGL_11_SOFTWARE) && \ +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) && \ !defined(GRAPHICS_API_OPENGL_11) && \ !defined(GRAPHICS_API_OPENGL_21) && \ !defined(GRAPHICS_API_OPENGL_33) && \ @@ -160,7 +156,7 @@ #endif // Security check in case multiple GRAPHICS_API_OPENGL_* defined -#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_SOFTWARE) #if defined(GRAPHICS_API_OPENGL_21) #undef GRAPHICS_API_OPENGL_21 #endif @@ -176,7 +172,7 @@ #endif // Software implementation uses OpenGL 1.1 functionality -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) #define GRAPHICS_API_OPENGL_11 #endif @@ -196,10 +192,6 @@ #define GRAPHICS_API_OPENGL_ES2 #endif -// Support framebuffer objects by default -// NOTE: Some driver implementation do not support it, despite they should -#define RLGL_RENDER_TEXTURES_HINT - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -212,9 +204,9 @@ #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 8192 #endif #if defined(GRAPHICS_API_OPENGL_ES2) - // We reduce memory sizes for embedded systems (RPI and HTML5) + // Reducing memory sizes for embedded systems (RPI and HTML5) // NOTE: On HTML5 (emscripten) this is allocated on heap, - // by default it's only 16MB!...just take care... + // by default heap is only 16MB!...just take care... #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 2048 #endif #endif @@ -353,16 +345,14 @@ #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 #endif -#ifdef RL_SUPPORT_MESH_GPU_SKINNING -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7 +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES 7 #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 #endif -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX - #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX 9 +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM 9 #endif //---------------------------------------------------------------------------------- @@ -406,7 +396,7 @@ typedef struct rlVertexBuffer { // Draw call type // NOTE: Only texture changes register a new draw, other state-change-related elements are not -// used at this moment (vaoId, shaderId, matrices), raylib just forces a batch draw call if any +// used at this moment (vaoId, shaderId, matrices), raylib forces a batch draw call if any // of those state-change happens (this is done in core module) typedef struct rlDrawCall { int mode; // Drawing mode: LINES, TRIANGLES, QUADS @@ -433,7 +423,7 @@ typedef struct rlRenderBatch { // OpenGL version typedef enum { - RL_OPENGL_11_SOFTWARE = 0, // Software rendering + RL_OPENGL_SOFTWARE = 0, // Software rendering RL_OPENGL_11, // OpenGL 1.1 RL_OPENGL_21, // OpenGL 2.1 (GLSL 120) RL_OPENGL_33, // OpenGL 3.3 (GLSL 330) @@ -488,7 +478,7 @@ typedef enum { // NOTE 1: Filtering considers mipmaps if available in the texture // NOTE 2: Filter is accordingly set for minification and magnification typedef enum { - RL_TEXTURE_FILTER_POINT = 0, // No filter, just pixel approximation + RL_TEXTURE_FILTER_POINT = 0, // No filter, pixel approximation RL_TEXTURE_FILTER_BILINEAR, // Linear filtering RL_TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) RL_TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x @@ -772,21 +762,22 @@ RLAPI unsigned char *rlReadScreenPixels(int width, int height); // Rea // Framebuffer management (fbo) RLAPI unsigned int rlLoadFramebuffer(void); // Load an empty framebuffer -RLAPI void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer +RLAPI void rlFramebufferAttach(unsigned int id, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +// WARNING: Copy and resize framebuffer functionality only defined for software backend RLAPI void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels); // Copy framebuffer pixel data to internal buffer RLAPI void rlResizeFramebuffer(int width, int height); // Resize internal framebuffer -#endif // Shaders management -RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings -RLAPI unsigned int rlCompileShader(const char *shaderCode, int type); // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) -RLAPI unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program +RLAPI unsigned int rlLoadShader(const char *code, int type); // Load (compile) shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) +RLAPI unsigned int rlLoadShaderProgram(const char *vsCode, const char *fsCode); // Load shader from code strings +RLAPI unsigned int rlLoadShaderProgramEx(unsigned int vsId, unsigned int fsId); // Load shader program, using already loaded shader ids +RLAPI unsigned int rlLoadShaderProgramCompute(unsigned int csId); // Load compute shader program +RLAPI void rlUnloadShader(unsigned int id); // Unload shader, loaded with rlLoadShader() RLAPI void rlUnloadShaderProgram(unsigned int id); // Unload shader program -RLAPI int rlGetLocationUniform(unsigned int shaderId, const char *uniformName); // Get shader location uniform -RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName); // Get shader location attribute +RLAPI int rlGetLocationUniform(unsigned int id, const char *uniformName); // Get shader location uniform, requires shader program id +RLAPI int rlGetLocationAttrib(unsigned int id, const char *attribName); // Get shader location attribute, requires shader program id RLAPI void rlSetUniform(int locIndex, const void *value, int uniformType, int count); // Set shader value uniform RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat); // Set shader value matrix RLAPI void rlSetUniformMatrices(int locIndex, const Matrix *mat, int count); // Set shader value matrices @@ -794,7 +785,6 @@ RLAPI void rlSetUniformSampler(int locIndex, unsigned int textureId); RLAPI void rlSetShader(unsigned int id, int *locs); // Set shader currently active (id and locations) // Compute shader management -RLAPI unsigned int rlLoadComputeShaderProgram(unsigned int shaderId); // Load compute shader program RLAPI void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ); // Dispatch compute shader (equivalent to *draw* for graphics pipeline) // Shader buffer storage object management (ssbo) @@ -845,9 +835,10 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #endif #if defined(GRAPHICS_API_OPENGL_11) - #if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) + #if defined(GRAPHICS_API_OPENGL_SOFTWARE) #define RLSW_IMPLEMENTATION #define SW_MALLOC(sz) RL_MALLOC(sz) + #define SW_CALLOC(n,sz) RL_CALLOC(n, sz) #define SW_REALLOC(ptr, newSz) RL_REALLOC(ptr, newSz) #define SW_FREE(ptr) RL_FREE(ptr) #include "external/rlsw.h" // OpenGL 1.1 software implementation @@ -889,7 +880,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #elif defined(GRAPHICS_API_OPENGL_ES2) // NOTE: OpenGL ES 2.0 can be enabled on Desktop platforms, // in that case, functions are loaded from a custom glad for OpenGL ES 2.0 - // TODO: OpenGL ES 2.0 support shouldn't be platform-dependant, neither require GLAD + // TODO: OpenGL ES 2.0 support shouldn't be platform-dependent, neither require GLAD #if defined(PLATFORM_DESKTOP_GLFW) || defined(PLATFORM_DESKTOP_SDL) #define GLAD_GLES2_IMPLEMENTATION #include "external/glad_gles2.h" @@ -902,6 +893,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad // It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi // provided headers (despite being defined in official Khronos GLES2 headers) + // TODO: Avoid raylib platform-dependent code on rlgl, it should be a completely portable library #if defined(PLATFORM_DRM) typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); @@ -1000,31 +992,34 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad // Default shader vertex attribute names to set location points #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION - #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION + #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD + #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL - #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL + #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR - #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR + #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT + #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 + #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 #endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS - #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS "vertexBoneIds" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES + #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES #endif #ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS - #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS + #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS #endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX - #define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX +#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES + #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEMATRICES +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM + #define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM #endif #ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP @@ -1045,9 +1040,6 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) #endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES - #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES "boneMatrices" // bone matrices -#endif #ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) #endif @@ -1057,6 +1049,9 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) #endif +#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES + #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices (required for GPU skinning) +#endif //---------------------------------------------------------------------------------- // Module Types and Structures Definition @@ -1141,7 +1136,7 @@ typedef struct rlglData { } ExtSupported; // Extensions supported flags } rlglData; -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 //---------------------------------------------------------------------------------- // Global Variables Definition @@ -1151,7 +1146,8 @@ static double rlCullDistanceFar = RL_CULL_DISTANCE_FAR; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) static rlglData RLGL = { 0 }; -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +static bool isGpuReady = false; #if defined(GRAPHICS_API_OPENGL_ES2) && !defined(GRAPHICS_API_OPENGL_ES3) // NOTE: VAO functionality is exposed through extensions (OES) @@ -1171,10 +1167,10 @@ static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) static void rlLoadShaderDefault(void); // Load default shader static void rlUnloadShaderDefault(void); // Unload default shader -#if defined(RLGL_SHOW_GL_DETAILS_INFO) +#if RLGL_SHOW_GL_DETAILS_INFO static const char *rlGetCompressedFormatName(int format); // Get compressed format official GL identifier name -#endif // RLGL_SHOW_GL_DETAILS_INFO -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +#endif +#endif static int rlGetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) @@ -1251,7 +1247,7 @@ void rlPushMatrix(void) RLGL.State.stackCounter++; } -// Pop lattest inserted matrix from RLGL.State.stack +// Pop latest inserted matrix from RLGL.State.stack void rlPopMatrix(void) { if (RLGL.State.stackCounter > 0) @@ -1277,14 +1273,14 @@ void rlLoadIdentity(void) // Multiply the current matrix by a translation matrix void rlTranslatef(float x, float y, float z) { - Matrix matTranslation = { - 1.0f, 0.0f, 0.0f, x, - 0.0f, 1.0f, 0.0f, y, - 0.0f, 0.0f, 1.0f, z, - 0.0f, 0.0f, 0.0f, 1.0f - }; + Matrix matTranslation = rlMatrixIdentity(); - // NOTE: We transpose matrix with multiplication order + // Set translation component of matrix + matTranslation.m12 = x; + matTranslation.m13 = y; + matTranslation.m14 = z; + + // NOTE: Transposing matrix by multiplication order *RLGL.State.currentMatrix = rlMatrixMultiply(matTranslation, *RLGL.State.currentMatrix); } @@ -1329,21 +1325,21 @@ void rlRotatef(float angle, float x, float y, float z) matRotation.m14 = 0.0f; matRotation.m15 = 1.0f; - // NOTE: We transpose matrix with multiplication order + // NOTE: Transposing matrix by multiplication order *RLGL.State.currentMatrix = rlMatrixMultiply(matRotation, *RLGL.State.currentMatrix); } // Multiply the current matrix by a scaling matrix void rlScalef(float x, float y, float z) { - Matrix matScale = { - x, 0.0f, 0.0f, 0.0f, - 0.0f, y, 0.0f, 0.0f, - 0.0f, 0.0f, z, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; + Matrix matScale = rlMatrixIdentity(); - // NOTE: We transpose matrix with multiplication order + // Set scale component of matrix + matScale.m0 = x; + matScale.m5 = y; + matScale.m10 = z; + + // NOTE: Transposing matrix by multiplication order *RLGL.State.currentMatrix = rlMatrixMultiply(matScale, *RLGL.State.currentMatrix); } @@ -1351,6 +1347,7 @@ void rlScalef(float x, float y, float z) void rlMultMatrixf(const float *matf) { // Matrix creation from array + // Conversion from column-major to row-major memory order Matrix mat = { matf[0], matf[4], matf[8], matf[12], matf[1], matf[5], matf[9], matf[13], matf[2], matf[6], matf[10], matf[14], @@ -1395,7 +1392,7 @@ void rlFrustum(double left, double right, double bottom, double top, double znea void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar) { // NOTE: If left-right and top-botton values are equal it could create a division by zero, - // response to it is platform/compiler dependant + // response to it is platform/compiler dependent Matrix matOrtho = { 0 }; float rl = (float)(right - left); @@ -1424,7 +1421,6 @@ void rlOrtho(double left, double right, double bottom, double top, double znear, #endif // Set the viewport area (transformation from normalized device coordinates to window coordinates) -// NOTE: We store current viewport dimensions void rlViewport(int x, int y, int width, int height) { glViewport(x, y, width, height); @@ -1513,7 +1509,7 @@ void rlBegin(int mode) // Finish vertex providing void rlEnd(void) { - // NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values, + // NOTE: Depth increment is dependent on rlOrtho(): z-near and z-far values, // as well as depth buffer bit-depth (16bit or 24bit or 32bit) // Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits) RLGL.currentBatch->currentDepth += (1.0f/20000.0f); @@ -1535,9 +1531,9 @@ void rlVertex3f(float x, float y, float z) tz = RLGL.State.transform.m2*x + RLGL.State.transform.m6*y + RLGL.State.transform.m10*z + RLGL.State.transform.m14; } - // WARNING: We can't break primitives when launching a new batch + // WARNING: Be careful with primitives breaking when launching a new batch! // RL_LINES comes in pairs, RL_TRIANGLES come in groups of 3 vertices and RL_QUADS come in groups of 4 vertices - // We must check current draw.mode when a new vertex is required and finish the batch only if the draw.mode draw.vertexCount is %2, %3 or %4 + // Checking current draw.mode when a new vertex is required and finish the batch only if the draw.mode draw.vertexCount is %2, %3 or %4 if (RLGL.State.vertexCounter > (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4 - 4)) { if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_LINES) && @@ -1545,7 +1541,7 @@ void rlVertex3f(float x, float y, float z) { // Reached the maximum number of vertices for RL_LINES drawing // Launch a draw call but keep current state for next vertices comming - // NOTE: We add +1 vertex to the check for security + // NOTE: Adding +1 vertex to the check for some safety rlCheckRenderBatchLimit(2 + 1); } else if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) && @@ -1617,6 +1613,11 @@ void rlNormal3f(float x, float y, float z) normaly = RLGL.State.transform.m1*x + RLGL.State.transform.m5*y + RLGL.State.transform.m9*z; normalz = RLGL.State.transform.m2*x + RLGL.State.transform.m6*y + RLGL.State.transform.m10*z; } + + // NOTE: Default behavior assumes the normal vector is in the correct space for what the shader expects, + // it could be not normalized to 0.0f..1.0f, magnitud can be useed for some effects + /* + // WARNING: Vector normalization if required float length = sqrtf(normalx*normalx + normaly*normaly + normalz*normalz); if (length != 0.0f) { @@ -1625,6 +1626,7 @@ void rlNormal3f(float x, float y, float z) normaly *= ilength; normalz *= ilength; } + */ RLGL.State.normalx = normalx; RLGL.State.normaly = normaly; RLGL.State.normalz = normalz; @@ -1665,7 +1667,7 @@ void rlSetTexture(unsigned int id) #if defined(GRAPHICS_API_OPENGL_11) rlDisableTexture(); #else - // NOTE: If quads batch limit is reached, we force a draw call and next batch starts + // NOTE: If quads batch limit is reached, force a draw call and next batch starts if (RLGL.State.vertexCounter >= RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4) { @@ -1760,11 +1762,6 @@ void rlTextureParameters(unsigned int id, int param, int value) { glBindTexture(GL_TEXTURE_2D, id); -#if !defined(GRAPHICS_API_OPENGL_11) - // Reset anisotropy filter, in case it was set - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); -#endif - switch (param) { case RL_TEXTURE_WRAP_S: @@ -1784,6 +1781,9 @@ void rlTextureParameters(unsigned int id, int param, int value) case RL_TEXTURE_FILTER_ANISOTROPIC: { #if !defined(GRAPHICS_API_OPENGL_11) + // Reset anisotropy filter, in case it was set + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f) { @@ -1864,7 +1864,7 @@ void rlDisableShader(void) // Enable rendering to texture (fbo) void rlEnableFramebuffer(unsigned int id) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, id); #endif } @@ -1873,7 +1873,7 @@ void rlEnableFramebuffer(unsigned int id) unsigned int rlGetActiveFramebuffer(void) { GLint fboId = 0; -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fboId); #endif return fboId; @@ -1882,7 +1882,7 @@ unsigned int rlGetActiveFramebuffer(void) // Disable rendering to texture void rlDisableFramebuffer(void) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, 0); #endif } @@ -1890,7 +1890,7 @@ void rlDisableFramebuffer(void) // Blit active framebuffer to main framebuffer void rlBlitFramebuffer(int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, int bufferMask) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) glBlitFramebuffer(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask, GL_NEAREST); #endif } @@ -1898,7 +1898,7 @@ void rlBlitFramebuffer(int srcX, int srcY, int srcWidth, int srcHeight, int dstX // Bind framebuffer object (fbo) void rlBindFramebuffer(unsigned int target, unsigned int framebuffer) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glBindFramebuffer(target, framebuffer); #endif } @@ -1907,8 +1907,8 @@ void rlBindFramebuffer(unsigned int target, unsigned int framebuffer) // NOTE: One color buffer is always active by default void rlActiveDrawBuffers(int count) { -#if ((defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) && defined(RLGL_RENDER_TEXTURES_HINT)) - // NOTE: Maximum number of draw buffers supported is implementation dependant, +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) + // NOTE: Maximum number of draw buffers supported is implementation dependent, // it can be queried with glGet*() but it must be at least 8 //GLint maxDrawBuffers = 0; //glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); @@ -2218,7 +2218,7 @@ void rlSetBlendFactorsSeparate(int glSrcRGB, int glDstRGB, int glSrcAlpha, int g //---------------------------------------------------------------------------------- // Module Functions Definition - OpenGL Debug //---------------------------------------------------------------------------------- -#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43) +#if defined(GRAPHICS_API_OPENGL_43) && RLGL_ENABLE_OPENGL_DEBUG_CONTEXT static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) { // Ignore non-significant error/warning codes (NVidia drivers) @@ -2282,8 +2282,10 @@ static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint // Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states void rlglInit(int width, int height) { - // Enable OpenGL debug context if required -#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43) + isGpuReady = true; + + // Enable OpenGL debug context if requested (and supported) +#if defined(GRAPHICS_API_OPENGL_43) && RLGL_ENABLE_OPENGL_DEBUG_CONTEXT if ((glDebugMessageCallback != NULL) && (glDebugMessageControl != NULL)) { glDebugMessageCallback(rlDebugMessageCallback, 0); @@ -2327,7 +2329,17 @@ void rlglInit(int width, int height) RLGL.State.projection = rlMatrixIdentity(); RLGL.State.modelview = rlMatrixIdentity(); RLGL.State.currentMatrix = &RLGL.State.modelview; -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 + +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) + // Initialize software renderer backend + int result = swInit(width, height); + if (result == 0) + { + TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!"); + exit(-1); + } +#endif // Initialize OpenGL default states //---------------------------------------------------------- @@ -2345,39 +2357,28 @@ void rlglInit(int width, int height) glFrontFace(GL_CCW); // Front face are defined counter clockwise (default) glEnable(GL_CULL_FACE); // Enable backface culling - // Init state: Cubemap seamless -#if defined(GRAPHICS_API_OPENGL_33) - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0) -#endif - #if defined(GRAPHICS_API_OPENGL_11) // Init state: Color hints (deprecated in OpenGL 3.0+) glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) #endif - -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) - int result = swInit(width, height); // Initialize software renderer backend - if (result == 0) - { - TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!"); - exit(-1); - } +#if defined(GRAPHICS_API_OPENGL_33) + // Init state: Cubemap seamless + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0) #endif - #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Store screen size into global variables RLGL.State.framebufferWidth = width; RLGL.State.framebufferHeight = height; - - TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully"); - //---------------------------------------------------------- #endif // Init state: Color/Depth buffers clear glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black) glClearDepth(1.0f); // Set clear depth value (default) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D) + + TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully"); + //---------------------------------------------------------- } // Vertex Buffer Object deinitialization (memory free) @@ -2392,9 +2393,10 @@ void rlglClose(void) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId); #endif -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) swClose(); // Unload sofware renderer resources #endif + isGpuReady = false; } // Load OpenGL extensions @@ -2411,7 +2413,7 @@ void rlLoadExtensions(void *loader) glGetIntegerv(GL_NUM_EXTENSIONS, &numExt); TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt); -#if defined(RLGL_SHOW_GL_DETAILS_INFO) +#if RLGL_SHOW_GL_DETAILS_INFO // Get supported extensions list // WARNING: glGetStringi() not available on OpenGL 2.1 TRACELOG(RL_LOG_INFO, "GL: OpenGL extensions:"); @@ -2453,7 +2455,7 @@ void rlLoadExtensions(void *loader) RLGL.ExtSupported.ssbo = GLAD_GL_ARB_shader_storage_buffer_object; #endif -#endif // GRAPHICS_API_OPENGL_33 +#endif // GRAPHICS_API_OPENGL_33 #if defined(GRAPHICS_API_OPENGL_ES3) // Register supported extensions flags @@ -2491,13 +2493,13 @@ void rlLoadExtensions(void *loader) const char **extList = (const char **)RL_CALLOC(512, sizeof(const char *)); // Allocate 512 strings pointers (2 KB) const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string - // NOTE: We have to duplicate string because glGetString() returns a const string - int size = strlen(extensions) + 1; // Get extensions string size in bytes - char *extensionsDup = (char *)RL_CALLOC(size, sizeof(char)); - strcpy(extensionsDup, extensions); + // NOTE: String duplication rquired because glGetString() returns a const string + int extensionsLength = (int)strlen(extensions); // Get extensions string size in bytes + char *extensionsDup = (char *)RL_CALLOC(extensionsLength + 1, sizeof(char)); // Allocate space for copy with additional EOL byte + strncpy(extensionsDup, extensions, extensionsLength); extList[numExt] = extensionsDup; - for (int i = 0; i < size; i++) + for (int i = 0; i < extensionsLength; i++) { if (extensionsDup[i] == ' ') { @@ -2509,7 +2511,7 @@ void rlLoadExtensions(void *loader) TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt); -#if defined(RLGL_SHOW_GL_DETAILS_INFO) +#if RLGL_SHOW_GL_DETAILS_INFO TRACELOG(RL_LOG_INFO, "GL: OpenGL extensions:"); for (int i = 0; i < numExt; i++) TRACELOG(RL_LOG_INFO, " %s", extList[i]); #endif @@ -2619,7 +2621,7 @@ void rlLoadExtensions(void *loader) // Free extensions pointers RL_FREE(extList); RL_FREE(extensionsDup); // Duplicated string must be deallocated -#endif // GRAPHICS_API_OPENGL_ES2 +#endif // GRAPHICS_API_OPENGL_ES2 // Check OpenGL information and capabilities //------------------------------------------------------------------------------ @@ -2639,7 +2641,7 @@ void rlLoadExtensions(void *loader) #endif glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &RLGL.ExtSupported.maxAnisotropyLevel); -#if defined(RLGL_SHOW_GL_DETAILS_INFO) +#if RLGL_SHOW_GL_DETAILS_INFO // Show some OpenGL GPU capabilities TRACELOG(RL_LOG_INFO, "GL: OpenGL capabilities:"); GLint capability = 0; @@ -2670,8 +2672,9 @@ void rlLoadExtensions(void *loader) TRACELOG(RL_LOG_INFO, " GL_MAX_VERTEX_ATTRIB_BINDINGS: %i", capability); glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &capability); TRACELOG(RL_LOG_INFO, " GL_MAX_UNIFORM_LOCATIONS: %i", capability); -#endif // GRAPHICS_API_OPENGL_43 -#else // RLGL_SHOW_GL_DETAILS_INFO +#endif + +#else // !RLGL_SHOW_GL_DETAILS_INFO // Show some basic info about GL supported features if (RLGL.ExtSupported.vao) TRACELOG(RL_LOG_INFO, "GL: VAO extension detected, VAO functions loaded successfully"); @@ -2685,9 +2688,9 @@ void rlLoadExtensions(void *loader) if (RLGL.ExtSupported.texCompASTC) TRACELOG(RL_LOG_INFO, "GL: ASTC compressed textures supported"); if (RLGL.ExtSupported.computeShader) TRACELOG(RL_LOG_INFO, "GL: Compute shaders supported"); if (RLGL.ExtSupported.ssbo) TRACELOG(RL_LOG_INFO, "GL: Shader storage buffer objects supported"); -#endif // RLGL_SHOW_GL_DETAILS_INFO +#endif -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 } // Get OpenGL procedure address @@ -2705,8 +2708,8 @@ int rlGetVersion(void) { int glVersion = 0; -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) - glVersion = RL_OPENGL_11_SOFTWARE; +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) + glVersion = RL_OPENGL_SOFTWARE; #elif defined(GRAPHICS_API_OPENGL_11) glVersion = RL_OPENGL_11; #endif @@ -2799,6 +2802,7 @@ int *rlGetShaderLocsDefault(void) rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) { rlRenderBatch batch = { 0 }; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return batch; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes) @@ -2921,7 +2925,7 @@ rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) batch.bufferCount = numBuffers; // Record buffer count batch.drawCounter = 1; // Reset draws counter - batch.currentDepth = -1.0f; // Reset depth value + batch.currentDepth = -1.0f; // Reset depth value //-------------------------------------------------------------------------------------------- #endif @@ -2975,19 +2979,21 @@ void rlUnloadRenderBatch(rlRenderBatch batch) } // Draw render batch -// NOTE: We require a pointer to reset batch and increase current buffer (multi-buffer) +// NOTE: Batch is reseted and current buffer is updated (for multi-buffer config) void rlDrawRenderBatch(rlRenderBatch *batch) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Update batch vertex buffers //------------------------------------------------------------------------------------------------------------ // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0) - // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (use a change detector flag?) if (RLGL.State.vertexCounter > 0) { // Activate elements VAO if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId); + // TODO: If no data changed on the CPU arrays there is no need to re-upload data to GPU, + // a flag can be used to detect changes but it would imply keeping a copy buffer and memcmp() both, does it worth it? + // Vertex positions buffer glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]); glBufferSubData(GL_ARRAY_BUFFER, 0, RLGL.State.vertexCounter*3*sizeof(float), batch->vertexBuffer[batch->currentBuffer].vertices); @@ -3010,18 +3016,17 @@ void rlDrawRenderBatch(rlRenderBatch *batch) // NOTE: glMapBuffer() causes sync issue // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job - // To avoid waiting (idle), you can call first glBufferData() with NULL pointer before glMapBuffer() - // If you do that, the previous data in PBO will be discarded and glMapBuffer() returns a new + // To avoid waiting (idle), glBufferData() can bee called first with NULL pointer before glMapBuffer() + // Doing that, the previous data in PBO will be discarded and glMapBuffer() returns a new // allocated pointer immediately even if GPU is still working with the previous data // Another option: map the buffer object into client's memory - // Probably this code could be moved somewhere else... - // batch->vertexBuffer[batch->currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); - // if (batch->vertexBuffer[batch->currentBuffer].vertices) - // { - // Update vertex data - // } - // glUnmapBuffer(GL_ARRAY_BUFFER); + //batch->vertexBuffer[batch->currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); + //if (batch->vertexBuffer[batch->currentBuffer].vertices) + //{ + // Update vertex data + //} + //glUnmapBuffer(GL_ARRAY_BUFFER); // Unbind the current VAO if (RLGL.ExtSupported.vao) glBindVertexArray(0); @@ -3136,7 +3141,7 @@ void rlDrawRenderBatch(rlRenderBatch *batch) else { #if defined(GRAPHICS_API_OPENGL_33) - // We need to define the number of indices to be processed: elementCount*6 + // The number of indices to be processed needs to be defined: elementCount*6 // NOTE: The final parameter tells the GPU the offset in bytes from the // start of the index buffer to the location of the first index to process glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(vertexOffset/4*6*sizeof(GLuint))); @@ -3237,7 +3242,7 @@ bool rlCheckRenderBatchLimit(int vCount) rlDrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside - // Restore state of last batch so we can continue adding vertices + // Restore state of last batch so new vertices can be added RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = currentMode; RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = currentTexture; } @@ -3252,6 +3257,7 @@ bool rlCheckRenderBatchLimit(int vCount) unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding @@ -3259,6 +3265,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, #if defined(GRAPHICS_API_OPENGL_11) if (format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) { + // TODO: Support texture data decompression TRACELOG(RL_LOG_WARNING, "GL: OpenGL 1.1 does not support GPU compressed texture formats"); return id; } @@ -3294,7 +3301,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, return id; } #endif -#endif // GRAPHICS_API_OPENGL_11 +#endif // GRAPHICS_API_OPENGL_11 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); @@ -3319,7 +3326,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, unsigned int glInternalFormat, glFormat, glType; rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); - TRACELOGD("TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset); + TRACELOG(RL_LOG_DEBUG, "TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset); if (glInternalFormat != 0) { @@ -3348,8 +3355,8 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, mipWidth /= 2; mipHeight /= 2; - mipOffset += mipSize; // Increment offset position to next mipmap - if (data != NULL) dataPtr += mipSize; // Increment data pointer to next mipmap + mipOffset += mipSize; // Increment offset position to next mipmap + if (data != NULL) dataPtr += mipSize; // Increment data pointer to next mipmap // Security check for NPOT textures if (mipWidth < 1) mipWidth = 1; @@ -3357,7 +3364,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, } // Texture parameters configuration - // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used + // NOTE: glTexParameteri does NOT affect texture uploading #if defined(GRAPHICS_API_OPENGL_ES2) // NOTE: OpenGL ES 2.0 with no GL_OES_texture_npot support (i.e. WebGL) has limited NPOT support, so CLAMP_TO_EDGE must be used if (RLGL.ExtSupported.texNPOT) @@ -3383,14 +3390,22 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, #if defined(GRAPHICS_API_OPENGL_33) if (mipmapCount > 1) { - // Activate Trilinear filtering if mipmaps are available + // Activate trilinear filtering if mipmaps are available glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount); // Required for user-defined mip count + + // Define the maximum number of mipmap levels to be used, 0 is base texture size + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount - 1); + + // Check if the loaded texture with mipmaps is complete, + // uncomplete textures will draw in black if mipmap filtering is required + //GLint complete = 0; + //glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_FORMAT, &complete); } #endif - // At this point we have the texture loaded in GPU and texture parameters configured + // At this point texture is loaded in GPU and texture parameters configured // NOTE: If mipmaps were not in data, they are not generated automatically @@ -3408,16 +3423,17 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // In case depth textures not supported, we force renderbuffer usage + // In case depth textures were not supported, force renderbuffer usage if (!RLGL.ExtSupported.texDepth) useRenderBuffer = true; - // NOTE: We let the implementation to choose the best bit-depth + // NOTE: Letting the implementation to choose the best bit-depth // Possible formats: GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32 and GL_DEPTH_COMPONENT32F unsigned int glInternalFormat = GL_DEPTH_COMPONENT; -#if (defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_ES3)) +#if defined(GRAPHICS_API_OPENGL_ES2) // WARNING: WebGL platform requires unsized internal format definition (GL_DEPTH_COMPONENT) // while other platforms using OpenGL ES 2.0 require/support sized internal formats depending on the GPU capabilities if (!RLGL.ExtSupported.texDepthWebGL || useRenderBuffer) @@ -3427,6 +3443,13 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) else glInternalFormat = GL_DEPTH_COMPONENT16; } #endif +#if defined(GRAPHICS_API_OPENGL_ES3) + // NOTE: This sized internal format should also work for WebGL 2.0 + // WARNING: Specification only allows GL_DEPTH_COMPONENT32F for GL_FLOAT type + // REF: https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml + if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24; + else glInternalFormat = GL_DEPTH_COMPONENT16; +#endif if (!useRenderBuffer && RLGL.ExtSupported.texDepth) { @@ -3455,6 +3478,13 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Depth renderbuffer loaded successfully (%i bits)", id, (RLGL.ExtSupported.maxDepthBits >= 24)? RLGL.ExtSupported.maxDepthBits : 16); } +#elif defined(GRAPHICS_API_OPENGL_SOFTWARE) + // NOTE: Renderbuffers are the same type of object as textures in rlsw + // WARNING: Ensure that the depth format is the one specified at rlsw compilation + glGenRenderbuffers(1, &id); + glBindRenderbuffer(GL_RENDERBUFFER, id); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); #endif return id; @@ -3466,6 +3496,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mipmapCount) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) int mipSize = size; @@ -3558,7 +3589,7 @@ unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mi } // Update already loaded texture in GPU with new data -// NOTE: We don't know safely if internal texture format is the expected one... +// WARNING: Not possible to know safely if internal texture format is the expected one... void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data) { glBindTexture(GL_TEXTURE_2D, id); @@ -3692,7 +3723,7 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) glBindTexture(GL_TEXTURE_2D, id); - // NOTE: Using texture id, we can retrieve some texture info (but not on OpenGL ES 2.0) + // NOTE: Using texture id, some texture info can be retrieved (but not on OpenGL ES 2.0) // Possible texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE //int width, height, format; //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); @@ -3725,7 +3756,7 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) // Two possible Options: // 1 - Bind texture to color fbo attachment and glReadPixels() // 2 - Create an fbo, activate it, render quad with texture, glReadPixels() - // We are using Option 1, just need to care for texture format on retrieval + // Using Option 1, care for texture format on retrieval // NOTE: This behaviour could be conditioned by graphic driver... unsigned int fboId = rlLoadFramebuffer(); @@ -3735,7 +3766,7 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) // Attach our texture to FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0); - // We read data as RGBA because FBO texture is configured as RGBA, despite binding another texture format + // Reading data as RGBA because FBO texture is configured as RGBA, despite binding another texture format pixels = RL_CALLOC(rlGetPixelDataSize(width, height, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8), 1); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); @@ -3748,33 +3779,35 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) return pixels; } -#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE) // Copy framebuffer pixel data to internal buffer -void rlCopyFramebuffer(int x, int y, int width, int height, int format, void* pixels) +void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels) { +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) unsigned int glInternalFormat, glFormat, glType; rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); // Get OpenGL texture format - swCopyFramebuffer(x, y, width, height, glFormat, glType, pixels); + swReadPixels(x, y, width, height, glFormat, glType, pixels); +#endif } // Resize internal framebuffer void rlResizeFramebuffer(int width, int height) { - swResizeFramebuffer(width, height); -} +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) + swResize(width, height); #endif +} // Read screen pixel data (color buffer) unsigned char *rlReadScreenPixels(int width, int height) { unsigned char *imgData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char)); - // NOTE 1: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer - // NOTE 2: We are getting alpha channel! Be careful, it can be transparent if not cleared properly! + // NOTE: glReadPixels() returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer + // WARNING: Getting alpha channel! Be careful, it can be transparent if not cleared properly! glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imgData); - // Flip image vertically! - // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it! + // Flip image vertically + // NOTE: Alpha value has already been applied to RGB in framebuffer, not needed anymore for (int y = height - 1; y >= height/2; y--) { for (int x = 0; x < (width*4); x += 4) @@ -3808,21 +3841,22 @@ unsigned char *rlReadScreenPixels(int width, int height) unsigned int rlLoadFramebuffer(void) { unsigned int fboId = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return fboId; } -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) - glGenFramebuffers(1, &fboId); // Create the framebuffer object - glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) + glGenFramebuffers(1, &fboId); // Create the framebuffer object + glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer #endif return fboId; } -// Attach color buffer texture to an fbo (unloads previous attachment) +// Attach color buffer texture to a framebuffer object (unloads previous attachment) // NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture -void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel) +void rlFramebufferAttach(unsigned int id, unsigned int texId, int attachType, int texType, int mipLevel) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) - glBindFramebuffer(GL_FRAMEBUFFER, fboId); +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) + glBindFramebuffer(GL_FRAMEBUFFER, id); switch (attachType) { @@ -3861,7 +3895,7 @@ bool rlFramebufferComplete(unsigned int id) { bool result = false; -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) glBindFramebuffer(GL_FRAMEBUFFER, id); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -3892,15 +3926,15 @@ bool rlFramebufferComplete(unsigned int id) // NOTE: All attached textures/cubemaps/renderbuffers are also deleted void rlUnloadFramebuffer(unsigned int id) { -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) // Query depth attachment to automatically delete texture/renderbuffer - int depthType = 0, depthId = 0; + int depthType = 0; glBindFramebuffer(GL_FRAMEBUFFER, id); // Bind framebuffer to query depth texture type glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &depthType); - // TODO: Review warning retrieving object name in WebGL // WARNING: WebGL: INVALID_ENUM: getFramebufferAttachmentParameter: invalid parameter name - // https://registry.khronos.org/webgl/specs/latest/1.0/ + // REF: https://registry.khronos.org/webgl/specs/latest/1.0/ + int depthId = 0; glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthId); unsigned int depthIdU = (unsigned int)depthId; @@ -3923,6 +3957,7 @@ void rlUnloadFramebuffer(unsigned int id) unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glGenBuffers(1, &id); @@ -3937,6 +3972,7 @@ unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic) unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic) { unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) glGenBuffers(1, &id); @@ -4102,12 +4138,12 @@ void rlDisableStatePointer(int vertexAttribType) unsigned int rlLoadVertexArray(void) { unsigned int vaoId = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return vaoId; } + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (RLGL.ExtSupported.vao) - { - glGenVertexArrays(1, &vaoId); - } + if (RLGL.ExtSupported.vao) glGenVertexArrays(1, &vaoId); #endif + return vaoId; } @@ -4157,11 +4193,77 @@ void rlUnloadVertexBuffer(unsigned int vboId) // Shaders management //----------------------------------------------------------------------------------------------- -// Load shader from code strings -// NOTE: If shader string is NULL, using default vertex/fragment shaders -unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) +// Load (compile) shader and return shader id +unsigned int rlLoadShader(const char *code, int type) { - unsigned int id = 0; + unsigned int shaderId = 0; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + shaderId = glCreateShader(type); + glShaderSource(shaderId, 1, &code, NULL); + + GLint success = 0; + glCompileShader(shaderId); + glGetShaderiv(shaderId, GL_COMPILE_STATUS, &success); + + if (success == GL_FALSE) + { + switch (type) + { + case GL_VERTEX_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shaderId); break; + case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shaderId); break; + //case GL_GEOMETRY_SHADER: + #if defined(GRAPHICS_API_OPENGL_43) + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile compute shader code", shaderId); break; + #elif defined(GRAPHICS_API_OPENGL_33) + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shaderId); break; + #endif + default: break; + } + + int maxLength = 0; + glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &maxLength); + + if (maxLength > 0) + { + int length = 0; + char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); + glGetShaderInfoLog(shaderId, maxLength, &length, log); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shaderId, log); + RL_FREE(log); + } + + // Unload object allocated by glCreateShader(), + // despite failing in the compilation process + glDeleteShader(shaderId); + shaderId = 0; + } + else + { + switch (type) + { + case GL_VERTEX_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shaderId); break; + case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shaderId); break; + //case GL_GEOMETRY_SHADER: + #if defined(GRAPHICS_API_OPENGL_43) + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader compiled successfully", shaderId); break; + #elif defined(GRAPHICS_API_OPENGL_33) + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shaderId); break; + #endif + default: break; + } + } +#endif + + return shaderId; +} + +// Load shader program from code strings +// NOTE: If shader string is NULL, using default vertex/fragment shaders +unsigned int rlLoadShaderProgram(const char *vsCode, const char *fsCode) +{ + unsigned int id = 0; // Shader program id + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) unsigned int vertexShaderId = 0; @@ -4169,23 +4271,23 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) // Compile vertex shader (if provided) // NOTE: If not vertex shader is provided, use default one - if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER); + if (vsCode != NULL) vertexShaderId = rlLoadShader(vsCode, GL_VERTEX_SHADER); else vertexShaderId = RLGL.State.defaultVShaderId; // Compile fragment shader (if provided) // NOTE: If not vertex shader is provided, use default one - if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER); + if (fsCode != NULL) fragmentShaderId = rlLoadShader(fsCode, GL_FRAGMENT_SHADER); else fragmentShaderId = RLGL.State.defaultFShaderId; - // In case vertex and fragment shader are the default ones, no need to recompile, we can just assign the default shader program id + // In case vertex and fragment shader are the default ones, no need to recompile, assign the default shader program id if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId; else if ((vertexShaderId > 0) && (fragmentShaderId > 0)) { - // One of or both shader are new, we need to compile a new shader program - id = rlLoadShaderProgram(vertexShaderId, fragmentShaderId); + // One of or both shader are new, a new shader program needs to be compiled + id = rlLoadShaderProgramEx(vertexShaderId, fragmentShaderId); - // We can detach and delete vertex/fragment shaders (if not default ones) - // NOTE: We detach shader before deletion to make sure memory is freed + // Detaching and deleting vertex/fragment shaders (if not default ones) + // WARNING: Detach shader before deletion to make sure memory is freed if (vertexShaderId != RLGL.State.defaultVShaderId) { // WARNING: Shader program linkage could fail and returned id is 0 @@ -4199,10 +4301,10 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) glDeleteShader(fragmentShaderId); } - // In case shader program loading failed, we assign default shader + // In case shader program loading failed, assign default shader if (id == 0) { - // In case shader loading fails, we return the default shader + // In case shader loading fails, reassigning default shader TRACELOG(RL_LOG_WARNING, "SHADER: Failed to load custom shader code, using default shader"); id = RLGL.State.defaultShaderId; } @@ -4225,7 +4327,7 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name); name[namelen] = 0; - TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name)); + TRACELOG(RL_LOG_DEBUG, "SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name)); } } */ @@ -4235,124 +4337,57 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) return id; } -// Compile custom shader and return shader id -unsigned int rlCompileShader(const char *shaderCode, int type) +// Load shader program from already loaded shader ids +unsigned int rlLoadShaderProgramEx(unsigned int vsId, unsigned int fsId) { - unsigned int shader = 0; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - shader = glCreateShader(type); - glShaderSource(shader, 1, &shaderCode, NULL); - - GLint success = 0; - glCompileShader(shader); - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - - if (success == GL_FALSE) - { - switch (type) - { - case GL_VERTEX_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shader); break; - case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shader); break; - //case GL_GEOMETRY_SHADER: - #if defined(GRAPHICS_API_OPENGL_43) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile compute shader code", shader); break; - #elif defined(GRAPHICS_API_OPENGL_33) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shader); break; - #endif - default: break; - } - - int maxLength = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); - - if (maxLength > 0) - { - int length = 0; - char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); - glGetShaderInfoLog(shader, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shader, log); - RL_FREE(log); - } - - // Unload object allocated by glCreateShader(), - // despite failing in the compilation process - glDeleteShader(shader); - shader = 0; - } - else - { - switch (type) - { - case GL_VERTEX_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shader); break; - case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shader); break; - //case GL_GEOMETRY_SHADER: - #if defined(GRAPHICS_API_OPENGL_43) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader compiled successfully", shader); break; - #elif defined(GRAPHICS_API_OPENGL_33) - case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shader); break; - #endif - default: break; - } - } -#endif - - return shader; -} - -// Load custom shader strings and return program id -unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) -{ - unsigned int program = 0; + unsigned int programId = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return programId; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) GLint success = 0; - program = glCreateProgram(); + programId = glCreateProgram(); - glAttachShader(program, vShaderId); - glAttachShader(program, fShaderId); + glAttachShader(programId, vsId); + glAttachShader(programId, fsId); - // NOTE: Default attribute shader locations must be Bound before linking - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCE_TX, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCE_TX); + // Default attribute shader locations must be bound before linking + // NOTE: There is no problem with binding a generic attribute index to an attribute variable name + // that is never used; if some attrib name is no found on the shader, it locations becomes -1 + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); -#ifdef RL_SUPPORT_MESH_GPU_SKINNING - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS); - glBindAttribLocation(program, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); -#endif - - // NOTE: If some attrib name is no found on the shader, it locations becomes -1 - - glLinkProgram(program); + glLinkProgram(programId); // NOTE: All uniform variables are intitialised to 0 when a program links - glGetProgramiv(program, GL_LINK_STATUS, &success); + glGetProgramiv(programId, GL_LINK_STATUS, &success); if (success == GL_FALSE) { - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", program); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", programId); int maxLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); + glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength); if (maxLength > 0) { int length = 0; char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); - glGetProgramInfoLog(program, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log); + glGetProgramInfoLog(programId, maxLength, &length, log); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", programId, log); RL_FREE(log); } - glDeleteProgram(program); + glDeleteProgram(programId); - program = 0; + programId = 0; } else { @@ -4361,10 +4396,73 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) //GLint binarySize = 0; //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", program); + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", programId); } #endif - return program; + return programId; +} + +// Load compute shader program +unsigned int rlLoadShaderProgramCompute(unsigned int csId) +{ + unsigned int programId = 0; + +#if defined(GRAPHICS_API_OPENGL_43) + GLint success = 0; + programId = glCreateProgram(); + + glAttachShader(programId, csId); + + glLinkProgram(programId); + + // NOTE: All uniform variables are intitialised to 0 when a program links + + glGetProgramiv(programId, GL_LINK_STATUS, &success); + + if (success == GL_FALSE) + { + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", programId); + + int maxLength = 0; + glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength); + + if (maxLength > 0) + { + int length = 0; + char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); + glGetProgramInfoLog(programId, maxLength, &length, log); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", programId, log); + RL_FREE(log); + } + + glDeleteProgram(programId); + + programId = 0; + } + else + { + // Get the size of compiled shader program (not available on OpenGL ES 2.0) + // NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero + //GLint binarySize = 0; + //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", programId); + } +#else + TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not supported, enable GRAPHICS_API_OPENGL_43"); +#endif + + return programId; +} + +// Delete shader +void rlUnloadShader(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glDeleteShader(id); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Unloaded shader data from VRAM (GPU)", id); +#endif } // Unload shader program @@ -4378,11 +4476,12 @@ void rlUnloadShaderProgram(unsigned int id) } // Get shader location uniform -int rlGetLocationUniform(unsigned int shaderId, const char *uniformName) +// NOTE: First parameter refers to shader program id +int rlGetLocationUniform(unsigned int id, const char *uniformName) { int location = -1; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - location = glGetUniformLocation(shaderId, uniformName); + location = glGetUniformLocation(id, uniformName); //if (location == -1) TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to find shader uniform: %s", shaderId, uniformName); //else TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Shader uniform (%s) set at location: %i", shaderId, uniformName, location); @@ -4391,11 +4490,12 @@ int rlGetLocationUniform(unsigned int shaderId, const char *uniformName) } // Get shader location attribute -int rlGetLocationAttrib(unsigned int shaderId, const char *attribName) +// NOTE: First parameter refers to shader program id +int rlGetLocationAttrib(unsigned int id, const char *attribName) { int location = -1; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - location = glGetAttribLocation(shaderId, attribName); + location = glGetAttribLocation(id, attribName); //if (location == -1) TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to find shader attribute: %s", shaderId, attribName); //else TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Shader attribute (%s) set at location: %i", shaderId, attribName, location); @@ -4425,8 +4525,6 @@ void rlSetUniform(int locIndex, const void *value, int uniformType, int count) #endif case RL_SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break; default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized"); - - // TODO: Support glUniform1uiv(), glUniform2uiv(), glUniform3uiv(), glUniform4uiv() } #endif } @@ -4450,13 +4548,7 @@ void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType void rlSetUniformMatrix(int locIndex, Matrix mat) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - float matfloat[16] = { - mat.m0, mat.m1, mat.m2, mat.m3, - mat.m4, mat.m5, mat.m6, mat.m7, - mat.m8, mat.m9, mat.m10, mat.m11, - mat.m12, mat.m13, mat.m14, mat.m15 - }; - glUniformMatrix4fv(locIndex, 1, false, matfloat); + glUniformMatrix4fv(locIndex, 1, false, rlMatrixToFloat(mat)); #endif } @@ -4513,57 +4605,6 @@ void rlSetShader(unsigned int id, int *locs) #endif } -// Load compute shader program -unsigned int rlLoadComputeShaderProgram(unsigned int shaderId) -{ - unsigned int program = 0; - -#if defined(GRAPHICS_API_OPENGL_43) - GLint success = 0; - program = glCreateProgram(); - glAttachShader(program, shaderId); - glLinkProgram(program); - - // NOTE: All uniform variables are intitialised to 0 when a program links - - glGetProgramiv(program, GL_LINK_STATUS, &success); - - if (success == GL_FALSE) - { - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", program); - - int maxLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); - - if (maxLength > 0) - { - int length = 0; - char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); - glGetProgramInfoLog(program, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log); - RL_FREE(log); - } - - glDeleteProgram(program); - - program = 0; - } - else - { - // Get the size of compiled shader program (not available on OpenGL ES 2.0) - // NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero - //GLint binarySize = 0; - //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); - - TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", program); - } -#else - TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43"); -#endif - - return program; -} - // Dispatch compute shader (equivalent to *draw* for graphics pilepine) void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ) { @@ -4598,7 +4639,6 @@ void rlUnloadShaderBuffer(unsigned int ssboId) #else TRACELOG(RL_LOG_WARNING, "SSBO: SSBO not enabled. Define GRAPHICS_API_OPENGL_43"); #endif - } // Update SSBO buffer data @@ -4613,14 +4653,14 @@ void rlUpdateShaderBuffer(unsigned int id, const void *data, unsigned int dataSi // Get SSBO buffer size unsigned int rlGetShaderBufferSize(unsigned int id) { + unsigned int result = 0; #if defined(GRAPHICS_API_OPENGL_43) GLint64 size = 0; glBindBuffer(GL_SHADER_STORAGE_BUFFER, id); glGetBufferParameteri64v(GL_SHADER_STORAGE_BUFFER, GL_BUFFER_SIZE, &size); - return (size > 0)? (unsigned int)size : 0; -#else - return 0; + if (size > 0) result = (unsigned int)size; #endif + return result; } // Read SSBO buffer data (GPU->CPU) @@ -4729,9 +4769,9 @@ Matrix rlGetMatrixTransform(void) Matrix mat = rlMatrixIdentity(); #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // TODO: Consider possible transform matrices in the RLGL.State.stack - // Is this the right order? or should we start with the first stored matrix instead of the last one? //Matrix matStackTransform = rlMatrixIdentity(); //for (int i = RLGL.State.stackCounter; i > 0; i--) matStackTransform = rlMatrixMultiply(RLGL.State.stack[i], matStackTransform); + mat = RLGL.State.transform; #endif return mat; @@ -5057,10 +5097,10 @@ static void rlLoadShaderDefault(void) // NOTE: Compiled vertex/fragment shaders are not deleted, // they are kept for re-use as default shaders in case some shader loading fails - RLGL.State.defaultVShaderId = rlCompileShader(defaultVShaderCode, GL_VERTEX_SHADER); // Compile default vertex shader - RLGL.State.defaultFShaderId = rlCompileShader(defaultFShaderCode, GL_FRAGMENT_SHADER); // Compile default fragment shader + RLGL.State.defaultVShaderId = rlLoadShader(defaultVShaderCode, GL_VERTEX_SHADER); // Compile default vertex shader + RLGL.State.defaultFShaderId = rlLoadShader(defaultFShaderCode, GL_FRAGMENT_SHADER); // Compile default fragment shader - RLGL.State.defaultShaderId = rlLoadShaderProgram(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId); + RLGL.State.defaultShaderId = rlLoadShaderProgramEx(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId); if (RLGL.State.defaultShaderId > 0) { @@ -5097,7 +5137,7 @@ static void rlUnloadShaderDefault(void) TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default shader unloaded successfully", RLGL.State.defaultShaderId); } -#if defined(RLGL_SHOW_GL_DETAILS_INFO) +#if RLGL_SHOW_GL_DETAILS_INFO // Get compressed format official GL identifier name static const char *rlGetCompressedFormatName(int format) { @@ -5171,9 +5211,9 @@ static const char *rlGetCompressedFormatName(int format) default: return "GL_COMPRESSED_UNKNOWN"; break; } } -#endif // RLGL_SHOW_GL_DETAILS_INFO +#endif -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 // Get pixel data size in bytes (image or texture) // NOTE: Size depends on pixel format @@ -5202,24 +5242,36 @@ static int rlGetPixelDataSize(int width, int height, int format) case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB: case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB: case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB: - case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break; + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: // 8 bytes per each 4x4 block + { + int blockWidth = (width + 3)/4; + int blockHeight = (height + 3)/4; + dataSize = blockWidth*blockHeight*8; + } break; case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA: case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA: case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: - case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break; - case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; + case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: // 16 bytes per each 4x4 block + { + int blockWidth = (width + 3)/4; + int blockHeight = (height + 3)/4; + dataSize = blockWidth*blockHeight*16; + } break; + case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 4 bytes per each 4x4 block + { + int blockWidth = (width + 3)/4; + int blockHeight = (height + 3)/4; + dataSize = blockWidth*blockHeight*4; + } break; default: break; } - double bytesPerPixel = (double)bpp/8.0; - dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes - - // Most compressed formats works on 4x4 blocks, - // if texture is smaller, minimum dataSize is 8 or 16 - if ((width < 4) && (height < 4)) + // Compute dataSize for uncompressed texture data (no blocks) + if ((format >= RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) && + (format <= RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16)) { - if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8; - else if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16; + double bytesPerPixel = (double)bpp/8.0; + dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes } return dataSize; @@ -5230,17 +5282,17 @@ static int rlGetPixelDataSize(int width, int height, int format) // Get identity matrix static Matrix rlMatrixIdentity(void) { - Matrix result = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; + Matrix matIdentity = { 0 }; + matIdentity.m0 = 1.0f; + matIdentity.m5 = 1.0f; + matIdentity.m10 = 1.0f; + matIdentity.m15 = 1.0f; - return result; + return matIdentity; } #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Get float array of matrix data +// Explicit conversion to column-major memory layout static rl_float16 rlMatrixToFloatV(Matrix mat) { rl_float16 result = { 0 }; @@ -5364,4 +5416,4 @@ static Matrix rlMatrixInvert(Matrix mat) } #endif -#endif // RLGL_IMPLEMENTATION \ No newline at end of file +#endif // RLGL_IMPLEMENTATION diff --git a/lib/rlgl.zig b/lib/rlgl.zig index fe62459..7846dd7 100644 --- a/lib/rlgl.zig +++ b/lib/rlgl.zig @@ -6,7 +6,7 @@ const std = @import("std"); pub const cdef = @import("rlgl-ext.zig"); test { - std.testing.refAllDeclsRecursive(@This()); + std.testing.refAllDecls(@This()); } const Matrix = rl.Matrix; @@ -39,7 +39,7 @@ pub const rlRenderBatch = extern struct { }; pub const rlGlVersion = enum(c_int) { - rl_opengl_11_software = 0, + rl_opengl_software = 0, rl_opengl_11 = 1, rl_opengl_21 = 2, rl_opengl_33 = 3, @@ -268,9 +268,9 @@ pub const rl_default_shader_attrib_location_color = @as(i32, 3); pub const rl_default_shader_attrib_location_tangent = @as(i32, 4); pub const rl_default_shader_attrib_location_texcoord2 = @as(i32, 5); pub const rl_default_shader_attrib_location_indices = @as(i32, 6); -pub const rl_default_shader_attrib_location_boneids = @as(i32, 7); -pub const rl_default_shader_attrib_location_boneweights = @as(i32, 5); -pub const rl_default_shader_attrib_location_instance_tx = @as(i32, 9); +pub const rl_default_shader_attrib_location_boneindices = @as(i32, 7); +pub const rl_default_shader_attrib_location_boneweights = @as(i32, 8); +pub const rl_default_shader_attrib_location_instancetransform = @as(i32, 9); /// Choose the current matrix to be transformed pub fn rlMatrixMode(mode: i32) void { @@ -896,8 +896,8 @@ pub fn rlLoadFramebuffer() u32 { } /// Attach texture/renderbuffer to a framebuffer -pub fn rlFramebufferAttach(fboId: u32, texId: u32, attachType: i32, texType: i32, mipLevel: i32) void { - cdef.rlFramebufferAttach(@as(c_uint, fboId), @as(c_uint, texId), @as(c_int, attachType), @as(c_int, texType), @as(c_int, mipLevel)); +pub fn rlFramebufferAttach(id: u32, texId: u32, attachType: i32, texType: i32, mipLevel: i32) void { + cdef.rlFramebufferAttach(@as(c_uint, id), @as(c_uint, texId), @as(c_int, attachType), @as(c_int, texType), @as(c_int, mipLevel)); } /// Verify framebuffer is complete @@ -920,19 +920,29 @@ pub fn rlResizeFramebuffer(width: i32, height: i32) void { cdef.rlResizeFramebuffer(@as(c_int, width), @as(c_int, height)); } +/// Load (compile) shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) +pub fn rlLoadShader(code: [:0]const u8, ty: i32) u32 { + return @as(u32, cdef.rlLoadShader(@as([*c]const u8, @ptrCast(code)), @as(c_int, ty))); +} + /// Load shader from code strings -pub fn rlLoadShaderCode(vsCode: ?[:0]const u8, fsCode: ?[:0]const u8) u32 { - return @as(u32, cdef.rlLoadShaderCode(@as([*c]const u8, @ptrCast(vsCode)), @as([*c]const u8, @ptrCast(fsCode)))); +pub fn rlLoadShaderProgram(vsCode: [:0]const u8, fsCode: [:0]const u8) u32 { + return @as(u32, cdef.rlLoadShaderProgram(@as([*c]const u8, @ptrCast(vsCode)), @as([*c]const u8, @ptrCast(fsCode)))); } -/// Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) -pub fn rlCompileShader(shaderCode: [:0]const u8, ty: i32) u32 { - return @as(u32, cdef.rlCompileShader(@as([*c]const u8, @ptrCast(shaderCode)), @as(c_int, ty))); +/// Load shader program, using already loaded shader ids +pub fn rlLoadShaderProgramEx(vsId: u32, fsId: u32) u32 { + return @as(u32, cdef.rlLoadShaderProgramEx(@as(c_uint, vsId), @as(c_uint, fsId))); } -/// Load custom shader program -pub fn rlLoadShaderProgram(vShaderId: u32, fShaderId: u32) u32 { - return @as(u32, cdef.rlLoadShaderProgram(@as(c_uint, vShaderId), @as(c_uint, fShaderId))); +/// Load compute shader program +pub fn rlLoadShaderProgramCompute(csId: u32) u32 { + return @as(u32, cdef.rlLoadShaderProgramCompute(@as(c_uint, csId))); +} + +/// Unload shader, loaded with rlLoadShader() +pub fn rlUnloadShader(id: u32) void { + cdef.rlUnloadShader(@as(c_uint, id)); } /// Unload shader program @@ -940,14 +950,14 @@ pub fn rlUnloadShaderProgram(id: u32) void { cdef.rlUnloadShaderProgram(@as(c_uint, id)); } -/// Get shader location uniform -pub fn rlGetLocationUniform(shaderId: u32, uniformName: [:0]const u8) i32 { - return @as(i32, cdef.rlGetLocationUniform(@as(c_uint, shaderId), @as([*c]const u8, @ptrCast(uniformName)))); +/// Get shader location uniform, requires shader program id +pub fn rlGetLocationUniform(id: u32, uniformName: [:0]const u8) i32 { + return @as(i32, cdef.rlGetLocationUniform(@as(c_uint, id), @as([*c]const u8, @ptrCast(uniformName)))); } -/// Get shader location attribute -pub fn rlGetLocationAttrib(shaderId: u32, attribName: [:0]const u8) i32 { - return @as(i32, cdef.rlGetLocationAttrib(@as(c_uint, shaderId), @as([*c]const u8, @ptrCast(attribName)))); +/// Get shader location attribute, requires shader program id +pub fn rlGetLocationAttrib(id: u32, attribName: [:0]const u8) i32 { + return @as(i32, cdef.rlGetLocationAttrib(@as(c_uint, id), @as([*c]const u8, @ptrCast(attribName)))); } /// Set shader value uniform @@ -975,11 +985,6 @@ pub fn rlSetShader(id: u32, locs: []i32) void { cdef.rlSetShader(@as(c_uint, id), @as([*c]c_int, @ptrCast(locs))); } -/// Load compute shader program -pub fn rlLoadComputeShaderProgram(shaderId: u32) u32 { - return @as(u32, cdef.rlLoadComputeShaderProgram(@as(c_uint, shaderId))); -} - /// Dispatch compute shader (equivalent to *draw* for graphics pipeline) pub fn rlComputeShaderDispatch(groupX: u32, groupY: u32, groupZ: u32) void { cdef.rlComputeShaderDispatch(@as(c_uint, groupX), @as(c_uint, groupY), @as(c_uint, groupZ));