diff --git a/BINDINGS.md b/BINDINGS.md
index 7fd0dfd93..576d9b463 100644
--- a/BINDINGS.md
+++ b/BINDINGS.md
@@ -9,7 +9,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [raylib](https://github.com/raysan5/raylib) | **5.0** | [C/C++](https://en.wikipedia.org/wiki/C_(programming_language)) | Zlib |
| [raylib-beef](https://github.com/Starpelly/raylib-beef) | **5.0** | [Beef](https://www.beeflang.org) | MIT |
| [raylib-boo](https://github.com/Rabios/raylib-boo) | 3.7 | [Boo](http://boo-language.github.io) | MIT |
-| [raybit](https://github.com/Alex-Velez/raybit) | 3.7 | [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) | MIT |
+| [raybit](https://github.com/Alex-Velez/raybit) | **5.0** | [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) | MIT |
| [Raylib-cs](https://github.com/ChrisDill/Raylib-cs) | **5.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | Zlib |
| [Raylib-CsLo](https://github.com/NotNotTech/Raylib-CsLo) | 4.2 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 |
| [Raylib-CSharp-Vinculum](https://github.com/ZeroElectric/Raylib-CSharp-Vinculum) | **5.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 |
@@ -31,7 +31,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [raylib-go](https://github.com/gen2brain/raylib-go) | **5.0** | [Go](https://golang.org) | Zlib |
| [raylib-guile](https://github.com/petelliott/raylib-guile) | **auto** | [Guile](https://www.gnu.org/software/guile) | Zlib |
| [gforth-raylib](https://github.com/ArnautDaniel/gforth-raylib) | 3.5 | [Gforth](https://gforth.org) | **???** |
-| [h-raylib](https://github.com/Anut-py/h-raylib) | **5.1-dev** | [Haskell](https://haskell.org) | Apache-2.0 |
+| [h-raylib](https://github.com/Anut-py/h-raylib) | **5.5-dev** | [Haskell](https://haskell.org) | Apache-2.0 |
| [raylib-hx](https://github.com/foreignsasquatch/raylib-hx) | 4.2 | [Haxe](https://haxe.org) | Zlib |
| [hb-raylib](https://github.com/MarcosLeonardoMendezGerencir/hb-raylib) | 3.5 | [Harbour](https://harbour.github.io) | MIT |
| [jaylib](https://github.com/janet-lang/jaylib) | **5.0** | [Janet](https://janet-lang.org) | MIT |
@@ -78,10 +78,10 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [raylib-zig-bindings](https://github.com/L-Briand/raylib-zig-bindings) | **5.0** | [Zig](https://ziglang.org) | Zlib |
| [hare-raylib](https://git.sr.ht/~evantj/hare-raylib) | **auto** | [Hare](https://harelang.org) | Zlib |
| [raylib-sunder](https://github.com/ashn-dot-dev/raylib-sunder) | **auto** | [Sunder](https://github.com/ashn-dot-dev/sunder) | 0BSD |
-| [rayed-bqn](https://github.com/Brian-ED/rayed-bqn) | **auto** | [BQN](https://mlochbaum.github.io/BQN) | MIT |
+| [raylib-bqn](https://github.com/Brian-ED/raylib-bqn) | **5.0** | [BQN](https://mlochbaum.github.io/BQN) | MIT |
| [rayjs](https://github.com/mode777/rayjs) | 4.6-dev | [QuickJS](https://bellard.org/quickjs) | MIT |
| [raylib-raku](https://github.com/vushu/raylib-raku) | **auto** | [Raku](https://www.raku.org) | Artistic License 2.0 |
-| [Raylib.lean](https://github.com/KislyjKisel/Raylib.lean) | 4.5 | [Lean4](https://lean-lang.org) | BSD-3-Clause |
+| [Raylib.lean](https://github.com/KislyjKisel/Raylib.lean) | **5.5-dev** | [Lean4](https://lean-lang.org) | BSD-3-Clause |
| [raylib-cobol](https://codeberg.org/glowiak/raylib-cobol) | **auto** | [COBOL](https://gnucobol.sourceforge.io) | Public domain |
| [raylib-apl](https://github.com/Brian-ED/raylib-apl) | **5.0** | [Dyalog APL](https://www.dyalog.com/) | MIT |
@@ -92,6 +92,7 @@ These are utility wrappers for specific languages, they are not required to use
| ---------------------------------------------------- | :------------: | :------------------------------------------: | :-----: |
| [raylib-cpp](https://github.com/robloach/raylib-cpp) | **5.0** | [C++](https://en.wikipedia.org/wiki/C%2B%2B) | Zlib |
| [claylib](https://github.com/defun-games/claylib) | 4.5 | [Common Lisp](https://common-lisp.net) | Zlib |
+| [rayed-bqn](https://github.com/Brian-ED/rayed-bqn) | **5.0** | [BQN](https://mlochbaum.github.io/BQN) | MIT |
### Older or Unmaintained Language Bindings
diff --git a/CHANGELOG b/CHANGELOG
index 2141926ce..b5b50e4d7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,17 @@ changelog
Current Release: raylib 5.0 (18 November 2023)
+-------------------------------------------------------------------------
+Release: raylib 5.5 - 11th Anniversary Edition? (18 November 2024?)
+-------------------------------------------------------------------------
+KEY CHANGES:
+ -
+ -
+ -
+
+Detailed changes:
+...
+
-------------------------------------------------------------------------
Release: raylib 5.0 - 10th Anniversary Edition (18 November 2023)
-------------------------------------------------------------------------
diff --git a/build.zig b/build.zig
index 01e7b49fb..56e69caf4 100644
--- a/build.zig
+++ b/build.zig
@@ -1,11 +1,434 @@
const std = @import("std");
-const raylib = @import("src/build.zig");
+const builtin = @import("builtin");
-// This has been tested to work with zig 0.12.0
-pub fn build(b: *std.Build) !void {
- try raylib.build(b);
+/// Minimum supported version of Zig
+const min_ver = "0.12.0";
+
+comptime {
+ const order = std.SemanticVersion.order;
+ const parse = std.SemanticVersion.parse;
+ if (order(builtin.zig_version, parse(min_ver) catch unreachable) == .lt)
+ @compileError("Raylib requires zig version " ++ min_ver);
}
-// expose helper functions to user's build.zig
-pub const addRaylib = raylib.addRaylib;
-pub const addRaygui = raylib.addRaygui;
+// NOTE(freakmangd): I don't like using a global here, but it prevents having to
+// get the flags a second time when adding raygui
+var raylib_flags_arr: std.ArrayListUnmanaged([]const u8) = .{};
+
+// This has been tested with zig version 0.12.0
+pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile {
+ const raylib_dep = b.dependencyFromBuildZig(@This(), .{
+ .target = target,
+ .optimize = optimize,
+ .raudio = options.raudio,
+ .rmodels = options.rmodels,
+ .rshapes = options.rshapes,
+ .rtext = options.rtext,
+ .rtextures = options.rtextures,
+ .platform = options.platform,
+ .shared = options.shared,
+ .linux_display_backend = options.linux_display_backend,
+ .opengl_version = options.opengl_version,
+ .config = options.config,
+ });
+ const raylib = raylib_dep.artifact("raylib");
+
+ if (options.raygui) {
+ const raygui_dep = b.dependency(options.raygui_dependency_name, .{});
+ addRaygui(b, raylib, raygui_dep);
+ }
+
+ return raylib;
+}
+
+fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void {
+ raylib.defineCMacro("PLATFORM_DESKTOP", null);
+
+ switch (platform) {
+ .glfw => raylib.defineCMacro("PLATFORM_DESKTOP_GLFW", null),
+ .rgfw => raylib.defineCMacro("PLATFORM_DESKTOP_RGFW", null),
+ .sdl => raylib.defineCMacro("PLATFORM_DESKTOP_SDL", null),
+ else => {},
+ }
+}
+
+/// A list of all flags from `src/config.h` that one may override
+const config_h_flags = outer: {
+ // Set this value higher if compile errors happen as `src/config.h` gets larger
+ @setEvalBranchQuota(1 << 20);
+
+ const config_h = @embedFile("src/config.h");
+ var flags: [std.mem.count(u8, config_h, "\n") + 1][]const u8 = undefined;
+
+ var i = 0;
+ var lines = std.mem.tokenizeScalar(u8, config_h, '\n');
+ while (lines.next()) |line| {
+ if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue;
+ if (std.mem.startsWith(u8, line, "//")) continue;
+ if (std.mem.startsWith(u8, line, "#if")) continue;
+
+ var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace
+ flag = flag["#define ".len - 1 ..]; // Remove #define
+ flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace
+ flag = flag[0 .. std.mem.indexOf(u8, flag, " ") orelse continue]; // Flag is only one word, so capture till space
+ flag = "-D" ++ flag; // Prepend with -D
+
+ flags[i] = flag;
+ i += 1;
+ }
+
+ // Uncomment this to check what flags normally get passed
+ //@compileLog(flags[0..i].*);
+ break :outer flags[0..i].*;
+};
+
+fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile {
+ raylib_flags_arr.clearRetainingCapacity();
+
+ const shared_flags = &[_][]const u8{
+ "-fPIC",
+ "-DBUILD_LIBTYPE_SHARED",
+ };
+ try raylib_flags_arr.appendSlice(b.allocator, &[_][]const u8{
+ "-std=gnu99",
+ "-D_GNU_SOURCE",
+ "-DGL_SILENCE_DEPRECATION=199309L",
+ "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674
+ });
+ if (options.config.len > 0) {
+ // Sets a flag indiciating the use of a custom `config.h`
+ try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
+
+ // Splits a space-separated list of config flags into multiple flags
+ //
+ // Note: This means certain flags like `-x c++` won't be processed properly.
+ // `-xc++` or similar should be used when possible
+ var config_iter = std.mem.tokenizeScalar(u8, options.config, ' ');
+
+ // Apply config flags supplied by the user
+ while (config_iter.next()) |config_flag|
+ try raylib_flags_arr.append(b.allocator, config_flag);
+
+ // Apply all relevant configs from `src/config.h` *except* the user-specified ones
+ //
+ // Note: Currently using a suboptimal `O(m*n)` time algorithm where:
+ // `m` corresponds roughly to the number of lines in `src/config.h`
+ // `n` corresponds to the number of user-specified flags
+ outer: for (config_h_flags) |flag| {
+ // If a user already specified the flag, skip it
+ while (config_iter.next()) |config_flag| {
+ // For a user-specified flag to match, it must share the same prefix and have the
+ // same length or be followed by an equals sign
+ if (!std.mem.startsWith(u8, config_flag, flag)) continue;
+ if (config_flag.len == flag.len or config_flag[flag.len] == '=') continue :outer;
+ }
+
+ // Otherwise, append default value from config.h to compile flags
+ try raylib_flags_arr.append(b.allocator, flag);
+ }
+ }
+
+ if (options.shared) {
+ try raylib_flags_arr.appendSlice(b.allocator, shared_flags);
+ }
+
+ const raylib = if (options.shared)
+ b.addSharedLibrary(.{
+ .name = "raylib",
+ .target = target,
+ .optimize = optimize,
+ })
+ else
+ b.addStaticLibrary(.{
+ .name = "raylib",
+ .target = target,
+ .optimize = optimize,
+ });
+ raylib.linkLibC();
+
+ // No GLFW required on PLATFORM_DRM
+ if (options.platform != .drm) {
+ raylib.addIncludePath(b.path("src/external/glfw/include"));
+ }
+
+ var c_source_files = try std.ArrayList([]const u8).initCapacity(b.allocator, 2);
+ c_source_files.appendSliceAssumeCapacity(&.{ "src/rcore.c", "src/utils.c" });
+
+ if (options.raudio) {
+ try c_source_files.append("src/raudio.c");
+ }
+ if (options.rmodels) {
+ try c_source_files.append("src/rmodels.c");
+ }
+ if (options.rshapes) {
+ try c_source_files.append("src/rshapes.c");
+ }
+ if (options.rtext) {
+ try c_source_files.append("src/rtext.c");
+ }
+ if (options.rtextures) {
+ try c_source_files.append("src/rtextures.c");
+ }
+
+ if (options.opengl_version != .auto) {
+ raylib.defineCMacro(options.opengl_version.toCMacroStr(), null);
+ }
+
+ switch (target.result.os.tag) {
+ .windows => {
+ try c_source_files.append("src/rglfw.c");
+ raylib.linkSystemLibrary("winmm");
+ raylib.linkSystemLibrary("gdi32");
+ raylib.linkSystemLibrary("opengl32");
+
+ setDesktopPlatform(raylib, options.platform);
+ },
+ .linux => {
+ if (options.platform != .drm) {
+ try c_source_files.append("src/rglfw.c");
+ raylib.linkSystemLibrary("GL");
+ raylib.linkSystemLibrary("rt");
+ raylib.linkSystemLibrary("dl");
+ raylib.linkSystemLibrary("m");
+
+ raylib.addLibraryPath(.{ .cwd_relative = "/usr/lib" });
+ raylib.addIncludePath(.{ .cwd_relative = "/usr/include" });
+ if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) {
+ raylib.defineCMacro("_GLFW_X11", null);
+ raylib.linkSystemLibrary("X11");
+ }
+
+ if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) {
+ _ = b.findProgram(&.{"wayland-scanner"}, &.{}) catch {
+ std.log.err(
+ \\ `wayland-scanner` may not be installed on the system.
+ \\ You can switch to X11 in your `build.zig` by changing `Options.linux_display_backend`
+ , .{});
+ @panic("`wayland-scanner` not found");
+ };
+ raylib.defineCMacro("_GLFW_WAYLAND", null);
+ raylib.linkSystemLibrary("wayland-client");
+ raylib.linkSystemLibrary("wayland-cursor");
+ raylib.linkSystemLibrary("wayland-egl");
+ raylib.linkSystemLibrary("xkbcommon");
+ waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol");
+ waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol");
+ waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol");
+ waylandGenerate(b, raylib, "viewporter.xml", "viewporter-client-protocol");
+ waylandGenerate(b, raylib, "relative-pointer-unstable-v1.xml", "relative-pointer-unstable-v1-client-protocol");
+ waylandGenerate(b, raylib, "pointer-constraints-unstable-v1.xml", "pointer-constraints-unstable-v1-client-protocol");
+ waylandGenerate(b, raylib, "fractional-scale-v1.xml", "fractional-scale-v1-client-protocol");
+ waylandGenerate(b, raylib, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol");
+ waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol");
+ }
+ setDesktopPlatform(raylib, options.platform);
+ } else {
+ if (options.opengl_version == .auto) {
+ raylib.linkSystemLibrary("GLESv2");
+ raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null);
+ }
+
+ raylib.linkSystemLibrary("EGL");
+ raylib.linkSystemLibrary("drm");
+ raylib.linkSystemLibrary("gbm");
+ raylib.linkSystemLibrary("pthread");
+ raylib.linkSystemLibrary("rt");
+ raylib.linkSystemLibrary("m");
+ raylib.linkSystemLibrary("dl");
+ raylib.addIncludePath(.{ .cwd_relative = "/usr/include/libdrm" });
+
+ raylib.defineCMacro("PLATFORM_DRM", null);
+ raylib.defineCMacro("EGL_NO_X11", null);
+ raylib.defineCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", "2048");
+ }
+ },
+ .freebsd, .openbsd, .netbsd, .dragonfly => {
+ try c_source_files.append("rglfw.c");
+ raylib.linkSystemLibrary("GL");
+ raylib.linkSystemLibrary("rt");
+ raylib.linkSystemLibrary("dl");
+ raylib.linkSystemLibrary("m");
+ raylib.linkSystemLibrary("X11");
+ raylib.linkSystemLibrary("Xrandr");
+ raylib.linkSystemLibrary("Xinerama");
+ raylib.linkSystemLibrary("Xi");
+ raylib.linkSystemLibrary("Xxf86vm");
+ raylib.linkSystemLibrary("Xcursor");
+
+ setDesktopPlatform(raylib, options.platform);
+ },
+ .macos => {
+ // On macos rglfw.c include Objective-C files.
+ try raylib_flags_arr.append(b.allocator, "-ObjC");
+ raylib.root_module.addCSourceFile(.{
+ .file = b.path("src/rglfw.c"),
+ .flags = raylib_flags_arr.items,
+ });
+ _ = raylib_flags_arr.pop();
+ raylib.linkFramework("Foundation");
+ raylib.linkFramework("CoreServices");
+ raylib.linkFramework("CoreGraphics");
+ raylib.linkFramework("AppKit");
+ raylib.linkFramework("IOKit");
+
+ setDesktopPlatform(raylib, options.platform);
+ },
+ .emscripten => {
+ raylib.defineCMacro("PLATFORM_WEB", null);
+ if (options.opengl_version == .auto) {
+ raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null);
+ }
+
+ if (b.sysroot == null) {
+ @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'");
+ }
+
+ const cache_include = b.pathJoin(&.{ b.sysroot.?, "cache", "sysroot", "include" });
+
+ var dir = std.fs.openDirAbsolute(cache_include, std.fs.Dir.OpenDirOptions{ .access_sub_paths = true, .no_follow = true }) catch @panic("No emscripten cache. Generate it!");
+ dir.close();
+ raylib.addIncludePath(.{ .cwd_relative = cache_include });
+ },
+ else => {
+ @panic("Unsupported OS");
+ },
+ }
+
+ raylib.root_module.addCSourceFiles(.{
+ .files = c_source_files.items,
+ .flags = raylib_flags_arr.items,
+ });
+
+ return raylib;
+}
+
+/// This function does not need to be called if you passed .raygui = true to addRaylib
+pub fn addRaygui(b: *std.Build, raylib: *std.Build.Step.Compile, raygui_dep: *std.Build.Dependency) void {
+ if (raylib_flags_arr.items.len == 0) {
+ @panic(
+ \\argument 2 `raylib` in `addRaygui` must come from b.dependency("raylib", ...).artifact("raylib")
+ );
+ }
+
+ var gen_step = b.addWriteFiles();
+ raylib.step.dependOn(&gen_step.step);
+
+ const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n");
+ raylib.addCSourceFile(.{ .file = raygui_c_path, .flags = raylib_flags_arr.items });
+ raylib.addIncludePath(raygui_dep.path("src"));
+
+ raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h");
+}
+
+pub const Options = struct {
+ raudio: bool = true,
+ rmodels: bool = true,
+ rshapes: bool = true,
+ rtext: bool = true,
+ rtextures: bool = true,
+ raygui: bool = false,
+ platform: PlatformBackend = .glfw,
+ shared: bool = false,
+ linux_display_backend: LinuxDisplayBackend = .Both,
+ opengl_version: OpenglVersion = .auto,
+ /// config should be a list of space-separated cflags, eg, "-DSUPPORT_CUSTOM_FRAME_CONTROL"
+ config: []const u8 = &.{},
+
+ raygui_dependency_name: []const u8 = "raygui",
+
+ const defaults = Options{};
+
+ fn getOptions(b: *std.Build) Options {
+ return .{
+ .platform = b.option(PlatformBackend, "platform", "Choose the platform backedn for desktop target") orelse defaults.platform,
+ .raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio,
+ .raygui = b.option(bool, "raygui", "Compile with raygui support") orelse defaults.raygui,
+ .rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels,
+ .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext,
+ .rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures,
+ .rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes,
+ .shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared,
+ .linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend,
+ .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version,
+ .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{},
+ };
+ }
+};
+
+pub const OpenglVersion = enum {
+ auto,
+ gl_1_1,
+ gl_2_1,
+ gl_3_3,
+ gl_4_3,
+ gles_2,
+ gles_3,
+
+ pub fn toCMacroStr(self: @This()) []const u8 {
+ switch (self) {
+ .auto => @panic("OpenglVersion.auto cannot be turned into a C macro string"),
+ .gl_1_1 => return "GRAPHICS_API_OPENGL_11",
+ .gl_2_1 => return "GRAPHICS_API_OPENGL_21",
+ .gl_3_3 => return "GRAPHICS_API_OPENGL_33",
+ .gl_4_3 => return "GRAPHICS_API_OPENGL_43",
+ .gles_2 => return "GRAPHICS_API_OPENGL_ES2",
+ .gles_3 => return "GRAPHICS_API_OPENGL_ES3",
+ }
+ }
+};
+
+pub const LinuxDisplayBackend = enum {
+ X11,
+ Wayland,
+ Both,
+};
+
+pub const PlatformBackend = enum {
+ glfw,
+ rgfw,
+ sdl,
+ drm,
+};
+
+pub fn build(b: *std.Build) !void {
+ // Standard target options allows the person running `zig build` to choose
+ // what target to build for. Here we do not override the defaults, which
+ // means any target is allowed, and the default is native. Other options
+ // for restricting supported target set are available.
+ const target = b.standardTargetOptions(.{});
+ // Standard optimization options allow the person running `zig build` to select
+ // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
+ // set a preferred release mode, allowing the user to decide how to optimize.
+ const optimize = b.standardOptimizeOption(.{});
+
+ const lib = try compileRaylib(b, target, optimize, Options.getOptions(b));
+
+ lib.installHeader(b.path("src/raylib.h"), "raylib.h");
+ lib.installHeader(b.path("src/raymath.h"), "raymath.h");
+ lib.installHeader(b.path("src/rlgl.h"), "rlgl.h");
+
+ b.installArtifact(lib);
+}
+
+fn waylandGenerate(
+ b: *std.Build,
+ raylib: *std.Build.Step.Compile,
+ comptime protocol: []const u8,
+ comptime basename: []const u8,
+) void {
+ const waylandDir = "src/external/glfw/deps/wayland";
+ const protocolDir = b.pathJoin(&.{ waylandDir, protocol });
+ const clientHeader = basename ++ ".h";
+ const privateCode = basename ++ "-code.h";
+
+ const client_step = b.addSystemCommand(&.{ "wayland-scanner", "client-header" });
+ client_step.addFileArg(b.path(protocolDir));
+ raylib.addIncludePath(client_step.addOutputFileArg(clientHeader).dirname());
+
+ const private_step = b.addSystemCommand(&.{ "wayland-scanner", "private-code" });
+ private_step.addFileArg(b.path(protocolDir));
+ raylib.addIncludePath(private_step.addOutputFileArg(privateCode).dirname());
+
+ raylib.step.dependOn(&client_step.step);
+ raylib.step.dependOn(&private_step.step);
+}
diff --git a/cmake/LibraryConfigurations.cmake b/cmake/LibraryConfigurations.cmake
index 6d2250c71..fb7898306 100644
--- a/cmake/LibraryConfigurations.cmake
+++ b/cmake/LibraryConfigurations.cmake
@@ -100,9 +100,10 @@ elseif ("${PLATFORM}" MATCHES "SDL")
endif ()
if (NOT ${OPENGL_VERSION} MATCHES "OFF")
- set(${SUGGESTED_GRAPHICS} "${GRAPHICS}")
+ set(SUGGESTED_GRAPHICS "${GRAPHICS}")
+
if (${OPENGL_VERSION} MATCHES "4.3")
- set(GRAPHICS "GRAPHICS_API_OPENGL_43")
+ set(GRAPHICS "GRAPHICS_API_OPENGL_43")
elseif (${OPENGL_VERSION} MATCHES "3.3")
set(GRAPHICS "GRAPHICS_API_OPENGL_33")
elseif (${OPENGL_VERSION} MATCHES "2.1")
@@ -114,8 +115,8 @@ if (NOT ${OPENGL_VERSION} MATCHES "OFF")
elseif (${OPENGL_VERSION} MATCHES "ES 3.0")
set(GRAPHICS "GRAPHICS_API_OPENGL_ES3")
endif ()
- if ("${SUGGESTED_GRAPHICS}" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}")
- message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail")
+ if (NOT "${SUGGESTED_GRAPHICS}" STREQUAL "" AND NOT "${SUGGESTED_GRAPHICS}" STREQUAL "${GRAPHICS}")
+ message(WARNING "You are overriding the suggested GRAPHICS=${SUGGESTED_GRAPHICS} with ${GRAPHICS}! This may fail.")
endif ()
endif ()
diff --git a/examples/Makefile b/examples/Makefile
index 93b05a0c7..65ee4fb80 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -70,8 +70,9 @@ RAYLIB_SRC_PATH ?= ../src
# Locations of raylib.h and libraylib.a/libraylib.so
# NOTE: Those variables are only used for PLATFORM_OS: LINUX, BSD
-RAYLIB_INCLUDE_PATH ?= /usr/local/include
-RAYLIB_LIB_PATH ?= /usr/local/lib
+DESTDIR ?= /usr/local
+RAYLIB_INCLUDE_PATH ?= $(DESTDIR)/include
+RAYLIB_LIB_PATH ?= $(DESTDIR)/lib
# Library type compilation: STATIC (.a) or SHARED (.so/.dll)
RAYLIB_LIBTYPE ?= STATIC
@@ -491,6 +492,7 @@ CORE = \
core/core_input_mouse \
core/core_input_mouse_wheel \
core/core_input_multitouch \
+ core/core_input_virtual_controls \
core/core_loading_thread \
core/core_random_sequence \
core/core_random_values \
@@ -547,7 +549,6 @@ TEXTURES = \
textures/textures_sprite_button \
textures/textures_sprite_explosion \
textures/textures_srcrec_dstrec \
- textures/textures_svg_loading \
textures/textures_textured_curve \
textures/textures_to_image
@@ -582,10 +583,12 @@ MODELS = \
models/models_mesh_generation \
models/models_mesh_picking \
models/models_orthographic_projection \
+ models/models_point_rendering \
models/models_rlgl_solar_system \
models/models_skybox \
models/models_waving_cubes \
- models/models_yaw_pitch_roll
+ models/models_yaw_pitch_roll \
+ models/models_gpu_skinning
SHADERS = \
shaders/shaders_basic_lighting \
diff --git a/examples/Makefile.Web b/examples/Makefile.Web
index 46a8a98ea..f6c8b785a 100644
--- a/examples/Makefile.Web
+++ b/examples/Makefile.Web
@@ -35,8 +35,9 @@ RAYLIB_PATH ?= ..
# Locations of raylib.h and libraylib.a/libraylib.so
# NOTE: Those variables are only used for PLATFORM_OS: LINUX, BSD
-RAYLIB_INCLUDE_PATH ?= /usr/local/include
-RAYLIB_LIB_PATH ?= /usr/local/lib
+DESTDIR ?= /usr/local
+RAYLIB_INCLUDE_PATH ?= $(DESTDIR)/include
+RAYLIB_LIB_PATH ?= $(DESTDIR)/lib
# Library type compilation: STATIC (.a) or SHARED (.so/.dll)
RAYLIB_LIBTYPE ?= STATIC
@@ -358,6 +359,7 @@ CORE = \
core/core_input_mouse \
core/core_input_mouse_wheel \
core/core_input_multitouch \
+ core/core_input_virtual_controls \
core/core_loading_thread \
core/core_random_sequence \
core/core_random_values \
@@ -413,7 +415,6 @@ TEXTURES = \
textures/textures_sprite_button \
textures/textures_sprite_explosion \
textures/textures_srcrec_dstrec \
- textures/textures_svg_loading \
textures/textures_textured_curve \
textures/textures_to_image
@@ -447,6 +448,7 @@ MODELS = \
models/models_mesh_generation \
models/models_mesh_picking \
models/models_orthographic_projection \
+ models/models_point_rendering \
models/models_rlgl_solar_system \
models/models_skybox \
models/models_waving_cubes \
@@ -773,10 +775,6 @@ textures/textures_srcrec_dstrec: textures/textures_srcrec_dstrec.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/scarfy.png@resources/scarfy.png
-textures/textures_svg_loading: textures/textures_svg_loading.c
- $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
- --preload-file textures/resources/test.svg
-
textures/textures_textured_curve: textures/textures_textured_curve.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file textures/resources/road.png@resources/road.png
diff --git a/examples/README.md b/examples/README.md
index 317f43c89..ee528d049 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -31,31 +31,32 @@ Examples using raylib core platform functionality like window creation, inputs,
| 05 | [core_input_gamepad](core/core_input_gamepad.c) |
| ⭐️☆☆☆ | 1.1 | **4.2** | [Ray](https://github.com/raysan5) |
| 06 | [core_input_multitouch](core/core_input_multitouch.c) |
| ⭐️☆☆☆ | 2.1 | 2.5 | [Berni](https://github.com/Berni8k) |
| 07 | [core_input_gestures](core/core_input_gestures.c) |
| ⭐️⭐️☆☆ | 1.4 | **4.2** | [Ray](https://github.com/raysan5) |
-| 08 | [core_2d_camera](core/core_2d_camera.c) |
| ⭐️⭐️☆☆ | 1.5 | 3.0 | [Ray](https://github.com/raysan5) |
-| 09 | [core_2d_camera_mouse_zoom](core/core_2d_camera_mouse_zoom.c) |
| ⭐️⭐️☆☆ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) |
-| 10 | [core_2d_camera_platformer](core/core_2d_camera_platformer.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [avyy](https://github.com/avyy) |
-| 11 | [core_2d_camera_split_screen](core/core_2d_camera_split_screen.c) |
| ⭐️⭐️⭐️⭐️ | **4.5** | **4.5** | [Gabriel dos Santos Sanches](https://github.com/gabrielssanches) |
-| 12 | [core_3d_camera_mode](core/core_3d_camera_mode.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
-| 13 | [core_3d_camera_free](core/core_3d_camera_free.c) |
| ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
-| 14 | [core_3d_camera_first_person](core/core_3d_camera_first_person.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
-| 15 | [core_3d_camera:split_screen](core/core_3d_camera_split_screen.c) |
| ⭐️⭐️⭐️⭐️ | 3.7 | **4.0** | [Jeffery Myers](https://github.com/JeffM2501) |
-| 16 | [core_3d_picking](core/core_3d_picking.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 17 | [core_world_screen](core/core_world_screen.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.4 | [Ray](https://github.com/raysan5) |
-| 18 | [core_custom_logging](core/core_custom_logging.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Pablo Marcos Oltra](https://github.com/pamarcos) |
-| 19 | [core_window_flags](core/core_window_flags.c) |
| ⭐️⭐️⭐️☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 20 | [core_window_letterbox](core/core_window_letterbox.c) |
| ⭐️⭐️☆☆ | 2.5 | **4.0** | [Anata](https://github.com/anatagawa) |
-| 21 | [core_window_should_close](core/core_window_should_close.c) |
| ⭐️☆☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
-| 22 | [core_drop_files](core/core_drop_files.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
-| 23 | [core_random_values](core/core_random_values.c) |
| ⭐️☆☆☆ | 1.1 | 1.1 | [Ray](https://github.com/raysan5) |
-| 24 | [core_storage_values](core/core_storage_values.c) |
| ⭐️⭐️☆☆ | 1.4 | **4.2** | [Ray](https://github.com/raysan5) |
-| 25 | [core_vr_simulator](core/core_vr_simulator.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
-| 26 | [core_loading_thread](core/core_loading_thread.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [Ray](https://github.com/raysan5) |
-| 27 | [core_scissor_test](core/core_scissor_test.c) |
| ⭐️☆☆☆ | 2.5 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) |
-| 28 | [core_basic_screen_manager](core/core_basic_screen_manager.c) |
| ⭐️☆☆☆ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) |
-| 29 | [core_custom_frame_control](core/core_custom_frame_control.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) |
-| 30 | [core_smooth_pixelperfect](core/core_smooth_pixelperfect.c) |
| ⭐️⭐️⭐️☆ | 3.7 | **4.0** | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) |
-| 31 | [core_window_should_close](core/core_window_should_close.c) |
| ⭐️⭐️☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
-| 32 | [core_random_sequence](core/core_random_sequence.c) |
| ⭐️☆☆☆ | **5.0** | **5.0** | [REDl3east](https://github.com/REDl3east) |
+| 08 | [core_input_virtual_controls](core/core_input_virtual_controls.c) |
| ⭐️⭐️☆☆ | **5.0** | **5.0** | [oblerion](https://github.com/oblerion) |
+| 09 | [core_2d_camera](core/core_2d_camera.c) |
| ⭐️⭐️☆☆ | 1.5 | 3.0 | [Ray](https://github.com/raysan5) |
+| 10 | [core_2d_camera_mouse_zoom](core/core_2d_camera_mouse_zoom.c) |
| ⭐️⭐️☆☆ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) |
+| 11 | [core_2d_camera_platformer](core/core_2d_camera_platformer.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [avyy](https://github.com/avyy) |
+| 12 | [core_2d_camera_split_screen](core/core_2d_camera_split_screen.c) |
| ⭐️⭐️⭐️⭐️ | **4.5** | **4.5** | [Gabriel dos Santos Sanches](https://github.com/gabrielssanches) |
+| 13 | [core_3d_camera_mode](core/core_3d_camera_mode.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
+| 14 | [core_3d_camera_free](core/core_3d_camera_free.c) |
| ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
+| 15 | [core_3d_camera_first_person](core/core_3d_camera_first_person.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
+| 16 | [core_3d_camera:split_screen](core/core_3d_camera_split_screen.c) |
| ⭐️⭐️⭐️⭐️ | 3.7 | **4.0** | [Jeffery Myers](https://github.com/JeffM2501) |
+| 17 | [core_3d_picking](core/core_3d_picking.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 18 | [core_world_screen](core/core_world_screen.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.4 | [Ray](https://github.com/raysan5) |
+| 19 | [core_custom_logging](core/core_custom_logging.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Pablo Marcos Oltra](https://github.com/pamarcos) |
+| 20 | [core_window_flags](core/core_window_flags.c) |
| ⭐️⭐️⭐️☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 21 | [core_window_letterbox](core/core_window_letterbox.c) |
| ⭐️⭐️☆☆ | 2.5 | **4.0** | [Anata](https://github.com/anatagawa) |
+| 22 | [core_window_should_close](core/core_window_should_close.c) |
| ⭐️☆☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
+| 23 | [core_drop_files](core/core_drop_files.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
+| 24 | [core_random_values](core/core_random_values.c) |
| ⭐️☆☆☆ | 1.1 | 1.1 | [Ray](https://github.com/raysan5) |
+| 25 | [core_storage_values](core/core_storage_values.c) |
| ⭐️⭐️☆☆ | 1.4 | **4.2** | [Ray](https://github.com/raysan5) |
+| 26 | [core_vr_simulator](core/core_vr_simulator.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
+| 27 | [core_loading_thread](core/core_loading_thread.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [Ray](https://github.com/raysan5) |
+| 28 | [core_scissor_test](core/core_scissor_test.c) |
| ⭐️☆☆☆ | 2.5 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) |
+| 29 | [core_basic_screen_manager](core/core_basic_screen_manager.c) |
| ⭐️☆☆☆ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) |
+| 30 | [core_custom_frame_control](core/core_custom_frame_control.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Ray](https://github.com/raysan5) |
+| 31 | [core_smooth_pixelperfect](core/core_smooth_pixelperfect.c) |
| ⭐️⭐️⭐️☆ | 3.7 | **4.0** | [Giancamillo Alessandroni](https://github.com/NotManyIdeasDev) |
+| 32 | [core_window_should_close](core/core_window_should_close.c) |
| ⭐️⭐️☆☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
+| 33 | [core_random_sequence](core/core_random_sequence.c) |
| ⭐️☆☆☆ | **5.0** | **5.0** | [REDl3east](https://github.com/REDl3east) |
### category: shapes
@@ -63,22 +64,22 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes](
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 31 | [shapes_basic_shapes](shapes/shapes_basic_shapes.c) |
| ⭐️☆☆☆ | 1.0 | **4.0** | [Ray](https://github.com/raysan5) |
-| 32 | [shapes_bouncing_ball](shapes/shapes_bouncing_ball.c) |
| ⭐️☆☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 33 | [shapes_colors_palette](shapes/shapes_colors_palette.c) |
| ⭐️⭐️☆☆ | 1.0 | 2.5 | [Ray](https://github.com/raysan5) |
-| 34 | [shapes_logo_raylib](shapes/shapes_logo_raylib.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
-| 35 | [shapes_logo_raylib_anim](shapes/shapes_logo_raylib_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
-| 36 | [shapes_rectangle_scaling](shapes/shapes_rectangle_scaling.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
-| 37 | [shapes_lines_bezier](shapes/shapes_lines_bezier.c) |
| ⭐️☆☆☆ | 1.7 | 1.7 | [Ray](https://github.com/raysan5) |
-| 38 | [shapes_collision_area](shapes/shapes_collision_area.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 39 | [shapes_following_eyes](shapes/shapes_following_eyes.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 40 | [shapes_easings_ball_anim](shapes/shapes_easings_ball_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 41 | [shapes_easings_box_anim](shapes/shapes_easings_box_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 42 | [shapes_easings_rectangle_array](shapes/shapes_easings_rectangle_array.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 43 | [shapes_draw_ring](shapes/shapes_draw_ring.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
-| 44 | [shapes_draw_circle_sector](shapes/shapes_draw_circle_sector.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
-| 45 | [shapes_draw_rectangle_rounded](shapes/shapes_draw_rectangle_rounded.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
-| 46 | [shapes_top_down_lights](shapes/shapes_top_down_lights.c) |
| ⭐️⭐️⭐️⭐️ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) |
+| 34 | [shapes_basic_shapes](shapes/shapes_basic_shapes.c) |
| ⭐️☆☆☆ | 1.0 | **4.0** | [Ray](https://github.com/raysan5) |
+| 35 | [shapes_bouncing_ball](shapes/shapes_bouncing_ball.c) |
| ⭐️☆☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 36 | [shapes_colors_palette](shapes/shapes_colors_palette.c) |
| ⭐️⭐️☆☆ | 1.0 | 2.5 | [Ray](https://github.com/raysan5) |
+| 37 | [shapes_logo_raylib](shapes/shapes_logo_raylib.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
+| 38 | [shapes_logo_raylib_anim](shapes/shapes_logo_raylib_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
+| 39 | [shapes_rectangle_scaling](shapes/shapes_rectangle_scaling.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
+| 40 | [shapes_lines_bezier](shapes/shapes_lines_bezier.c) |
| ⭐️☆☆☆ | 1.7 | 1.7 | [Ray](https://github.com/raysan5) |
+| 41 | [shapes_collision_area](shapes/shapes_collision_area.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 42 | [shapes_following_eyes](shapes/shapes_following_eyes.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 43 | [shapes_easings_ball_anim](shapes/shapes_easings_ball_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 44 | [shapes_easings_box_anim](shapes/shapes_easings_box_anim.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 45 | [shapes_easings_rectangle_array](shapes/shapes_easings_rectangle_array.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 46 | [shapes_draw_ring](shapes/shapes_draw_ring.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
+| 47 | [shapes_draw_circle_sector](shapes/shapes_draw_circle_sector.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
+| 48 | [shapes_draw_rectangle_rounded](shapes/shapes_draw_rectangle_rounded.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 2.5 | [Vlad Adrian](https://github.com/demizdor) |
+| 49 | [shapes_top_down_lights](shapes/shapes_top_down_lights.c) |
| ⭐️⭐️⭐️⭐️ | **4.2** | **4.2** | [Jeffery Myers](https://github.com/JeffM2501) |
### category: textures
@@ -86,28 +87,28 @@ Examples using raylib textures functionality, including image/textures loading/g
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 47 | [textures_logo_raylib](textures/textures_logo_raylib.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
-| 48 | [textures_srcrec_dstrec](textures/textures_srcrec_dstrec.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
-| 49 | [textures_image_drawing](textures/textures_image_drawing.c) |
| ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
-| 50 | [textures_image_generation](textures/textures_image_generation.c) |
| ⭐️⭐️☆☆ | 1.8 | 1.8 | [Ray](https://github.com/raysan5) |
-| 51 | [textures_image_loading](textures/textures_image_loading.c) |
| ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
-| 52 | [textures_image_processing](textures/textures_image_processing.c) |
| ⭐️⭐️⭐️☆ | 1.4 | 3.5 | [Ray](https://github.com/raysan5) |
-| 53 | [textures_image_text](textures/textures_image_text.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
-| 54 | [textures_to_image](textures/textures_to_image.c) |
| ⭐️☆☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 55 | [textures_raw_data](textures/textures_raw_data.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
-| 56 | [textures_particles_blending](textures/textures_particles_blending.c) |
| ⭐️☆☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
-| 57 | [textures_npatch_drawing](textures/textures_npatch_drawing.c) |
| ⭐️⭐️⭐️☆ | 2.0 | 2.5 | [Jorge A. Gomes](https://github.com/overdev) |
-| 58 | [textures_background_scrolling](textures/textures_background_scrolling.c) |
| ⭐️☆☆☆ | 2.0 | 2.5 | [Ray](https://github.com/raysan5) |
-| 59 | [textures_sprite_anim](textures/textures_sprite_anim.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
-| 60 | [textures_sprite_button](textures/textures_sprite_button.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
-| 61 | [textures_sprite_explosion](textures/textures_sprite_explosion.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 62 | [textures_bunnymark](textures/textures_bunnymark.c) |
| ⭐️⭐️⭐️☆ | 1.6 | 2.5 | [Ray](https://github.com/raysan5) |
-| 63 | [textures_mouse_painting](textures/textures_mouse_painting.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) |
-| 64 | [textures_blend_modes](textures/textures_blend_modes.c) |
| ⭐️☆☆☆ | 3.5 | 3.5 | [Karlo Licudine](https://github.com/accidentalrebel) |
-| 65 | [textures_draw_tiled](textures/textures_draw_tiled.c) |
| ⭐️⭐️⭐️☆ | 3.0 | **4.2** | [Vlad Adrian](https://github.com/demizdor) |
-| 66 | [textures_polygon](textures/textures_polygon.c) |
| ⭐️☆☆☆ | 3.7 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 67 | [textures_fog_of_war](textures/textures_fog_of_war.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
-| 68 | [textures_gif_player](textures/textures_gif_player.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
+| 50 | [textures_logo_raylib](textures/textures_logo_raylib.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
+| 51 | [textures_srcrec_dstrec](textures/textures_srcrec_dstrec.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
+| 52 | [textures_image_drawing](textures/textures_image_drawing.c) |
| ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
+| 53 | [textures_image_generation](textures/textures_image_generation.c) |
| ⭐️⭐️☆☆ | 1.8 | 1.8 | [Ray](https://github.com/raysan5) |
+| 54 | [textures_image_loading](textures/textures_image_loading.c) |
| ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
+| 55 | [textures_image_processing](textures/textures_image_processing.c) |
| ⭐️⭐️⭐️☆ | 1.4 | 3.5 | [Ray](https://github.com/raysan5) |
+| 56 | [textures_image_text](textures/textures_image_text.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
+| 57 | [textures_to_image](textures/textures_to_image.c) |
| ⭐️☆☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 58 | [textures_raw_data](textures/textures_raw_data.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
+| 59 | [textures_particles_blending](textures/textures_particles_blending.c) |
| ⭐️☆☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
+| 60 | [textures_npatch_drawing](textures/textures_npatch_drawing.c) |
| ⭐️⭐️⭐️☆ | 2.0 | 2.5 | [Jorge A. Gomes](https://github.com/overdev) |
+| 61 | [textures_background_scrolling](textures/textures_background_scrolling.c) |
| ⭐️☆☆☆ | 2.0 | 2.5 | [Ray](https://github.com/raysan5) |
+| 62 | [textures_sprite_anim](textures/textures_sprite_anim.c) |
| ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
+| 63 | [textures_sprite_button](textures/textures_sprite_button.c) |
| ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
+| 64 | [textures_sprite_explosion](textures/textures_sprite_explosion.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 65 | [textures_bunnymark](textures/textures_bunnymark.c) |
| ⭐️⭐️⭐️☆ | 1.6 | 2.5 | [Ray](https://github.com/raysan5) |
+| 66 | [textures_mouse_painting](textures/textures_mouse_painting.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) |
+| 67 | [textures_blend_modes](textures/textures_blend_modes.c) |
| ⭐️☆☆☆ | 3.5 | 3.5 | [Karlo Licudine](https://github.com/accidentalrebel) |
+| 68 | [textures_draw_tiled](textures/textures_draw_tiled.c) |
| ⭐️⭐️⭐️☆ | 3.0 | **4.2** | [Vlad Adrian](https://github.com/demizdor) |
+| 69 | [textures_polygon](textures/textures_polygon.c) |
| ⭐️☆☆☆ | 3.7 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 70 | [textures_fog_of_war](textures/textures_fog_of_war.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
+| 71 | [textures_gif_player](textures/textures_gif_player.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
### category: text
@@ -115,18 +116,18 @@ Examples using raylib text functionality, including sprite fonts loading/generat
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 69 | [text_raylib_fonts](text/text_raylib_fonts.c) |
| ⭐️☆☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
-| 70 | [text_font_spritefont](text/text_font_spritefont.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
-| 71 | [text_font_filters](text/text_font_filters.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
-| 72 | [text_font_loading](text/text_font_loading.c) |
| ⭐️☆☆☆ | 1.4 | 3.0 | [Ray](https://github.com/raysan5) |
-| 73 | [text_font_sdf](text/text_font_sdf.c) |
| ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 74 | [text_format_text](text/text_format_text.c) |
| ⭐️☆☆☆ | 1.1 | 3.0 | [Ray](https://github.com/raysan5) |
-| 75 | [text_input_box](text/text_input_box.c) |
| ⭐️⭐️☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
-| 76 | [text_writing_anim](text/text_writing_anim.c) |
| ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
-| 77 | [text_rectangle_bounds](text/text_rectangle_bounds.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
-| 78 | [text_unicode](text/text_unicode.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
-| 79 | [text_draw_3d](text/text_draw_3d.c) |
| ⭐️⭐️⭐️⭐️ | 3.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
-| 80 | [text_codepoints_loading](text/text_codepoints_loading.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
+| 72 | [text_raylib_fonts](text/text_raylib_fonts.c) |
| ⭐️☆☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
+| 73 | [text_font_spritefont](text/text_font_spritefont.c) |
| ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
+| 74 | [text_font_filters](text/text_font_filters.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
+| 75 | [text_font_loading](text/text_font_loading.c) |
| ⭐️☆☆☆ | 1.4 | 3.0 | [Ray](https://github.com/raysan5) |
+| 76 | [text_font_sdf](text/text_font_sdf.c) |
| ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 77 | [text_format_text](text/text_format_text.c) |
| ⭐️☆☆☆ | 1.1 | 3.0 | [Ray](https://github.com/raysan5) |
+| 78 | [text_input_box](text/text_input_box.c) |
| ⭐️⭐️☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
+| 79 | [text_writing_anim](text/text_writing_anim.c) |
| ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
+| 80 | [text_rectangle_bounds](text/text_rectangle_bounds.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
+| 81 | [text_unicode](text/text_unicode.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
+| 82 | [text_draw_3d](text/text_draw_3d.c) |
| ⭐️⭐️⭐️⭐️ | 3.5 | **4.0** | [Vlad Adrian](https://github.com/demizdor) |
+| 83 | [text_codepoints_loading](text/text_codepoints_loading.c) |
| ⭐️⭐️⭐️☆ | **4.2** | **4.2** | [Ray](https://github.com/raysan5) |
### category: models
@@ -134,24 +135,25 @@ Examples using raylib models functionality, including models loading/generation
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 81 | [models_animation](models/models_animation.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [culacant](https://github.com/culacant) |
-| 82 | [models_billboard](models/models_billboard.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
-| 83 | [models_box_collisions](models/models_box_collisions.c) |
| ⭐️☆☆☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
-| 84 | [models_cubicmap](models/models_cubicmap.c) |
| ⭐️⭐️☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
-| 85 | [models_first_person_maze](models/models_first_person_maze.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 86 | [models_geometric_shapes](models/models_geometric_shapes.c) |
| ⭐️☆☆☆ | 1.0 | 3.5 | [Ray](https://github.com/raysan5) |
-| 87 | [models_mesh_generation](models/models_mesh_generation.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
-| 88 | [models_mesh_picking](models/models_mesh_picking.c) |
| ⭐️⭐️⭐️☆ | 1.7 | **4.0** | [Joel Davis](https://github.com/joeld42) |
-| 89 | [models_loading](models/models_loading.c) |
| ⭐️☆☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
-| 90 | [models_loading_gltf](models/models_loading_gltf.c) |
| ⭐️☆☆☆ | 3.7 | **4.2** | [Ray](https://github.com/raysan5) |
-| 91 | [models_loading_vox](models/models_loading_vox.c) |
| ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) |
-| 92 | [models_loading_m3d](models/models_loading_m3d.c) |
| ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) |
-| 93 | [models_orthographic_projection](models/models_orthographic_projection.c) |
| ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) |
-| 94 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
-| 95 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) |
-| 96 | [models_waving_cubes](models/models_waving_cubes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) |
-| 97 | [models_heightmap](models/models_heightmap.c) |
| ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
-| 98 | [models_skybox](models/models_skybox.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
+| 84 | [models_animation](models/models_animation.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [culacant](https://github.com/culacant) |
+| 85 | [models_billboard](models/models_billboard.c) |
| ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
+| 86 | [models_box_collisions](models/models_box_collisions.c) |
| ⭐️☆☆☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
+| 87 | [models_cubicmap](models/models_cubicmap.c) |
| ⭐️⭐️☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
+| 88 | [models_first_person_maze](models/models_first_person_maze.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 89 | [models_geometric_shapes](models/models_geometric_shapes.c) |
| ⭐️☆☆☆ | 1.0 | 3.5 | [Ray](https://github.com/raysan5) |
+| 90 | [models_mesh_generation](models/models_mesh_generation.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
+| 91 | [models_mesh_picking](models/models_mesh_picking.c) |
| ⭐️⭐️⭐️☆ | 1.7 | **4.0** | [Joel Davis](https://github.com/joeld42) |
+| 92 | [models_loading](models/models_loading.c) |
| ⭐️☆☆☆ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
+| 93 | [models_loading_gltf](models/models_loading_gltf.c) |
| ⭐️☆☆☆ | 3.7 | **4.2** | [Ray](https://github.com/raysan5) |
+| 94 | [models_loading_vox](models/models_loading_vox.c) |
| ⭐️☆☆☆ | **4.0** | **4.0** | [Johann Nadalutti](https://github.com/procfxgen) |
+| 95 | [models_loading_m3d](models/models_loading_m3d.c) |
| ⭐️☆☆☆ | **4.2** | **4.2** | [bzt](https://bztsrc.gitlab.io/model3d) |
+| 96 | [models_orthographic_projection](models/models_orthographic_projection.c) |
| ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) |
+| 97 | [models_point_rendering](models/models_point_rendering.c) |
| ⭐️⭐️☆☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) |
+| 98 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) |
| ⭐️⭐️⭐️⭐️ | 2.5 | **4.0** | [Ray](https://github.com/raysan5) |
+| 99 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Berni](https://github.com/Berni8k) |
+| 100 | [models_waving_cubes](models/models_waving_cubes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [codecat](https://github.com/codecat) |
+| 101 | [models_heightmap](models/models_heightmap.c) |
| ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
+| 102 | [models_skybox](models/models_skybox.c) |
| ⭐️⭐️☆☆ | 1.8 | **4.0** | [Ray](https://github.com/raysan5) |
### category: shaders
@@ -159,26 +161,25 @@ Examples using raylib shaders functionality, including shaders loading, paramete
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 99 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) |
| ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) |
-| 100 | [shaders_model_shader](shaders/shaders_model_shader.c) |
| ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) |
-| 101 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) |
| ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
-| 102 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 103 | [shaders_postprocessing](shaders/shaders_postprocessing.c) |
| ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
-| 104 | [shaders_palette_switch](shaders/shaders_palette_switch.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) |
-| 105 | [shaders_raymarching](shaders/shaders_raymarching.c) |
| ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) |
-| 106 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) |
| ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) |
-| 107 | [shaders_texture_outline](shaders/shaders_texture_outline.c) |
| ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) |
-| 108 | [shaders_texture_waves](shaders/shaders_texture_waves.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) |
-| 109 | [shaders_julia_set](shaders/shaders_julia_set.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) |
-| 110 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) |
-| 111 | [shaders_fog](shaders/shaders_fog.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 112 | [shaders_simple_mask](shaders/shaders_simple_mask.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 113 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) |
-| 114 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) |
| ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) |
-| 115 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 116 | [shaders_spotlight](shaders/shaders_spotlight.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
-| 117 | [shaders_deferred_render](shaders/shaders_deferred_render.c) |
| ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) |
-| 118 | [shaders_vertex_displacement](shaders/shaders_vertex_displacement.c) |
| ⭐️☆☆☆ | 1.5 | 1.5 | [Alex ZH](https://github.com/ZzzhHe) |
+| 103 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) |
| ⭐️⭐️⭐️⭐️ | 3.0 | **4.2** | [Chris Camacho](https://github.com/codifies) |
+| 104 | [shaders_model_shader](shaders/shaders_model_shader.c) |
| ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) |
+| 105 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) |
| ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
+| 106 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) |
| ⭐️⭐️☆☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 107 | [shaders_postprocessing](shaders/shaders_postprocessing.c) |
| ⭐️⭐️⭐️☆ | 1.3 | **4.0** | [Ray](https://github.com/raysan5) |
+| 108 | [shaders_palette_switch](shaders/shaders_palette_switch.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) |
+| 109 | [shaders_raymarching](shaders/shaders_raymarching.c) |
| ⭐️⭐️⭐️⭐️ | 2.0 | **4.2** | [Ray](https://github.com/raysan5) |
+| 110 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) |
| ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/) |
+| 111 | [shaders_texture_outline](shaders/shaders_texture_outline.c) |
| ⭐️⭐️⭐️☆ | **4.0** | **4.0** | [Samuel Skiff](https://github.com/GoldenThumbs) |
+| 112 | [shaders_texture_waves](shaders/shaders_texture_waves.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) |
+| 113 | [shaders_julia_set](shaders/shaders_julia_set.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [eggmund](https://github.com/eggmund) |
+| 114 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) |
| ⭐️⭐️⭐️☆ | 2.5 | **4.0** | [ProfJski](https://github.com/ProfJski) |
+| 115 | [shaders_fog](shaders/shaders_fog.c) |
| ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 116 | [shaders_simple_mask](shaders/shaders_simple_mask.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 117 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) |
+| 118 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) |
| ⭐️⭐️⭐️⭐️ | 3.7 | **4.2** | [seanpringle](https://github.com/seanpringle) |
+| 119 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 120 | [shaders_spotlight](shaders/shaders_spotlight.c) |
| ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/codifies) |
+| 121 | [shaders_deferred_render](shaders/shaders_deferred_render.c) |
| ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) |
### category: audio
@@ -186,10 +187,10 @@ Examples using raylib audio functionality, including sound/music loading and pla
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 119 | [audio_module_playing](audio/audio_module_playing.c) |
| ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) |
-| 120 | [audio_music_stream](audio/audio_music_stream.c) |
| ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
-| 121 | [audio_raw_stream](audio/audio_raw_stream.c) |
| ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) |
-| 122 | [audio_sound_loading](audio/audio_sound_loading.c) |
| ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) |
+| 122 | [audio_module_playing](audio/audio_module_playing.c) |
| ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) |
+| 123 | [audio_music_stream](audio/audio_music_stream.c) |
| ⭐️☆☆☆ | 1.3 | **4.2** | [Ray](https://github.com/raysan5) |
+| 124 | [audio_raw_stream](audio/audio_raw_stream.c) |
| ⭐️⭐️⭐️☆ | 1.6 | **4.2** | [Ray](https://github.com/raysan5) |
+| 125 | [audio_sound_loading](audio/audio_sound_loading.c) |
| ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) |
### category: others
@@ -197,11 +198,11 @@ Examples showing raylib misc functionality that does not fit in other categories
| ## | example | image | difficulty
level | version
created | last version
updated | original
developer |
|----|----------|--------|:-------------------:|:------------------:|:------------------:|:----------|
-| 123 | [rlgl_standalone](others/rlgl_standalone.c) |
| ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) |
-| 124 | [rlgl_compute_shader](others/rlgl_compute_shader.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) |
-| 125 | [easings_testbed](others/easings_testbed.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
-| 126 | [raylib_opengl_interop](others/raylib_opengl_interop.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) |
-| 127 | [embedded_files_loading](others/embedded_files_loading.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
+| 126 | [rlgl_standalone](others/rlgl_standalone.c) |
| ⭐️⭐️⭐️⭐️ | 1.6 | **4.0** | [Ray](https://github.com/raysan5) |
+| 127 | [rlgl_compute_shader](others/rlgl_compute_shader.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Teddy Astie](https://github.com/tsnake41) |
+| 128 | [easings_testbed](others/easings_testbed.c) |
| ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
+| 129 | [raylib_opengl_interop](others/raylib_opengl_interop.c) |
| ⭐️⭐️⭐️⭐️ | **4.0** | **4.0** | [Stephan Soller](https://github.com/arkanis) |
+| 130 | [embedded_files_loading](others/embedded_files_loading.c) |
| ⭐️⭐️☆☆ | 3.5 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
As always contributions are welcome, feel free to send new examples! Here is an [examples template](examples_template.c) to start with!
diff --git a/examples/core/core_input_virtual_controls.c b/examples/core/core_input_virtual_controls.c
new file mode 100644
index 000000000..ae7f770aa
--- /dev/null
+++ b/examples/core/core_input_virtual_controls.c
@@ -0,0 +1,123 @@
+/*******************************************************************************************
+*
+* raylib [core] example - input virtual controls
+*
+* Example originally created with raylib 5.0, last time updated with raylib 5.0
+*
+* Example create by GreenSnakeLinux (@GreenSnakeLinux),
+* lighter by oblerion (@oblerion) and
+* reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2024 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [core] example - input virtual controls");
+
+ const int dpadX = 90;
+ const int dpadY = 300;
+ const int dpadRad = 25;//radius of each pad
+ Color dpadColor = BLUE;
+ int dpadKeydown = -1;//-1 if not down, else 0,1,2,3
+
+
+ const float dpadCollider[4][2]= // collider array with x,y position
+ {
+ {dpadX,dpadY-dpadRad*1.5},//up
+ {dpadX-dpadRad*1.5,dpadY},//left
+ {dpadX+dpadRad*1.5,dpadY},//right
+ {dpadX,dpadY+dpadRad*1.5}//down
+ };
+ const char dpadLabel[4]="XYBA";//label of Dpad
+
+ float playerX=100;
+ float playerY=100;
+
+ SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //--------------------------------------------------------------------------
+ dpadKeydown = -1; //reset
+ float inputX=0;
+ float inputY=0;
+ if(GetTouchPointCount()>0)
+ {//use touch pos
+ inputX = GetTouchX();
+ inputY = GetTouchY();
+ }
+ else
+ {//use mouse pos
+ inputX = GetMouseX();
+ inputY = GetMouseY();
+ }
+ for(int i=0;i<4;i++)
+ {
+ //test distance each collider and input < radius
+ if( fabsf(dpadCollider[i][1]-inputY) + fabsf(dpadCollider[i][0]-inputX) < dpadRad)
+ {
+ dpadKeydown = i;
+ break;
+ }
+ }
+ // move player
+ switch(dpadKeydown){
+ case 0: playerY -= 50*GetFrameTime();
+ break;
+ case 1: playerX -= 50*GetFrameTime();
+ break;
+ case 2: playerX += 50*GetFrameTime();
+ break;
+ case 3: playerY += 50*GetFrameTime();
+ default:;
+ };
+ //--------------------------------------------------------------------------
+
+ // Draw
+ //--------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(RAYWHITE);
+ for(int i=0;i<4;i++)
+ {
+ //draw all pad
+ DrawCircle(dpadCollider[i][0],dpadCollider[i][1],dpadRad,dpadColor);
+ if(i!=dpadKeydown)
+ {
+ //draw label
+ DrawText(TextSubtext(dpadLabel,i,1),
+ dpadCollider[i][0]-5,
+ dpadCollider[i][1]-5,16,BLACK);
+ }
+
+ }
+ DrawText("Player",playerX,playerY,16,BLACK);
+ EndDrawing();
+ //--------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
diff --git a/examples/core/core_input_virtual_controls.png b/examples/core/core_input_virtual_controls.png
new file mode 100644
index 000000000..a9776e68a
Binary files /dev/null and b/examples/core/core_input_virtual_controls.png differ
diff --git a/examples/models/models_gpu_skinning.c b/examples/models/models_gpu_skinning.c
new file mode 100644
index 000000000..b6296c96a
--- /dev/null
+++ b/examples/models/models_gpu_skinning.c
@@ -0,0 +1,118 @@
+/*******************************************************************************************
+*
+* raylib [core] example - Doing skinning on the gpu using a vertex shader
+*
+* Example originally created with raylib 4.5, last time updated with raylib 4.5
+*
+* Example contributed by Daniel Holden (@orangeduck) and reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2024 Daniel Holden (@orangeduck)
+*
+* Note: Due to limitations in the Apple OpenGL driver, this feature does not work on MacOS
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+
+#if defined(PLATFORM_DESKTOP)
+ #define GLSL_VERSION 330
+#else // PLATFORM_ANDROID, PLATFORM_WEB
+ #define GLSL_VERSION 100
+#endif
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [models] example - GPU skinning");
+
+ // Define the camera to look into our 3d world
+ Camera camera = { 0 };
+ camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position
+ camera.target = (Vector3){ 0.0f, 2.0f, 0.0f }; // Camera looking at point
+ camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
+ camera.fovy = 45.0f; // Camera field-of-view Y
+ camera.projection = CAMERA_PERSPECTIVE; // Camera projection type
+
+ // Load gltf model
+ Model characterModel = LoadModel("resources/models/gltf/greenman.glb"); // Load character model
+
+ // Load skinning shader
+ Shader skinningShader = LoadShader(TextFormat("resources/shaders/glsl%i/skinning.vs", GLSL_VERSION),
+ TextFormat("resources/shaders/glsl%i/skinning.fs", GLSL_VERSION));
+
+ characterModel.materials[1].shader = skinningShader;
+
+ // Load gltf model animations
+ int animsCount = 0;
+ unsigned int animIndex = 0;
+ unsigned int animCurrentFrame = 0;
+ ModelAnimation *modelAnimations = LoadModelAnimations("resources/models/gltf/greenman.glb", &animsCount);
+
+ Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
+
+ DisableCursor(); // Limit cursor to relative movement inside the window
+
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ UpdateCamera(&camera, CAMERA_THIRD_PERSON);
+
+ // Select current animation
+ if (IsKeyPressed(KEY_T)) animIndex = (animIndex + 1)%animsCount;
+ else if (IsKeyPressed(KEY_G)) animIndex = (animIndex + animsCount - 1)%animsCount;
+
+ // Update model animation
+ ModelAnimation anim = modelAnimations[animIndex];
+ animCurrentFrame = (animCurrentFrame + 1)%anim.frameCount;
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+
+ ClearBackground(RAYWHITE);
+
+ BeginMode3D(camera);
+
+ // Draw character
+ characterModel.transform = MatrixTranslate(position.x, position.y, position.z);
+ UpdateModelAnimationBoneMatrices(characterModel, anim, animCurrentFrame);
+ DrawMesh(characterModel.meshes[0], characterModel.materials[1], characterModel.transform);
+
+ DrawGrid(10, 1.0f);
+ EndMode3D();
+
+ DrawText("Use the T/G to switch animation", 10, 10, 20, GRAY);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadModelAnimations(modelAnimations, animsCount);
+ UnloadModel(characterModel); // Unload character model and meshes/material
+ UnloadShader(skinningShader);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/models/models_point_rendering.c b/examples/models/models_point_rendering.c
new file mode 100644
index 000000000..68d498453
--- /dev/null
+++ b/examples/models/models_point_rendering.c
@@ -0,0 +1,182 @@
+/*******************************************************************************************
+*
+* raylib example - point rendering
+*
+* Example originally created with raylib 5.0, last time updated with raylib 5.0
+*
+* Example contributed by Reese Gallagher (@satchelfrost) and reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2024 Reese Gallagher (@satchelfrost)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include // Required for: rand()
+#include // Required for: cos(), sin()
+
+#define MAX_POINTS 10000000 // 10 million
+#define MIN_POINTS 1000 // 1 thousand
+
+// Generate mesh using points
+Mesh GenMeshPoints(int numPoints);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main()
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [models] example - point rendering");
+
+ Camera camera = {
+ .position = { 3.0f, 3.0f, 3.0f },
+ .target = { 0.0f, 0.0f, 0.0f },
+ .up = { 0.0f, 1.0f, 0.0f },
+ .fovy = 45.0f,
+ .projection = CAMERA_PERSPECTIVE
+ };
+
+ Vector3 position = { 0.0f, 0.0f, 0.0f };
+ bool useDrawModelPoints = true;
+ bool numPointsChanged = false;
+ int numPoints = 1000;
+
+ Mesh mesh = GenMeshPoints(numPoints);
+ Model model = LoadModelFromMesh(mesh);
+
+ //SetTargetFPS(60);
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while(!WindowShouldClose())
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ UpdateCamera(&camera, CAMERA_ORBITAL);
+
+ if (IsKeyPressed(KEY_SPACE)) useDrawModelPoints = !useDrawModelPoints;
+ if (IsKeyPressed(KEY_UP))
+ {
+ numPoints = (numPoints*10 > MAX_POINTS)? MAX_POINTS : numPoints*10;
+ numPointsChanged = true;
+ }
+ if (IsKeyPressed(KEY_DOWN))
+ {
+ numPoints = (numPoints/10 < MIN_POINTS)? MIN_POINTS : numPoints/10;
+ numPointsChanged = true;
+ }
+
+ // Upload a different point cloud size
+ if (numPointsChanged)
+ {
+ UnloadModel(model);
+ mesh = GenMeshPoints(numPoints);
+ model = LoadModelFromMesh(mesh);
+ numPointsChanged = false;
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(BLACK);
+
+ BeginMode3D(camera);
+
+ // The new method only uploads the points once to the GPU
+ if (useDrawModelPoints)
+ {
+ DrawModelPoints(model, position, 1.0f, WHITE);
+ }
+ else
+ {
+ // The old method must continually draw the "points" (lines)
+ for (int i = 0; i < numPoints; i++)
+ {
+ Vector3 pos = {
+ .x = mesh.vertices[i*3 + 0],
+ .y = mesh.vertices[i*3 + 1],
+ .z = mesh.vertices[i*3 + 2],
+ };
+ Color color = {
+ .r = mesh.colors[i*4 + 0],
+ .g = mesh.colors[i*4 + 1],
+ .b = mesh.colors[i*4 + 2],
+ .a = mesh.colors[i*4 + 3],
+ };
+
+ DrawPoint3D(pos, color);
+ }
+ }
+
+ // Draw a unit sphere for reference
+ DrawSphereWires(position, 1.0f, 10, 10, YELLOW);
+
+ EndMode3D();
+
+ // Draw UI text
+ DrawText(TextFormat("Point Count: %d", numPoints), 20, screenHeight - 50, 40, WHITE);
+ DrawText("Up - increase points", 20, 70, 20, WHITE);
+ DrawText("Down - decrease points", 20, 100, 20, WHITE);
+ DrawText("Space - drawing function", 20, 130, 20, WHITE);
+
+ if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 20, 160, 20, GREEN);
+ else DrawText("Using: DrawPoint3D()", 20, 160, 20, RED);
+
+ DrawFPS(10, 10);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadModel(model);
+
+ CloseWindow();
+ //--------------------------------------------------------------------------------------
+ return 0;
+}
+
+// Generate a spherical point cloud
+Mesh GenMeshPoints(int numPoints)
+{
+ Mesh mesh = {
+ .triangleCount = 1,
+ .vertexCount = numPoints,
+ .vertices = (float *)MemAlloc(numPoints*3*sizeof(float)),
+ .colors = (unsigned char*)MemAlloc(numPoints*4*sizeof(unsigned char)),
+ };
+
+ // https://en.wikipedia.org/wiki/Spherical_coordinate_system
+ for (int i = 0; i < numPoints; i++)
+ {
+ float theta = PI*rand()/RAND_MAX;
+ float phi = 2.0f*PI*rand()/RAND_MAX;
+ float r = 10.0f*rand()/RAND_MAX;
+
+ mesh.vertices[i*3 + 0] = r*sin(theta)*cos(phi);
+ mesh.vertices[i*3 + 1] = r*sin(theta)*sin(phi);
+ mesh.vertices[i*3 + 2] = r*cos(theta);
+
+ Color color = ColorFromHSV(r*360.0f, 1.0f, 1.0f);
+
+ mesh.colors[i*4 + 0] = color.r;
+ mesh.colors[i*4 + 1] = color.g;
+ mesh.colors[i*4 + 2] = color.b;
+ mesh.colors[i*4 + 3] = color.a;
+ }
+
+ // Upload mesh data from CPU (RAM) to GPU (VRAM) memory
+ UploadMesh(&mesh, false);
+
+ return mesh;
+}
diff --git a/examples/models/models_point_rendering.png b/examples/models/models_point_rendering.png
new file mode 100644
index 000000000..a1fc718e4
Binary files /dev/null and b/examples/models/models_point_rendering.png differ
diff --git a/examples/models/resources/shaders/glsl100/skinning.fs b/examples/models/resources/shaders/glsl100/skinning.fs
new file mode 100644
index 000000000..ef6568036
--- /dev/null
+++ b/examples/models/resources/shaders/glsl100/skinning.fs
@@ -0,0 +1,17 @@
+#version 100
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+// Output fragment color
+out vec4 finalColor;
+
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+void main()
+{
+ vec4 texelColor = texture(texture0, fragTexCoord);
+ finalColor = texelColor*colDiffuse*fragColor;
+}
diff --git a/examples/models/resources/shaders/glsl100/skinning.vs b/examples/models/resources/shaders/glsl100/skinning.vs
new file mode 100644
index 000000000..9c92e2a8c
--- /dev/null
+++ b/examples/models/resources/shaders/glsl100/skinning.vs
@@ -0,0 +1,34 @@
+#version 100
+
+in vec3 vertexPosition;
+in vec2 vertexTexCoord;
+in vec4 vertexColor;
+in vec4 vertexBoneIds;
+in vec4 vertexBoneWeights;
+
+#define MAX_BONE_NUM 128
+uniform mat4 boneMatrices[MAX_BONE_NUM];
+
+uniform mat4 mvp;
+
+out vec2 fragTexCoord;
+out vec4 fragColor;
+
+void main()
+{
+ int boneIndex0 = int(vertexBoneIds.x);
+ int boneIndex1 = int(vertexBoneIds.y);
+ int boneIndex2 = int(vertexBoneIds.z);
+ int boneIndex3 = int(vertexBoneIds.w);
+
+ vec4 skinnedPosition =
+ vertexBoneWeights.x * (boneMatrices[boneIndex0] * vec4(vertexPosition, 1.0f)) +
+ vertexBoneWeights.y * (boneMatrices[boneIndex1] * vec4(vertexPosition, 1.0f)) +
+ vertexBoneWeights.z * (boneMatrices[boneIndex2] * vec4(vertexPosition, 1.0f)) +
+ vertexBoneWeights.w * (boneMatrices[boneIndex3] * vec4(vertexPosition, 1.0f));
+
+ fragTexCoord = vertexTexCoord;
+ fragColor = vertexColor;
+
+ gl_Position = mvp * skinnedPosition;
+}
\ No newline at end of file
diff --git a/examples/models/resources/shaders/glsl330/skinning.fs b/examples/models/resources/shaders/glsl330/skinning.fs
new file mode 100644
index 000000000..d4311ffcc
--- /dev/null
+++ b/examples/models/resources/shaders/glsl330/skinning.fs
@@ -0,0 +1,17 @@
+#version 330
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+// Output fragment color
+out vec4 finalColor;
+
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+void main()
+{
+ vec4 texelColor = texture(texture0, fragTexCoord);
+ finalColor = texelColor*colDiffuse*fragColor;
+}
diff --git a/examples/models/resources/shaders/glsl330/skinning.vs b/examples/models/resources/shaders/glsl330/skinning.vs
new file mode 100644
index 000000000..2dc976c48
--- /dev/null
+++ b/examples/models/resources/shaders/glsl330/skinning.vs
@@ -0,0 +1,34 @@
+#version 330
+
+in vec3 vertexPosition;
+in vec2 vertexTexCoord;
+in vec4 vertexColor;
+in vec4 vertexBoneIds;
+in vec4 vertexBoneWeights;
+
+#define MAX_BONE_NUM 128
+uniform mat4 boneMatrices[MAX_BONE_NUM];
+
+uniform mat4 mvp;
+
+out vec2 fragTexCoord;
+out vec4 fragColor;
+
+void main()
+{
+ int boneIndex0 = int(vertexBoneIds.x);
+ int boneIndex1 = int(vertexBoneIds.y);
+ int boneIndex2 = int(vertexBoneIds.z);
+ int boneIndex3 = int(vertexBoneIds.w);
+
+ vec4 skinnedPosition =
+ vertexBoneWeights.x * (boneMatrices[boneIndex0] * vec4(vertexPosition, 1.0f)) +
+ vertexBoneWeights.y * (boneMatrices[boneIndex1] * vec4(vertexPosition, 1.0f)) +
+ vertexBoneWeights.z * (boneMatrices[boneIndex2] * vec4(vertexPosition, 1.0f)) +
+ vertexBoneWeights.w * (boneMatrices[boneIndex3] * vec4(vertexPosition, 1.0f));
+
+ fragTexCoord = vertexTexCoord;
+ fragColor = vertexColor;
+
+ gl_Position = mvp * skinnedPosition;
+}
\ No newline at end of file
diff --git a/examples/textures/resources/test.svg b/examples/textures/resources/test.svg
deleted file mode 100644
index 3d9bbb113..000000000
--- a/examples/textures/resources/test.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/examples/textures/textures_image_drawing.c b/examples/textures/textures_image_drawing.c
index f49bc9e77..d0eee999d 100644
--- a/examples/textures/textures_image_drawing.c
+++ b/examples/textures/textures_image_drawing.c
@@ -47,7 +47,7 @@ int main(void)
UnloadImage(cat); // Unload image from RAM
- // Load custom font for frawing on image
+ // Load custom font for drawing on image
Font font = LoadFont("resources/custom_jupiter_crash.png");
// Draw over image using custom font
@@ -93,4 +93,4 @@ int main(void)
//--------------------------------------------------------------------------------------
return 0;
-}
\ No newline at end of file
+}
diff --git a/examples/textures/textures_svg_loading.c b/examples/textures/textures_svg_loading.c
deleted file mode 100644
index 434ec7602..000000000
--- a/examples/textures/textures_svg_loading.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*******************************************************************************************
-*
-* raylib [textures] example - SVG loading and texture creation
-*
-* NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU memory (VRAM)
-*
-* Example originally created with raylib 4.2, last time updated with raylib 4.2
-*
-* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
-* BSD-like license that allows static linking with closed source software
-*
-* Copyright (c) 2022 Dennis Meinen (@bixxy#4258 on Discord)
-*
-********************************************************************************************/
-
-#include "raylib.h"
-
-//------------------------------------------------------------------------------------
-// Program main entry point
-//------------------------------------------------------------------------------------
-int main(void)
-{
- // Initialization
- //--------------------------------------------------------------------------------------
- const int screenWidth = 800;
- const int screenHeight = 450;
-
- InitWindow(screenWidth, screenHeight, "raylib [textures] example - svg loading");
-
- // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
-
- Image image = LoadImageSvg("resources/test.svg", 400, 350); // Loaded in CPU memory (RAM)
- Texture2D texture = LoadTextureFromImage(image); // Image converted to texture, GPU memory (VRAM)
- UnloadImage(image); // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM
-
- SetTargetFPS(60); // Set our game to run at 60 frames-per-second
- //---------------------------------------------------------------------------------------
-
- // Main game loop
- while (!WindowShouldClose()) // Detect window close button or ESC key
- {
- // Update
- //----------------------------------------------------------------------------------
- // TODO: Update your variables here
- //----------------------------------------------------------------------------------
-
- // Draw
- //----------------------------------------------------------------------------------
- BeginDrawing();
-
- ClearBackground(RAYWHITE);
-
- DrawTexture(texture, screenWidth/2 - texture.width/2, screenHeight/2 - texture.height/2, WHITE);
-
- //Red border to illustrate how the SVG is centered within the specified dimensions
- DrawRectangleLines((screenWidth / 2 - texture.width / 2) - 1, (screenHeight / 2 - texture.height / 2) - 1, texture.width + 2, texture.height + 2, RED);
-
- DrawText("this IS a texture loaded from an SVG file!", 300, 410, 10, GRAY);
-
- EndDrawing();
- //----------------------------------------------------------------------------------
- }
-
- // De-Initialization
- //--------------------------------------------------------------------------------------
- UnloadTexture(texture); // Texture unloading
-
- CloseWindow(); // Close window and OpenGL context
- //--------------------------------------------------------------------------------------
-
- return 0;
-}
\ No newline at end of file
diff --git a/examples/textures/textures_svg_loading.png b/examples/textures/textures_svg_loading.png
deleted file mode 100644
index fa98605fa..000000000
Binary files a/examples/textures/textures_svg_loading.png and /dev/null differ
diff --git a/parser/README.md b/parser/README.md
index 45a2689a0..6616cdc51 100644
--- a/parser/README.md
+++ b/parser/README.md
@@ -41,7 +41,7 @@ OPTIONS:
-f, --format : Define output format for parser data.
Supported types: DEFAULT, JSON, XML, LUA
- -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMDEF for raymath.h, etc.)
+ -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMAPI for raymath.h, etc.)
NOTE: If no specifier defined, defaults to: RLAPI
-t, --truncate : Define string to truncate input after (i.e. "RLGL IMPLEMENTATION" for rlgl.h)
@@ -56,7 +56,7 @@ EXAMPLES:
> raylib_parser --output raylib_data.info --format XML
Process to generate as XML text data
- > raylib_parser --input raymath.h --output raymath_data.info --format XML
+ > raylib_parser --input raymath.h --output raymath_data.info --format XML --define RMAPI
Process to generate as XML text data
```
diff --git a/parser/output/raylib_api.json b/parser/output/raylib_api.json
index c4ce91e87..591fef737 100644
--- a/parser/output/raylib_api.json
+++ b/parser/output/raylib_api.json
@@ -850,12 +850,22 @@
{
"type": "unsigned char *",
"name": "boneIds",
- "description": "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning)"
+ "description": "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)"
},
{
"type": "float *",
"name": "boneWeights",
- "description": "Vertex bone weight, up to 4 bones influence by vertex (skinning)"
+ "description": "Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)"
+ },
+ {
+ "type": "Matrix *",
+ "name": "boneMatrices",
+ "description": "Bones animated transformation matrices"
+ },
+ {
+ "type": "int",
+ "name": "boneCount",
+ "description": "Number of bones"
},
{
"type": "unsigned int",
@@ -2518,6 +2528,21 @@
"name": "SHADER_LOC_MAP_BRDF",
"value": 25,
"description": "Shader location: sampler2d texture: brdf"
+ },
+ {
+ "name": "SHADER_LOC_VERTEX_BONEIDS",
+ "value": 26,
+ "description": "Shader location: vertex attribute: boneIds"
+ },
+ {
+ "name": "SHADER_LOC_VERTEX_BONEWEIGHTS",
+ "value": 27,
+ "description": "Shader location: vertex attribute: boneWeights"
+ },
+ {
+ "name": "SHADER_LOC_BONE_MATRICES",
+ "value": 28,
+ "description": "Shader location: array of matrices uniform: boneMatrices"
}
]
},
@@ -3215,12 +3240,12 @@
},
{
"name": "ToggleFullscreen",
- "description": "Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)",
+ "description": "Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP)",
"returnType": "void"
},
{
"name": "ToggleBorderlessWindowed",
- "description": "Toggle window state: borderless windowed (only PLATFORM_DESKTOP)",
+ "description": "Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP)",
"returnType": "void"
},
{
@@ -3738,8 +3763,8 @@
]
},
{
- "name": "IsShaderReady",
- "description": "Check if a shader is ready",
+ "name": "IsShaderValid",
+ "description": "Check if a shader is valid (loaded on GPU)",
"returnType": "bool",
"params": [
{
@@ -4477,6 +4502,17 @@
"description": "Get the directory of the running application (uses static string)",
"returnType": "const char *"
},
+ {
+ "name": "MakeDirectory",
+ "description": "Create directories (including full path requested), returns 0 on success",
+ "returnType": "int",
+ "params": [
+ {
+ "type": "const char *",
+ "name": "dirPath"
+ }
+ ]
+ },
{
"name": "ChangeDirectory",
"description": "Change working directory, return true on success",
@@ -4523,7 +4559,7 @@
},
{
"name": "LoadDirectoryFilesEx",
- "description": "Load directory filepaths with extension filtering and recursive directory scan",
+ "description": "Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result",
"returnType": "FilePathList",
"params": [
{
@@ -4655,6 +4691,51 @@
}
]
},
+ {
+ "name": "ComputeCRC32",
+ "description": "Compute CRC32 hash code",
+ "returnType": "unsigned int",
+ "params": [
+ {
+ "type": "unsigned char *",
+ "name": "data"
+ },
+ {
+ "type": "int",
+ "name": "dataSize"
+ }
+ ]
+ },
+ {
+ "name": "ComputeMD5",
+ "description": "Compute MD5 hash code, returns static int[4] (16 bytes)",
+ "returnType": "unsigned int *",
+ "params": [
+ {
+ "type": "unsigned char *",
+ "name": "data"
+ },
+ {
+ "type": "int",
+ "name": "dataSize"
+ }
+ ]
+ },
+ {
+ "name": "ComputeSHA1",
+ "description": "Compute SHA1 hash code, returns static int[5] (20 bytes)",
+ "returnType": "unsigned int *",
+ "params": [
+ {
+ "type": "unsigned char *",
+ "name": "data"
+ },
+ {
+ "type": "int",
+ "name": "dataSize"
+ }
+ ]
+ },
{
"name": "LoadAutomationEventList",
"description": "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS",
@@ -5150,7 +5231,7 @@
},
{
"name": "GetGestureHoldDuration",
- "description": "Get gesture hold time in milliseconds",
+ "description": "Get gesture hold time in seconds",
"returnType": "float"
},
{
@@ -5238,7 +5319,7 @@
},
{
"name": "DrawPixel",
- "description": "Draw a pixel",
+ "description": "Draw a pixel using geometry [Can be slow, use with care]",
"returnType": "void",
"params": [
{
@@ -5257,7 +5338,7 @@
},
{
"name": "DrawPixelV",
- "description": "Draw a pixel (Vector version)",
+ "description": "Draw a pixel using geometry (Vector version) [Can be slow, use with care]",
"returnType": "void",
"params": [
{
@@ -6779,25 +6860,6 @@
}
]
},
- {
- "name": "LoadImageSvg",
- "description": "Load image from SVG file data or string with specified size",
- "returnType": "Image",
- "params": [
- {
- "type": "const char *",
- "name": "fileNameOrString"
- },
- {
- "type": "int",
- "name": "width"
- },
- {
- "type": "int",
- "name": "height"
- }
- ]
- },
{
"name": "LoadImageAnim",
"description": "Load image sequence from file (frames appended to image.data)",
@@ -6872,8 +6934,8 @@
"returnType": "Image"
},
{
- "name": "IsImageReady",
- "description": "Check if an image is ready",
+ "name": "IsImageValid",
+ "description": "Check if an image is valid (data and parameters)",
"returnType": "bool",
"params": [
{
@@ -8336,8 +8398,8 @@
]
},
{
- "name": "IsTextureReady",
- "description": "Check if a texture is ready",
+ "name": "IsTextureValid",
+ "description": "Check if a texture is valid (loaded in GPU)",
"returnType": "bool",
"params": [
{
@@ -8358,8 +8420,8 @@
]
},
{
- "name": "IsRenderTextureReady",
- "description": "Check if a render texture is ready",
+ "name": "IsRenderTextureValid",
+ "description": "Check if a render texture is valid (loaded in GPU)",
"returnType": "bool",
"params": [
{
@@ -8780,6 +8842,25 @@
}
]
},
+ {
+ "name": "ColorLerp",
+ "description": "Get color lerp interpolation between two colors, factor [0.0f..1.0f]",
+ "returnType": "Color",
+ "params": [
+ {
+ "type": "Color",
+ "name": "color1"
+ },
+ {
+ "type": "Color",
+ "name": "color2"
+ },
+ {
+ "type": "float",
+ "name": "factor"
+ }
+ ]
+ },
{
"name": "GetColor",
"description": "Get Color structure from hexadecimal value",
@@ -8862,7 +8943,7 @@
},
{
"name": "LoadFontEx",
- "description": "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character setFont",
+ "description": "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height",
"returnType": "Font",
"params": [
{
@@ -8934,8 +9015,8 @@
]
},
{
- "name": "IsFontReady",
- "description": "Check if a font is ready",
+ "name": "IsFontValid",
+ "description": "Check if a font is valid (font data loaded, WARNING: GPU texture not checked)",
"returnType": "bool",
"params": [
{
@@ -10226,8 +10307,8 @@
]
},
{
- "name": "IsModelReady",
- "description": "Check if a model is ready",
+ "name": "IsModelValid",
+ "description": "Check if a model is valid (loaded in GPU, VAO/VBOs)",
"returnType": "bool",
"params": [
{
@@ -10366,6 +10447,60 @@
}
]
},
+ {
+ "name": "DrawModelPoints",
+ "description": "Draw a model as points",
+ "returnType": "void",
+ "params": [
+ {
+ "type": "Model",
+ "name": "model"
+ },
+ {
+ "type": "Vector3",
+ "name": "position"
+ },
+ {
+ "type": "float",
+ "name": "scale"
+ },
+ {
+ "type": "Color",
+ "name": "tint"
+ }
+ ]
+ },
+ {
+ "name": "DrawModelPointsEx",
+ "description": "Draw a model as points with extended parameters",
+ "returnType": "void",
+ "params": [
+ {
+ "type": "Model",
+ "name": "model"
+ },
+ {
+ "type": "Vector3",
+ "name": "position"
+ },
+ {
+ "type": "Vector3",
+ "name": "rotationAxis"
+ },
+ {
+ "type": "float",
+ "name": "rotationAngle"
+ },
+ {
+ "type": "Vector3",
+ "name": "scale"
+ },
+ {
+ "type": "Color",
+ "name": "tint"
+ }
+ ]
+ },
{
"name": "DrawBoundingBox",
"description": "Draw bounding box (wires)",
@@ -10859,8 +10994,8 @@
"returnType": "Material"
},
{
- "name": "IsMaterialReady",
- "description": "Check if a material is ready",
+ "name": "IsMaterialValid",
+ "description": "Check if a material is valid (shader assigned, map textures loaded in GPU)",
"returnType": "bool",
"params": [
{
@@ -10993,6 +11128,25 @@
}
]
},
+ {
+ "name": "UpdateModelAnimationBoneMatrices",
+ "description": "Update model animation mesh bone matrices (Note GPU skinning does not work on Mac)",
+ "returnType": "void",
+ "params": [
+ {
+ "type": "Model",
+ "name": "model"
+ },
+ {
+ "type": "ModelAnimation",
+ "name": "anim"
+ },
+ {
+ "type": "int",
+ "name": "frame"
+ }
+ ]
+ },
{
"name": "CheckCollisionSpheres",
"description": "Check collision between two spheres",
@@ -11215,8 +11369,8 @@
]
},
{
- "name": "IsWaveReady",
- "description": "Checks if wave data is ready",
+ "name": "IsWaveValid",
+ "description": "Checks if wave data is valid (data loaded and parameters)",
"returnType": "bool",
"params": [
{
@@ -11259,8 +11413,8 @@
]
},
{
- "name": "IsSoundReady",
- "description": "Checks if a sound is ready",
+ "name": "IsSoundValid",
+ "description": "Checks if a sound is valid (data loaded and buffers initialized)",
"returnType": "bool",
"params": [
{
@@ -11557,8 +11711,8 @@
]
},
{
- "name": "IsMusicReady",
- "description": "Checks if a music stream is ready",
+ "name": "IsMusicValid",
+ "description": "Checks if a music stream is valid (context and buffers initialized)",
"returnType": "bool",
"params": [
{
@@ -11746,8 +11900,8 @@
]
},
{
- "name": "IsAudioStreamReady",
- "description": "Checks if an audio stream is ready",
+ "name": "IsAudioStreamValid",
+ "description": "Checks if an audio stream is valid (buffers initialized)",
"returnType": "bool",
"params": [
{
diff --git a/parser/output/raylib_api.lua b/parser/output/raylib_api.lua
index 3a9e2f04f..b84e3c08c 100644
--- a/parser/output/raylib_api.lua
+++ b/parser/output/raylib_api.lua
@@ -850,12 +850,22 @@ return {
{
type = "unsigned char *",
name = "boneIds",
- description = "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning)"
+ description = "Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)"
},
{
type = "float *",
name = "boneWeights",
- description = "Vertex bone weight, up to 4 bones influence by vertex (skinning)"
+ description = "Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)"
+ },
+ {
+ type = "Matrix *",
+ name = "boneMatrices",
+ description = "Bones animated transformation matrices"
+ },
+ {
+ type = "int",
+ name = "boneCount",
+ description = "Number of bones"
},
{
type = "unsigned int",
@@ -2518,6 +2528,21 @@ return {
name = "SHADER_LOC_MAP_BRDF",
value = 25,
description = "Shader location: sampler2d texture: brdf"
+ },
+ {
+ name = "SHADER_LOC_VERTEX_BONEIDS",
+ value = 26,
+ description = "Shader location: vertex attribute: boneIds"
+ },
+ {
+ name = "SHADER_LOC_VERTEX_BONEWEIGHTS",
+ value = 27,
+ description = "Shader location: vertex attribute: boneWeights"
+ },
+ {
+ name = "SHADER_LOC_BONE_MATRICES",
+ value = 28,
+ description = "Shader location: array of matrices uniform: boneMatrices"
}
}
},
@@ -3158,12 +3183,12 @@ return {
},
{
name = "ToggleFullscreen",
- description = "Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)",
+ description = "Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP)",
returnType = "void"
},
{
name = "ToggleBorderlessWindowed",
- description = "Toggle window state: borderless windowed (only PLATFORM_DESKTOP)",
+ description = "Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP)",
returnType = "void"
},
{
@@ -3564,8 +3589,8 @@ return {
}
},
{
- name = "IsShaderReady",
- description = "Check if a shader is ready",
+ name = "IsShaderValid",
+ description = "Check if a shader is valid (loaded on GPU)",
returnType = "bool",
params = {
{type = "Shader", name = "shader"}
@@ -4042,6 +4067,14 @@ return {
description = "Get the directory of the running application (uses static string)",
returnType = "const char *"
},
+ {
+ name = "MakeDirectory",
+ description = "Create directories (including full path requested), returns 0 on success",
+ returnType = "int",
+ params = {
+ {type = "const char *", name = "dirPath"}
+ }
+ },
{
name = "ChangeDirectory",
description = "Change working directory, return true on success",
@@ -4076,7 +4109,7 @@ return {
},
{
name = "LoadDirectoryFilesEx",
- description = "Load directory filepaths with extension filtering and recursive directory scan",
+ description = "Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result",
returnType = "FilePathList",
params = {
{type = "const char *", name = "basePath"},
@@ -4157,6 +4190,33 @@ return {
{type = "int *", name = "outputSize"}
}
},
+ {
+ name = "ComputeCRC32",
+ description = "Compute CRC32 hash code",
+ returnType = "unsigned int",
+ params = {
+ {type = "unsigned char *", name = "data"},
+ {type = "int", name = "dataSize"}
+ }
+ },
+ {
+ name = "ComputeMD5",
+ description = "Compute MD5 hash code, returns static int[4] (16 bytes)",
+ returnType = "unsigned int *",
+ params = {
+ {type = "unsigned char *", name = "data"},
+ {type = "int", name = "dataSize"}
+ }
+ },
+ {
+ name = "ComputeSHA1",
+ description = "Compute SHA1 hash code, returns static int[5] (20 bytes)",
+ returnType = "unsigned int *",
+ params = {
+ {type = "unsigned char *", name = "data"},
+ {type = "int", name = "dataSize"}
+ }
+ },
{
name = "LoadAutomationEventList",
description = "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS",
@@ -4517,7 +4577,7 @@ return {
},
{
name = "GetGestureHoldDuration",
- description = "Get gesture hold time in milliseconds",
+ description = "Get gesture hold time in seconds",
returnType = "float"
},
{
@@ -4581,7 +4641,7 @@ return {
},
{
name = "DrawPixel",
- description = "Draw a pixel",
+ description = "Draw a pixel using geometry [Can be slow, use with care]",
returnType = "void",
params = {
{type = "int", name = "posX"},
@@ -4591,7 +4651,7 @@ return {
},
{
name = "DrawPixelV",
- description = "Draw a pixel (Vector version)",
+ description = "Draw a pixel using geometry (Vector version) [Can be slow, use with care]",
returnType = "void",
params = {
{type = "Vector2", name = "position"},
@@ -5306,16 +5366,6 @@ return {
{type = "int", name = "headerSize"}
}
},
- {
- name = "LoadImageSvg",
- description = "Load image from SVG file data or string with specified size",
- returnType = "Image",
- params = {
- {type = "const char *", name = "fileNameOrString"},
- {type = "int", name = "width"},
- {type = "int", name = "height"}
- }
- },
{
name = "LoadImageAnim",
description = "Load image sequence from file (frames appended to image.data)",
@@ -5360,8 +5410,8 @@ return {
returnType = "Image"
},
{
- name = "IsImageReady",
- description = "Check if an image is ready",
+ name = "IsImageValid",
+ description = "Check if an image is valid (data and parameters)",
returnType = "bool",
params = {
{type = "Image", name = "image"}
@@ -6125,8 +6175,8 @@ return {
}
},
{
- name = "IsTextureReady",
- description = "Check if a texture is ready",
+ name = "IsTextureValid",
+ description = "Check if a texture is valid (loaded in GPU)",
returnType = "bool",
params = {
{type = "Texture2D", name = "texture"}
@@ -6141,8 +6191,8 @@ return {
}
},
{
- name = "IsRenderTextureReady",
- description = "Check if a render texture is ready",
+ name = "IsRenderTextureValid",
+ description = "Check if a render texture is valid (loaded in GPU)",
returnType = "bool",
params = {
{type = "RenderTexture2D", name = "target"}
@@ -6377,6 +6427,16 @@ return {
{type = "Color", name = "tint"}
}
},
+ {
+ name = "ColorLerp",
+ description = "Get color lerp interpolation between two colors, factor [0.0f..1.0f]",
+ returnType = "Color",
+ params = {
+ {type = "Color", name = "color1"},
+ {type = "Color", name = "color2"},
+ {type = "float", name = "factor"}
+ }
+ },
{
name = "GetColor",
description = "Get Color structure from hexadecimal value",
@@ -6429,7 +6489,7 @@ return {
},
{
name = "LoadFontEx",
- description = "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character setFont",
+ description = "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height",
returnType = "Font",
params = {
{type = "const char *", name = "fileName"},
@@ -6462,8 +6522,8 @@ return {
}
},
{
- name = "IsFontReady",
- description = "Check if a font is ready",
+ name = "IsFontValid",
+ description = "Check if a font is valid (font data loaded, WARNING: GPU texture not checked)",
returnType = "bool",
params = {
{type = "Font", name = "font"}
@@ -7142,8 +7202,8 @@ return {
}
},
{
- name = "IsModelReady",
- description = "Check if a model is ready",
+ name = "IsModelValid",
+ description = "Check if a model is valid (loaded in GPU, VAO/VBOs)",
returnType = "bool",
params = {
{type = "Model", name = "model"}
@@ -7213,6 +7273,30 @@ return {
{type = "Color", name = "tint"}
}
},
+ {
+ name = "DrawModelPoints",
+ description = "Draw a model as points",
+ returnType = "void",
+ params = {
+ {type = "Model", name = "model"},
+ {type = "Vector3", name = "position"},
+ {type = "float", name = "scale"},
+ {type = "Color", name = "tint"}
+ }
+ },
+ {
+ name = "DrawModelPointsEx",
+ description = "Draw a model as points with extended parameters",
+ returnType = "void",
+ params = {
+ {type = "Model", name = "model"},
+ {type = "Vector3", name = "position"},
+ {type = "Vector3", name = "rotationAxis"},
+ {type = "float", name = "rotationAngle"},
+ {type = "Vector3", name = "scale"},
+ {type = "Color", name = "tint"}
+ }
+ },
{
name = "DrawBoundingBox",
description = "Draw bounding box (wires)",
@@ -7472,8 +7556,8 @@ return {
returnType = "Material"
},
{
- name = "IsMaterialReady",
- description = "Check if a material is ready",
+ name = "IsMaterialValid",
+ description = "Check if a material is valid (shader assigned, map textures loaded in GPU)",
returnType = "bool",
params = {
{type = "Material", name = "material"}
@@ -7552,6 +7636,16 @@ return {
{type = "ModelAnimation", name = "anim"}
}
},
+ {
+ name = "UpdateModelAnimationBoneMatrices",
+ description = "Update model animation mesh bone matrices (Note GPU skinning does not work on Mac)",
+ returnType = "void",
+ params = {
+ {type = "Model", name = "model"},
+ {type = "ModelAnimation", name = "anim"},
+ {type = "int", name = "frame"}
+ }
+ },
{
name = "CheckCollisionSpheres",
description = "Check collision between two spheres",
@@ -7681,8 +7775,8 @@ return {
}
},
{
- name = "IsWaveReady",
- description = "Checks if wave data is ready",
+ name = "IsWaveValid",
+ description = "Checks if wave data is valid (data loaded and parameters)",
returnType = "bool",
params = {
{type = "Wave", name = "wave"}
@@ -7713,8 +7807,8 @@ return {
}
},
{
- name = "IsSoundReady",
- description = "Checks if a sound is ready",
+ name = "IsSoundValid",
+ description = "Checks if a sound is valid (data loaded and buffers initialized)",
returnType = "bool",
params = {
{type = "Sound", name = "sound"}
@@ -7903,8 +7997,8 @@ return {
}
},
{
- name = "IsMusicReady",
- description = "Checks if a music stream is ready",
+ name = "IsMusicValid",
+ description = "Checks if a music stream is valid (context and buffers initialized)",
returnType = "bool",
params = {
{type = "Music", name = "music"}
@@ -8029,8 +8123,8 @@ return {
}
},
{
- name = "IsAudioStreamReady",
- description = "Checks if an audio stream is ready",
+ name = "IsAudioStreamValid",
+ description = "Checks if an audio stream is valid (buffers initialized)",
returnType = "bool",
params = {
{type = "AudioStream", name = "stream"}
diff --git a/parser/output/raylib_api.txt b/parser/output/raylib_api.txt
index afa9b525d..e0d5f36b4 100644
--- a/parser/output/raylib_api.txt
+++ b/parser/output/raylib_api.txt
@@ -403,7 +403,7 @@ Struct 14: Camera2D (4 fields)
Field[2]: Vector2 target // Camera target (rotation and zoom origin)
Field[3]: float rotation // Camera rotation in degrees
Field[4]: float zoom // Camera zoom (scaling), should be 1.0f by default
-Struct 15: Mesh (15 fields)
+Struct 15: Mesh (17 fields)
Name: Mesh
Description: Mesh, vertex data and vao/vbo
Field[1]: int vertexCount // Number of vertices stored in arrays
@@ -417,10 +417,12 @@ Struct 15: Mesh (15 fields)
Field[9]: unsigned short * indices // Vertex indices (in case vertex data comes indexed)
Field[10]: float * animVertices // Animated vertex positions (after bones transformations)
Field[11]: float * animNormals // Animated normals (after bones transformations)
- Field[12]: unsigned char * boneIds // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning)
- Field[13]: float * boneWeights // Vertex bone weight, up to 4 bones influence by vertex (skinning)
- Field[14]: unsigned int vaoId // OpenGL Vertex Array Object id
- Field[15]: unsigned int * vboId // OpenGL Vertex Buffer Objects id (default vertex data)
+ Field[12]: unsigned char * boneIds // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) (shader-location = 6)
+ Field[13]: float * boneWeights // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)
+ Field[14]: Matrix * boneMatrices // Bones animated transformation matrices
+ Field[15]: int boneCount // Number of bones
+ Field[16]: unsigned int vaoId // OpenGL Vertex Array Object id
+ Field[17]: unsigned int * vboId // OpenGL Vertex Buffer Objects id (default vertex data)
Struct 16: Shader (2 fields)
Name: Shader
Description: Shader
@@ -793,7 +795,7 @@ Enum 08: MaterialMapIndex (11 values)
Value[MATERIAL_MAP_IRRADIANCE]: 8
Value[MATERIAL_MAP_PREFILTER]: 9
Value[MATERIAL_MAP_BRDF]: 10
-Enum 09: ShaderLocationIndex (26 values)
+Enum 09: ShaderLocationIndex (29 values)
Name: ShaderLocationIndex
Description: Shader location index
Value[SHADER_LOC_VERTEX_POSITION]: 0
@@ -822,6 +824,9 @@ Enum 09: ShaderLocationIndex (26 values)
Value[SHADER_LOC_MAP_IRRADIANCE]: 23
Value[SHADER_LOC_MAP_PREFILTER]: 24
Value[SHADER_LOC_MAP_BRDF]: 25
+ Value[SHADER_LOC_VERTEX_BONEIDS]: 26
+ Value[SHADER_LOC_VERTEX_BONEWEIGHTS]: 27
+ Value[SHADER_LOC_BONE_MATRICES]: 28
Enum 10: ShaderUniformDataType (9 values)
Name: ShaderUniformDataType
Description: Shader uniform data type
@@ -984,7 +989,7 @@ Callback 006: AudioCallback() (2 input parameters)
Param[1]: bufferData (type: void *)
Param[2]: frames (type: unsigned int)
-Functions found: 573
+Functions found: 580
Function 001: InitWindow() (3 input parameters)
Name: InitWindow
@@ -1056,12 +1061,12 @@ Function 013: ClearWindowState() (1 input parameters)
Function 014: ToggleFullscreen() (0 input parameters)
Name: ToggleFullscreen
Return type: void
- Description: Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)
+ Description: Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP)
No input parameters
Function 015: ToggleBorderlessWindowed() (0 input parameters)
Name: ToggleBorderlessWindowed
Return type: void
- Description: Toggle window state: borderless windowed (only PLATFORM_DESKTOP)
+ Description: Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP)
No input parameters
Function 016: MaximizeWindow() (0 input parameters)
Name: MaximizeWindow
@@ -1373,10 +1378,10 @@ Function 075: LoadShaderFromMemory() (2 input parameters)
Description: Load shader from code strings and bind default locations
Param[1]: vsCode (type: const char *)
Param[2]: fsCode (type: const char *)
-Function 076: IsShaderReady() (1 input parameters)
- Name: IsShaderReady
+Function 076: IsShaderValid() (1 input parameters)
+ Name: IsShaderValid
Return type: bool
- Description: Check if a shader is ready
+ Description: Check if a shader is valid (loaded on GPU)
Param[1]: shader (type: Shader)
Function 077: GetShaderLocation() (2 input parameters)
Name: GetShaderLocation
@@ -1699,373 +1704,396 @@ Function 133: GetApplicationDirectory() (0 input parameters)
Return type: const char *
Description: Get the directory of the running application (uses static string)
No input parameters
-Function 134: ChangeDirectory() (1 input parameters)
+Function 134: MakeDirectory() (1 input parameters)
+ Name: MakeDirectory
+ Return type: int
+ Description: Create directories (including full path requested), returns 0 on success
+ Param[1]: dirPath (type: const char *)
+Function 135: ChangeDirectory() (1 input parameters)
Name: ChangeDirectory
Return type: bool
Description: Change working directory, return true on success
Param[1]: dir (type: const char *)
-Function 135: IsPathFile() (1 input parameters)
+Function 136: IsPathFile() (1 input parameters)
Name: IsPathFile
Return type: bool
Description: Check if a given path is a file or a directory
Param[1]: path (type: const char *)
-Function 136: IsFileNameValid() (1 input parameters)
+Function 137: IsFileNameValid() (1 input parameters)
Name: IsFileNameValid
Return type: bool
Description: Check if fileName is valid for the platform/OS
Param[1]: fileName (type: const char *)
-Function 137: LoadDirectoryFiles() (1 input parameters)
+Function 138: LoadDirectoryFiles() (1 input parameters)
Name: LoadDirectoryFiles
Return type: FilePathList
Description: Load directory filepaths
Param[1]: dirPath (type: const char *)
-Function 138: LoadDirectoryFilesEx() (3 input parameters)
+Function 139: LoadDirectoryFilesEx() (3 input parameters)
Name: LoadDirectoryFilesEx
Return type: FilePathList
- Description: Load directory filepaths with extension filtering and recursive directory scan
+ Description: Load directory filepaths with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result
Param[1]: basePath (type: const char *)
Param[2]: filter (type: const char *)
Param[3]: scanSubdirs (type: bool)
-Function 139: UnloadDirectoryFiles() (1 input parameters)
+Function 140: UnloadDirectoryFiles() (1 input parameters)
Name: UnloadDirectoryFiles
Return type: void
Description: Unload filepaths
Param[1]: files (type: FilePathList)
-Function 140: IsFileDropped() (0 input parameters)
+Function 141: IsFileDropped() (0 input parameters)
Name: IsFileDropped
Return type: bool
Description: Check if a file has been dropped into window
No input parameters
-Function 141: LoadDroppedFiles() (0 input parameters)
+Function 142: LoadDroppedFiles() (0 input parameters)
Name: LoadDroppedFiles
Return type: FilePathList
Description: Load dropped filepaths
No input parameters
-Function 142: UnloadDroppedFiles() (1 input parameters)
+Function 143: UnloadDroppedFiles() (1 input parameters)
Name: UnloadDroppedFiles
Return type: void
Description: Unload dropped filepaths
Param[1]: files (type: FilePathList)
-Function 143: GetFileModTime() (1 input parameters)
+Function 144: GetFileModTime() (1 input parameters)
Name: GetFileModTime
Return type: long
Description: Get file modification time (last write time)
Param[1]: fileName (type: const char *)
-Function 144: CompressData() (3 input parameters)
+Function 145: CompressData() (3 input parameters)
Name: CompressData
Return type: unsigned char *
Description: Compress data (DEFLATE algorithm), memory must be MemFree()
Param[1]: data (type: const unsigned char *)
Param[2]: dataSize (type: int)
Param[3]: compDataSize (type: int *)
-Function 145: DecompressData() (3 input parameters)
+Function 146: DecompressData() (3 input parameters)
Name: DecompressData
Return type: unsigned char *
Description: Decompress data (DEFLATE algorithm), memory must be MemFree()
Param[1]: compData (type: const unsigned char *)
Param[2]: compDataSize (type: int)
Param[3]: dataSize (type: int *)
-Function 146: EncodeDataBase64() (3 input parameters)
+Function 147: EncodeDataBase64() (3 input parameters)
Name: EncodeDataBase64
Return type: char *
Description: Encode data to Base64 string, memory must be MemFree()
Param[1]: data (type: const unsigned char *)
Param[2]: dataSize (type: int)
Param[3]: outputSize (type: int *)
-Function 147: DecodeDataBase64() (2 input parameters)
+Function 148: DecodeDataBase64() (2 input parameters)
Name: DecodeDataBase64
Return type: unsigned char *
Description: Decode Base64 string data, memory must be MemFree()
Param[1]: data (type: const unsigned char *)
Param[2]: outputSize (type: int *)
-Function 148: LoadAutomationEventList() (1 input parameters)
+Function 149: ComputeCRC32() (2 input parameters)
+ Name: ComputeCRC32
+ Return type: unsigned int
+ Description: Compute CRC32 hash code
+ Param[1]: data (type: unsigned char *)
+ Param[2]: dataSize (type: int)
+Function 150: ComputeMD5() (2 input parameters)
+ Name: ComputeMD5
+ Return type: unsigned int *
+ Description: Compute MD5 hash code, returns static int[4] (16 bytes)
+ Param[1]: data (type: unsigned char *)
+ Param[2]: dataSize (type: int)
+Function 151: ComputeSHA1() (2 input parameters)
+ Name: ComputeSHA1
+ Return type: unsigned int *
+ Description: Compute SHA1 hash code, returns static int[5] (20 bytes)
+ Param[1]: data (type: unsigned char *)
+ Param[2]: dataSize (type: int)
+Function 152: LoadAutomationEventList() (1 input parameters)
Name: LoadAutomationEventList
Return type: AutomationEventList
Description: Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
Param[1]: fileName (type: const char *)
-Function 149: UnloadAutomationEventList() (1 input parameters)
+Function 153: UnloadAutomationEventList() (1 input parameters)
Name: UnloadAutomationEventList
Return type: void
Description: Unload automation events list from file
Param[1]: list (type: AutomationEventList)
-Function 150: ExportAutomationEventList() (2 input parameters)
+Function 154: ExportAutomationEventList() (2 input parameters)
Name: ExportAutomationEventList
Return type: bool
Description: Export automation events list as text file
Param[1]: list (type: AutomationEventList)
Param[2]: fileName (type: const char *)
-Function 151: SetAutomationEventList() (1 input parameters)
+Function 155: SetAutomationEventList() (1 input parameters)
Name: SetAutomationEventList
Return type: void
Description: Set automation event list to record to
Param[1]: list (type: AutomationEventList *)
-Function 152: SetAutomationEventBaseFrame() (1 input parameters)
+Function 156: SetAutomationEventBaseFrame() (1 input parameters)
Name: SetAutomationEventBaseFrame
Return type: void
Description: Set automation event internal base frame to start recording
Param[1]: frame (type: int)
-Function 153: StartAutomationEventRecording() (0 input parameters)
+Function 157: StartAutomationEventRecording() (0 input parameters)
Name: StartAutomationEventRecording
Return type: void
Description: Start recording automation events (AutomationEventList must be set)
No input parameters
-Function 154: StopAutomationEventRecording() (0 input parameters)
+Function 158: StopAutomationEventRecording() (0 input parameters)
Name: StopAutomationEventRecording
Return type: void
Description: Stop recording automation events
No input parameters
-Function 155: PlayAutomationEvent() (1 input parameters)
+Function 159: PlayAutomationEvent() (1 input parameters)
Name: PlayAutomationEvent
Return type: void
Description: Play a recorded automation event
Param[1]: event (type: AutomationEvent)
-Function 156: IsKeyPressed() (1 input parameters)
+Function 160: IsKeyPressed() (1 input parameters)
Name: IsKeyPressed
Return type: bool
Description: Check if a key has been pressed once
Param[1]: key (type: int)
-Function 157: IsKeyPressedRepeat() (1 input parameters)
+Function 161: IsKeyPressedRepeat() (1 input parameters)
Name: IsKeyPressedRepeat
Return type: bool
Description: Check if a key has been pressed again (Only PLATFORM_DESKTOP)
Param[1]: key (type: int)
-Function 158: IsKeyDown() (1 input parameters)
+Function 162: IsKeyDown() (1 input parameters)
Name: IsKeyDown
Return type: bool
Description: Check if a key is being pressed
Param[1]: key (type: int)
-Function 159: IsKeyReleased() (1 input parameters)
+Function 163: IsKeyReleased() (1 input parameters)
Name: IsKeyReleased
Return type: bool
Description: Check if a key has been released once
Param[1]: key (type: int)
-Function 160: IsKeyUp() (1 input parameters)
+Function 164: IsKeyUp() (1 input parameters)
Name: IsKeyUp
Return type: bool
Description: Check if a key is NOT being pressed
Param[1]: key (type: int)
-Function 161: GetKeyPressed() (0 input parameters)
+Function 165: GetKeyPressed() (0 input parameters)
Name: GetKeyPressed
Return type: int
Description: Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty
No input parameters
-Function 162: GetCharPressed() (0 input parameters)
+Function 166: GetCharPressed() (0 input parameters)
Name: GetCharPressed
Return type: int
Description: Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty
No input parameters
-Function 163: SetExitKey() (1 input parameters)
+Function 167: SetExitKey() (1 input parameters)
Name: SetExitKey
Return type: void
Description: Set a custom key to exit program (default is ESC)
Param[1]: key (type: int)
-Function 164: IsGamepadAvailable() (1 input parameters)
+Function 168: IsGamepadAvailable() (1 input parameters)
Name: IsGamepadAvailable
Return type: bool
Description: Check if a gamepad is available
Param[1]: gamepad (type: int)
-Function 165: GetGamepadName() (1 input parameters)
+Function 169: GetGamepadName() (1 input parameters)
Name: GetGamepadName
Return type: const char *
Description: Get gamepad internal name id
Param[1]: gamepad (type: int)
-Function 166: IsGamepadButtonPressed() (2 input parameters)
+Function 170: IsGamepadButtonPressed() (2 input parameters)
Name: IsGamepadButtonPressed
Return type: bool
Description: Check if a gamepad button has been pressed once
Param[1]: gamepad (type: int)
Param[2]: button (type: int)
-Function 167: IsGamepadButtonDown() (2 input parameters)
+Function 171: IsGamepadButtonDown() (2 input parameters)
Name: IsGamepadButtonDown
Return type: bool
Description: Check if a gamepad button is being pressed
Param[1]: gamepad (type: int)
Param[2]: button (type: int)
-Function 168: IsGamepadButtonReleased() (2 input parameters)
+Function 172: IsGamepadButtonReleased() (2 input parameters)
Name: IsGamepadButtonReleased
Return type: bool
Description: Check if a gamepad button has been released once
Param[1]: gamepad (type: int)
Param[2]: button (type: int)
-Function 169: IsGamepadButtonUp() (2 input parameters)
+Function 173: IsGamepadButtonUp() (2 input parameters)
Name: IsGamepadButtonUp
Return type: bool
Description: Check if a gamepad button is NOT being pressed
Param[1]: gamepad (type: int)
Param[2]: button (type: int)
-Function 170: GetGamepadButtonPressed() (0 input parameters)
+Function 174: GetGamepadButtonPressed() (0 input parameters)
Name: GetGamepadButtonPressed
Return type: int
Description: Get the last gamepad button pressed
No input parameters
-Function 171: GetGamepadAxisCount() (1 input parameters)
+Function 175: GetGamepadAxisCount() (1 input parameters)
Name: GetGamepadAxisCount
Return type: int
Description: Get gamepad axis count for a gamepad
Param[1]: gamepad (type: int)
-Function 172: GetGamepadAxisMovement() (2 input parameters)
+Function 176: GetGamepadAxisMovement() (2 input parameters)
Name: GetGamepadAxisMovement
Return type: float
Description: Get axis movement value for a gamepad axis
Param[1]: gamepad (type: int)
Param[2]: axis (type: int)
-Function 173: SetGamepadMappings() (1 input parameters)
+Function 177: SetGamepadMappings() (1 input parameters)
Name: SetGamepadMappings
Return type: int
Description: Set internal gamepad mappings (SDL_GameControllerDB)
Param[1]: mappings (type: const char *)
-Function 174: SetGamepadVibration() (3 input parameters)
+Function 178: SetGamepadVibration() (3 input parameters)
Name: SetGamepadVibration
Return type: void
Description: Set gamepad vibration for both motors
Param[1]: gamepad (type: int)
Param[2]: leftMotor (type: float)
Param[3]: rightMotor (type: float)
-Function 175: IsMouseButtonPressed() (1 input parameters)
+Function 179: IsMouseButtonPressed() (1 input parameters)
Name: IsMouseButtonPressed
Return type: bool
Description: Check if a mouse button has been pressed once
Param[1]: button (type: int)
-Function 176: IsMouseButtonDown() (1 input parameters)
+Function 180: IsMouseButtonDown() (1 input parameters)
Name: IsMouseButtonDown
Return type: bool
Description: Check if a mouse button is being pressed
Param[1]: button (type: int)
-Function 177: IsMouseButtonReleased() (1 input parameters)
+Function 181: IsMouseButtonReleased() (1 input parameters)
Name: IsMouseButtonReleased
Return type: bool
Description: Check if a mouse button has been released once
Param[1]: button (type: int)
-Function 178: IsMouseButtonUp() (1 input parameters)
+Function 182: IsMouseButtonUp() (1 input parameters)
Name: IsMouseButtonUp
Return type: bool
Description: Check if a mouse button is NOT being pressed
Param[1]: button (type: int)
-Function 179: GetMouseX() (0 input parameters)
+Function 183: GetMouseX() (0 input parameters)
Name: GetMouseX
Return type: int
Description: Get mouse position X
No input parameters
-Function 180: GetMouseY() (0 input parameters)
+Function 184: GetMouseY() (0 input parameters)
Name: GetMouseY
Return type: int
Description: Get mouse position Y
No input parameters
-Function 181: GetMousePosition() (0 input parameters)
+Function 185: GetMousePosition() (0 input parameters)
Name: GetMousePosition
Return type: Vector2
Description: Get mouse position XY
No input parameters
-Function 182: GetMouseDelta() (0 input parameters)
+Function 186: GetMouseDelta() (0 input parameters)
Name: GetMouseDelta
Return type: Vector2
Description: Get mouse delta between frames
No input parameters
-Function 183: SetMousePosition() (2 input parameters)
+Function 187: SetMousePosition() (2 input parameters)
Name: SetMousePosition
Return type: void
Description: Set mouse position XY
Param[1]: x (type: int)
Param[2]: y (type: int)
-Function 184: SetMouseOffset() (2 input parameters)
+Function 188: SetMouseOffset() (2 input parameters)
Name: SetMouseOffset
Return type: void
Description: Set mouse offset
Param[1]: offsetX (type: int)
Param[2]: offsetY (type: int)
-Function 185: SetMouseScale() (2 input parameters)
+Function 189: SetMouseScale() (2 input parameters)
Name: SetMouseScale
Return type: void
Description: Set mouse scaling
Param[1]: scaleX (type: float)
Param[2]: scaleY (type: float)
-Function 186: GetMouseWheelMove() (0 input parameters)
+Function 190: GetMouseWheelMove() (0 input parameters)
Name: GetMouseWheelMove
Return type: float
Description: Get mouse wheel movement for X or Y, whichever is larger
No input parameters
-Function 187: GetMouseWheelMoveV() (0 input parameters)
+Function 191: GetMouseWheelMoveV() (0 input parameters)
Name: GetMouseWheelMoveV
Return type: Vector2
Description: Get mouse wheel movement for both X and Y
No input parameters
-Function 188: SetMouseCursor() (1 input parameters)
+Function 192: SetMouseCursor() (1 input parameters)
Name: SetMouseCursor
Return type: void
Description: Set mouse cursor
Param[1]: cursor (type: int)
-Function 189: GetTouchX() (0 input parameters)
+Function 193: GetTouchX() (0 input parameters)
Name: GetTouchX
Return type: int
Description: Get touch position X for touch point 0 (relative to screen size)
No input parameters
-Function 190: GetTouchY() (0 input parameters)
+Function 194: GetTouchY() (0 input parameters)
Name: GetTouchY
Return type: int
Description: Get touch position Y for touch point 0 (relative to screen size)
No input parameters
-Function 191: GetTouchPosition() (1 input parameters)
+Function 195: GetTouchPosition() (1 input parameters)
Name: GetTouchPosition
Return type: Vector2
Description: Get touch position XY for a touch point index (relative to screen size)
Param[1]: index (type: int)
-Function 192: GetTouchPointId() (1 input parameters)
+Function 196: GetTouchPointId() (1 input parameters)
Name: GetTouchPointId
Return type: int
Description: Get touch point identifier for given index
Param[1]: index (type: int)
-Function 193: GetTouchPointCount() (0 input parameters)
+Function 197: GetTouchPointCount() (0 input parameters)
Name: GetTouchPointCount
Return type: int
Description: Get number of touch points
No input parameters
-Function 194: SetGesturesEnabled() (1 input parameters)
+Function 198: SetGesturesEnabled() (1 input parameters)
Name: SetGesturesEnabled
Return type: void
Description: Enable a set of gestures using flags
Param[1]: flags (type: unsigned int)
-Function 195: IsGestureDetected() (1 input parameters)
+Function 199: IsGestureDetected() (1 input parameters)
Name: IsGestureDetected
Return type: bool
Description: Check if a gesture have been detected
Param[1]: gesture (type: unsigned int)
-Function 196: GetGestureDetected() (0 input parameters)
+Function 200: GetGestureDetected() (0 input parameters)
Name: GetGestureDetected
Return type: int
Description: Get latest detected gesture
No input parameters
-Function 197: GetGestureHoldDuration() (0 input parameters)
+Function 201: GetGestureHoldDuration() (0 input parameters)
Name: GetGestureHoldDuration
Return type: float
- Description: Get gesture hold time in milliseconds
+ Description: Get gesture hold time in seconds
No input parameters
-Function 198: GetGestureDragVector() (0 input parameters)
+Function 202: GetGestureDragVector() (0 input parameters)
Name: GetGestureDragVector
Return type: Vector2
Description: Get gesture drag vector
No input parameters
-Function 199: GetGestureDragAngle() (0 input parameters)
+Function 203: GetGestureDragAngle() (0 input parameters)
Name: GetGestureDragAngle
Return type: float
Description: Get gesture drag angle
No input parameters
-Function 200: GetGesturePinchVector() (0 input parameters)
+Function 204: GetGesturePinchVector() (0 input parameters)
Name: GetGesturePinchVector
Return type: Vector2
Description: Get gesture pinch delta
No input parameters
-Function 201: GetGesturePinchAngle() (0 input parameters)
+Function 205: GetGesturePinchAngle() (0 input parameters)
Name: GetGesturePinchAngle
Return type: float
Description: Get gesture pinch angle
No input parameters
-Function 202: UpdateCamera() (2 input parameters)
+Function 206: UpdateCamera() (2 input parameters)
Name: UpdateCamera
Return type: void
Description: Update camera position for selected mode
Param[1]: camera (type: Camera *)
Param[2]: mode (type: int)
-Function 203: UpdateCameraPro() (4 input parameters)
+Function 207: UpdateCameraPro() (4 input parameters)
Name: UpdateCameraPro
Return type: void
Description: Update camera movement/rotation
@@ -2073,36 +2101,36 @@ Function 203: UpdateCameraPro() (4 input parameters)
Param[2]: movement (type: Vector3)
Param[3]: rotation (type: Vector3)
Param[4]: zoom (type: float)
-Function 204: SetShapesTexture() (2 input parameters)
+Function 208: SetShapesTexture() (2 input parameters)
Name: SetShapesTexture
Return type: void
Description: Set texture and rectangle to be used on shapes drawing
Param[1]: texture (type: Texture2D)
Param[2]: source (type: Rectangle)
-Function 205: GetShapesTexture() (0 input parameters)
+Function 209: GetShapesTexture() (0 input parameters)
Name: GetShapesTexture
Return type: Texture2D
Description: Get texture that is used for shapes drawing
No input parameters
-Function 206: GetShapesTextureRectangle() (0 input parameters)
+Function 210: GetShapesTextureRectangle() (0 input parameters)
Name: GetShapesTextureRectangle
Return type: Rectangle
Description: Get texture source rectangle that is used for shapes drawing
No input parameters
-Function 207: DrawPixel() (3 input parameters)
+Function 211: DrawPixel() (3 input parameters)
Name: DrawPixel
Return type: void
- Description: Draw a pixel
+ Description: Draw a pixel using geometry [Can be slow, use with care]
Param[1]: posX (type: int)
Param[2]: posY (type: int)
Param[3]: color (type: Color)
-Function 208: DrawPixelV() (2 input parameters)
+Function 212: DrawPixelV() (2 input parameters)
Name: DrawPixelV
Return type: void
- Description: Draw a pixel (Vector version)
+ Description: Draw a pixel using geometry (Vector version) [Can be slow, use with care]
Param[1]: position (type: Vector2)
Param[2]: color (type: Color)
-Function 209: DrawLine() (5 input parameters)
+Function 213: DrawLine() (5 input parameters)
Name: DrawLine
Return type: void
Description: Draw a line
@@ -2111,14 +2139,14 @@ Function 209: DrawLine() (5 input parameters)
Param[3]: endPosX (type: int)
Param[4]: endPosY (type: int)
Param[5]: color (type: Color)
-Function 210: DrawLineV() (3 input parameters)
+Function 214: DrawLineV() (3 input parameters)
Name: DrawLineV
Return type: void
Description: Draw a line (using gl lines)
Param[1]: startPos (type: Vector2)
Param[2]: endPos (type: Vector2)
Param[3]: color (type: Color)
-Function 211: DrawLineEx() (4 input parameters)
+Function 215: DrawLineEx() (4 input parameters)
Name: DrawLineEx
Return type: void
Description: Draw a line (using triangles/quads)
@@ -2126,14 +2154,14 @@ Function 211: DrawLineEx() (4 input parameters)
Param[2]: endPos (type: Vector2)
Param[3]: thick (type: float)
Param[4]: color (type: Color)
-Function 212: DrawLineStrip() (3 input parameters)
+Function 216: DrawLineStrip() (3 input parameters)
Name: DrawLineStrip
Return type: void
Description: Draw lines sequence (using gl lines)
Param[1]: points (type: const Vector2 *)
Param[2]: pointCount (type: int)
Param[3]: color (type: Color)
-Function 213: DrawLineBezier() (4 input parameters)
+Function 217: DrawLineBezier() (4 input parameters)
Name: DrawLineBezier
Return type: void
Description: Draw line segment cubic-bezier in-out interpolation
@@ -2141,7 +2169,7 @@ Function 213: DrawLineBezier() (4 input parameters)
Param[2]: endPos (type: Vector2)
Param[3]: thick (type: float)
Param[4]: color (type: Color)
-Function 214: DrawCircle() (4 input parameters)
+Function 218: DrawCircle() (4 input parameters)
Name: DrawCircle
Return type: void
Description: Draw a color-filled circle
@@ -2149,7 +2177,7 @@ Function 214: DrawCircle() (4 input parameters)
Param[2]: centerY (type: int)
Param[3]: radius (type: float)
Param[4]: color (type: Color)
-Function 215: DrawCircleSector() (6 input parameters)
+Function 219: DrawCircleSector() (6 input parameters)
Name: DrawCircleSector
Return type: void
Description: Draw a piece of a circle
@@ -2159,7 +2187,7 @@ Function 215: DrawCircleSector() (6 input parameters)
Param[4]: endAngle (type: float)
Param[5]: segments (type: int)
Param[6]: color (type: Color)
-Function 216: DrawCircleSectorLines() (6 input parameters)
+Function 220: DrawCircleSectorLines() (6 input parameters)
Name: DrawCircleSectorLines
Return type: void
Description: Draw circle sector outline
@@ -2169,7 +2197,7 @@ Function 216: DrawCircleSectorLines() (6 input parameters)
Param[4]: endAngle (type: float)
Param[5]: segments (type: int)
Param[6]: color (type: Color)
-Function 217: DrawCircleGradient() (5 input parameters)
+Function 221: DrawCircleGradient() (5 input parameters)
Name: DrawCircleGradient
Return type: void
Description: Draw a gradient-filled circle
@@ -2178,14 +2206,14 @@ Function 217: DrawCircleGradient() (5 input parameters)
Param[3]: radius (type: float)
Param[4]: inner (type: Color)
Param[5]: outer (type: Color)
-Function 218: DrawCircleV() (3 input parameters)
+Function 222: DrawCircleV() (3 input parameters)
Name: DrawCircleV
Return type: void
Description: Draw a color-filled circle (Vector version)
Param[1]: center (type: Vector2)
Param[2]: radius (type: float)
Param[3]: color (type: Color)
-Function 219: DrawCircleLines() (4 input parameters)
+Function 223: DrawCircleLines() (4 input parameters)
Name: DrawCircleLines
Return type: void
Description: Draw circle outline
@@ -2193,14 +2221,14 @@ Function 219: DrawCircleLines() (4 input parameters)
Param[2]: centerY (type: int)
Param[3]: radius (type: float)
Param[4]: color (type: Color)
-Function 220: DrawCircleLinesV() (3 input parameters)
+Function 224: DrawCircleLinesV() (3 input parameters)
Name: DrawCircleLinesV
Return type: void
Description: Draw circle outline (Vector version)
Param[1]: center (type: Vector2)
Param[2]: radius (type: float)
Param[3]: color (type: Color)
-Function 221: DrawEllipse() (5 input parameters)
+Function 225: DrawEllipse() (5 input parameters)
Name: DrawEllipse
Return type: void
Description: Draw ellipse
@@ -2209,7 +2237,7 @@ Function 221: DrawEllipse() (5 input parameters)
Param[3]: radiusH (type: float)
Param[4]: radiusV (type: float)
Param[5]: color (type: Color)
-Function 222: DrawEllipseLines() (5 input parameters)
+Function 226: DrawEllipseLines() (5 input parameters)
Name: DrawEllipseLines
Return type: void
Description: Draw ellipse outline
@@ -2218,7 +2246,7 @@ Function 222: DrawEllipseLines() (5 input parameters)
Param[3]: radiusH (type: float)
Param[4]: radiusV (type: float)
Param[5]: color (type: Color)
-Function 223: DrawRing() (7 input parameters)
+Function 227: DrawRing() (7 input parameters)
Name: DrawRing
Return type: void
Description: Draw ring
@@ -2229,7 +2257,7 @@ Function 223: DrawRing() (7 input parameters)
Param[5]: endAngle (type: float)
Param[6]: segments (type: int)
Param[7]: color (type: Color)
-Function 224: DrawRingLines() (7 input parameters)
+Function 228: DrawRingLines() (7 input parameters)
Name: DrawRingLines
Return type: void
Description: Draw ring outline
@@ -2240,7 +2268,7 @@ Function 224: DrawRingLines() (7 input parameters)
Param[5]: endAngle (type: float)
Param[6]: segments (type: int)
Param[7]: color (type: Color)
-Function 225: DrawRectangle() (5 input parameters)
+Function 229: DrawRectangle() (5 input parameters)
Name: DrawRectangle
Return type: void
Description: Draw a color-filled rectangle
@@ -2249,20 +2277,20 @@ Function 225: DrawRectangle() (5 input parameters)
Param[3]: width (type: int)
Param[4]: height (type: int)
Param[5]: color (type: Color)
-Function 226: DrawRectangleV() (3 input parameters)
+Function 230: DrawRectangleV() (3 input parameters)
Name: DrawRectangleV
Return type: void
Description: Draw a color-filled rectangle (Vector version)
Param[1]: position (type: Vector2)
Param[2]: size (type: Vector2)
Param[3]: color (type: Color)
-Function 227: DrawRectangleRec() (2 input parameters)
+Function 231: DrawRectangleRec() (2 input parameters)
Name: DrawRectangleRec
Return type: void
Description: Draw a color-filled rectangle
Param[1]: rec (type: Rectangle)
Param[2]: color (type: Color)
-Function 228: DrawRectanglePro() (4 input parameters)
+Function 232: DrawRectanglePro() (4 input parameters)
Name: DrawRectanglePro
Return type: void
Description: Draw a color-filled rectangle with pro parameters
@@ -2270,7 +2298,7 @@ Function 228: DrawRectanglePro() (4 input parameters)
Param[2]: origin (type: Vector2)
Param[3]: rotation (type: float)
Param[4]: color (type: Color)
-Function 229: DrawRectangleGradientV() (6 input parameters)
+Function 233: DrawRectangleGradientV() (6 input parameters)
Name: DrawRectangleGradientV
Return type: void
Description: Draw a vertical-gradient-filled rectangle
@@ -2280,7 +2308,7 @@ Function 229: DrawRectangleGradientV() (6 input parameters)
Param[4]: height (type: int)
Param[5]: top (type: Color)
Param[6]: bottom (type: Color)
-Function 230: DrawRectangleGradientH() (6 input parameters)
+Function 234: DrawRectangleGradientH() (6 input parameters)
Name: DrawRectangleGradientH
Return type: void
Description: Draw a horizontal-gradient-filled rectangle
@@ -2290,7 +2318,7 @@ Function 230: DrawRectangleGradientH() (6 input parameters)
Param[4]: height (type: int)
Param[5]: left (type: Color)
Param[6]: right (type: Color)
-Function 231: DrawRectangleGradientEx() (5 input parameters)
+Function 235: DrawRectangleGradientEx() (5 input parameters)
Name: DrawRectangleGradientEx
Return type: void
Description: Draw a gradient-filled rectangle with custom vertex colors
@@ -2299,7 +2327,7 @@ Function 231: DrawRectangleGradientEx() (5 input parameters)
Param[3]: bottomLeft (type: Color)
Param[4]: topRight (type: Color)
Param[5]: bottomRight (type: Color)
-Function 232: DrawRectangleLines() (5 input parameters)
+Function 236: DrawRectangleLines() (5 input parameters)
Name: DrawRectangleLines
Return type: void
Description: Draw rectangle outline
@@ -2308,14 +2336,14 @@ Function 232: DrawRectangleLines() (5 input parameters)
Param[3]: width (type: int)
Param[4]: height (type: int)
Param[5]: color (type: Color)
-Function 233: DrawRectangleLinesEx() (3 input parameters)
+Function 237: DrawRectangleLinesEx() (3 input parameters)
Name: DrawRectangleLinesEx
Return type: void
Description: Draw rectangle outline with extended parameters
Param[1]: rec (type: Rectangle)
Param[2]: lineThick (type: float)
Param[3]: color (type: Color)
-Function 234: DrawRectangleRounded() (4 input parameters)
+Function 238: DrawRectangleRounded() (4 input parameters)
Name: DrawRectangleRounded
Return type: void
Description: Draw rectangle with rounded edges
@@ -2323,7 +2351,7 @@ Function 234: DrawRectangleRounded() (4 input parameters)
Param[2]: roundness (type: float)
Param[3]: segments (type: int)
Param[4]: color (type: Color)
-Function 235: DrawRectangleRoundedLines() (4 input parameters)
+Function 239: DrawRectangleRoundedLines() (4 input parameters)
Name: DrawRectangleRoundedLines
Return type: void
Description: Draw rectangle lines with rounded edges
@@ -2331,7 +2359,7 @@ Function 235: DrawRectangleRoundedLines() (4 input parameters)
Param[2]: roundness (type: float)
Param[3]: segments (type: int)
Param[4]: color (type: Color)
-Function 236: DrawRectangleRoundedLinesEx() (5 input parameters)
+Function 240: DrawRectangleRoundedLinesEx() (5 input parameters)
Name: DrawRectangleRoundedLinesEx
Return type: void
Description: Draw rectangle with rounded edges outline
@@ -2340,7 +2368,7 @@ Function 236: DrawRectangleRoundedLinesEx() (5 input parameters)
Param[3]: segments (type: int)
Param[4]: lineThick (type: float)
Param[5]: color (type: Color)
-Function 237: DrawTriangle() (4 input parameters)
+Function 241: DrawTriangle() (4 input parameters)
Name: DrawTriangle
Return type: void
Description: Draw a color-filled triangle (vertex in counter-clockwise order!)
@@ -2348,7 +2376,7 @@ Function 237: DrawTriangle() (4 input parameters)
Param[2]: v2 (type: Vector2)
Param[3]: v3 (type: Vector2)
Param[4]: color (type: Color)
-Function 238: DrawTriangleLines() (4 input parameters)
+Function 242: DrawTriangleLines() (4 input parameters)
Name: DrawTriangleLines
Return type: void
Description: Draw triangle outline (vertex in counter-clockwise order!)
@@ -2356,21 +2384,21 @@ Function 238: DrawTriangleLines() (4 input parameters)
Param[2]: v2 (type: Vector2)
Param[3]: v3 (type: Vector2)
Param[4]: color (type: Color)
-Function 239: DrawTriangleFan() (3 input parameters)
+Function 243: DrawTriangleFan() (3 input parameters)
Name: DrawTriangleFan
Return type: void
Description: Draw a triangle fan defined by points (first vertex is the center)
Param[1]: points (type: const Vector2 *)
Param[2]: pointCount (type: int)
Param[3]: color (type: Color)
-Function 240: DrawTriangleStrip() (3 input parameters)
+Function 244: DrawTriangleStrip() (3 input parameters)
Name: DrawTriangleStrip
Return type: void
Description: Draw a triangle strip defined by points
Param[1]: points (type: const Vector2 *)
Param[2]: pointCount (type: int)
Param[3]: color (type: Color)
-Function 241: DrawPoly() (5 input parameters)
+Function 245: DrawPoly() (5 input parameters)
Name: DrawPoly
Return type: void
Description: Draw a regular polygon (Vector version)
@@ -2379,7 +2407,7 @@ Function 241: DrawPoly() (5 input parameters)
Param[3]: radius (type: float)
Param[4]: rotation (type: float)
Param[5]: color (type: Color)
-Function 242: DrawPolyLines() (5 input parameters)
+Function 246: DrawPolyLines() (5 input parameters)
Name: DrawPolyLines
Return type: void
Description: Draw a polygon outline of n sides
@@ -2388,7 +2416,7 @@ Function 242: DrawPolyLines() (5 input parameters)
Param[3]: radius (type: float)
Param[4]: rotation (type: float)
Param[5]: color (type: Color)
-Function 243: DrawPolyLinesEx() (6 input parameters)
+Function 247: DrawPolyLinesEx() (6 input parameters)
Name: DrawPolyLinesEx
Return type: void
Description: Draw a polygon outline of n sides with extended parameters
@@ -2398,7 +2426,7 @@ Function 243: DrawPolyLinesEx() (6 input parameters)
Param[4]: rotation (type: float)
Param[5]: lineThick (type: float)
Param[6]: color (type: Color)
-Function 244: DrawSplineLinear() (4 input parameters)
+Function 248: DrawSplineLinear() (4 input parameters)
Name: DrawSplineLinear
Return type: void
Description: Draw spline: Linear, minimum 2 points
@@ -2406,7 +2434,7 @@ Function 244: DrawSplineLinear() (4 input parameters)
Param[2]: pointCount (type: int)
Param[3]: thick (type: float)
Param[4]: color (type: Color)
-Function 245: DrawSplineBasis() (4 input parameters)
+Function 249: DrawSplineBasis() (4 input parameters)
Name: DrawSplineBasis
Return type: void
Description: Draw spline: B-Spline, minimum 4 points
@@ -2414,7 +2442,7 @@ Function 245: DrawSplineBasis() (4 input parameters)
Param[2]: pointCount (type: int)
Param[3]: thick (type: float)
Param[4]: color (type: Color)
-Function 246: DrawSplineCatmullRom() (4 input parameters)
+Function 250: DrawSplineCatmullRom() (4 input parameters)
Name: DrawSplineCatmullRom
Return type: void
Description: Draw spline: Catmull-Rom, minimum 4 points
@@ -2422,7 +2450,7 @@ Function 246: DrawSplineCatmullRom() (4 input parameters)
Param[2]: pointCount (type: int)
Param[3]: thick (type: float)
Param[4]: color (type: Color)
-Function 247: DrawSplineBezierQuadratic() (4 input parameters)
+Function 251: DrawSplineBezierQuadratic() (4 input parameters)
Name: DrawSplineBezierQuadratic
Return type: void
Description: Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]
@@ -2430,7 +2458,7 @@ Function 247: DrawSplineBezierQuadratic() (4 input parameters)
Param[2]: pointCount (type: int)
Param[3]: thick (type: float)
Param[4]: color (type: Color)
-Function 248: DrawSplineBezierCubic() (4 input parameters)
+Function 252: DrawSplineBezierCubic() (4 input parameters)
Name: DrawSplineBezierCubic
Return type: void
Description: Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]
@@ -2438,7 +2466,7 @@ Function 248: DrawSplineBezierCubic() (4 input parameters)
Param[2]: pointCount (type: int)
Param[3]: thick (type: float)
Param[4]: color (type: Color)
-Function 249: DrawSplineSegmentLinear() (4 input parameters)
+Function 253: DrawSplineSegmentLinear() (4 input parameters)
Name: DrawSplineSegmentLinear
Return type: void
Description: Draw spline segment: Linear, 2 points
@@ -2446,7 +2474,7 @@ Function 249: DrawSplineSegmentLinear() (4 input parameters)
Param[2]: p2 (type: Vector2)
Param[3]: thick (type: float)
Param[4]: color (type: Color)
-Function 250: DrawSplineSegmentBasis() (6 input parameters)
+Function 254: DrawSplineSegmentBasis() (6 input parameters)
Name: DrawSplineSegmentBasis
Return type: void
Description: Draw spline segment: B-Spline, 4 points
@@ -2456,7 +2484,7 @@ Function 250: DrawSplineSegmentBasis() (6 input parameters)
Param[4]: p4 (type: Vector2)
Param[5]: thick (type: float)
Param[6]: color (type: Color)
-Function 251: DrawSplineSegmentCatmullRom() (6 input parameters)
+Function 255: DrawSplineSegmentCatmullRom() (6 input parameters)
Name: DrawSplineSegmentCatmullRom
Return type: void
Description: Draw spline segment: Catmull-Rom, 4 points
@@ -2466,7 +2494,7 @@ Function 251: DrawSplineSegmentCatmullRom() (6 input parameters)
Param[4]: p4 (type: Vector2)
Param[5]: thick (type: float)
Param[6]: color (type: Color)
-Function 252: DrawSplineSegmentBezierQuadratic() (5 input parameters)
+Function 256: DrawSplineSegmentBezierQuadratic() (5 input parameters)
Name: DrawSplineSegmentBezierQuadratic
Return type: void
Description: Draw spline segment: Quadratic Bezier, 2 points, 1 control point
@@ -2475,7 +2503,7 @@ Function 252: DrawSplineSegmentBezierQuadratic() (5 input parameters)
Param[3]: p3 (type: Vector2)
Param[4]: thick (type: float)
Param[5]: color (type: Color)
-Function 253: DrawSplineSegmentBezierCubic() (6 input parameters)
+Function 257: DrawSplineSegmentBezierCubic() (6 input parameters)
Name: DrawSplineSegmentBezierCubic
Return type: void
Description: Draw spline segment: Cubic Bezier, 2 points, 2 control points
@@ -2485,14 +2513,14 @@ Function 253: DrawSplineSegmentBezierCubic() (6 input parameters)
Param[4]: p4 (type: Vector2)
Param[5]: thick (type: float)
Param[6]: color (type: Color)
-Function 254: GetSplinePointLinear() (3 input parameters)
+Function 258: GetSplinePointLinear() (3 input parameters)
Name: GetSplinePointLinear
Return type: Vector2
Description: Get (evaluate) spline point: Linear
Param[1]: startPos (type: Vector2)
Param[2]: endPos (type: Vector2)
Param[3]: t (type: float)
-Function 255: GetSplinePointBasis() (5 input parameters)
+Function 259: GetSplinePointBasis() (5 input parameters)
Name: GetSplinePointBasis
Return type: Vector2
Description: Get (evaluate) spline point: B-Spline
@@ -2501,7 +2529,7 @@ Function 255: GetSplinePointBasis() (5 input parameters)
Param[3]: p3 (type: Vector2)
Param[4]: p4 (type: Vector2)
Param[5]: t (type: float)
-Function 256: GetSplinePointCatmullRom() (5 input parameters)
+Function 260: GetSplinePointCatmullRom() (5 input parameters)
Name: GetSplinePointCatmullRom
Return type: Vector2
Description: Get (evaluate) spline point: Catmull-Rom
@@ -2510,7 +2538,7 @@ Function 256: GetSplinePointCatmullRom() (5 input parameters)
Param[3]: p3 (type: Vector2)
Param[4]: p4 (type: Vector2)
Param[5]: t (type: float)
-Function 257: GetSplinePointBezierQuad() (4 input parameters)
+Function 261: GetSplinePointBezierQuad() (4 input parameters)
Name: GetSplinePointBezierQuad
Return type: Vector2
Description: Get (evaluate) spline point: Quadratic Bezier
@@ -2518,7 +2546,7 @@ Function 257: GetSplinePointBezierQuad() (4 input parameters)
Param[2]: c2 (type: Vector2)
Param[3]: p3 (type: Vector2)
Param[4]: t (type: float)
-Function 258: GetSplinePointBezierCubic() (5 input parameters)
+Function 262: GetSplinePointBezierCubic() (5 input parameters)
Name: GetSplinePointBezierCubic
Return type: Vector2
Description: Get (evaluate) spline point: Cubic Bezier
@@ -2527,13 +2555,13 @@ Function 258: GetSplinePointBezierCubic() (5 input parameters)
Param[3]: c3 (type: Vector2)
Param[4]: p4 (type: Vector2)
Param[5]: t (type: float)
-Function 259: CheckCollisionRecs() (2 input parameters)
+Function 263: CheckCollisionRecs() (2 input parameters)
Name: CheckCollisionRecs
Return type: bool
Description: Check collision between two rectangles
Param[1]: rec1 (type: Rectangle)
Param[2]: rec2 (type: Rectangle)
-Function 260: CheckCollisionCircles() (4 input parameters)
+Function 264: CheckCollisionCircles() (4 input parameters)
Name: CheckCollisionCircles
Return type: bool
Description: Check collision between two circles
@@ -2541,27 +2569,27 @@ Function 260: CheckCollisionCircles() (4 input parameters)
Param[2]: radius1 (type: float)
Param[3]: center2 (type: Vector2)
Param[4]: radius2 (type: float)
-Function 261: CheckCollisionCircleRec() (3 input parameters)
+Function 265: CheckCollisionCircleRec() (3 input parameters)
Name: CheckCollisionCircleRec
Return type: bool
Description: Check collision between circle and rectangle
Param[1]: center (type: Vector2)
Param[2]: radius (type: float)
Param[3]: rec (type: Rectangle)
-Function 262: CheckCollisionPointRec() (2 input parameters)
+Function 266: CheckCollisionPointRec() (2 input parameters)
Name: CheckCollisionPointRec
Return type: bool
Description: Check if point is inside rectangle
Param[1]: point (type: Vector2)
Param[2]: rec (type: Rectangle)
-Function 263: CheckCollisionPointCircle() (3 input parameters)
+Function 267: CheckCollisionPointCircle() (3 input parameters)
Name: CheckCollisionPointCircle
Return type: bool
Description: Check if point is inside circle
Param[1]: point (type: Vector2)
Param[2]: center (type: Vector2)
Param[3]: radius (type: float)
-Function 264: CheckCollisionPointTriangle() (4 input parameters)
+Function 268: CheckCollisionPointTriangle() (4 input parameters)
Name: CheckCollisionPointTriangle
Return type: bool
Description: Check if point is inside a triangle
@@ -2569,14 +2597,14 @@ Function 264: CheckCollisionPointTriangle() (4 input parameters)
Param[2]: p1 (type: Vector2)
Param[3]: p2 (type: Vector2)
Param[4]: p3 (type: Vector2)
-Function 265: CheckCollisionPointPoly() (3 input parameters)
+Function 269: CheckCollisionPointPoly() (3 input parameters)
Name: CheckCollisionPointPoly
Return type: bool
Description: Check if point is within a polygon described by array of vertices
Param[1]: point (type: Vector2)
Param[2]: points (type: const Vector2 *)
Param[3]: pointCount (type: int)
-Function 266: CheckCollisionLines() (5 input parameters)
+Function 270: CheckCollisionLines() (5 input parameters)
Name: CheckCollisionLines
Return type: bool
Description: Check the collision between two lines defined by two points each, returns collision point by reference
@@ -2585,7 +2613,7 @@ Function 266: CheckCollisionLines() (5 input parameters)
Param[3]: startPos2 (type: Vector2)
Param[4]: endPos2 (type: Vector2)
Param[5]: collisionPoint (type: Vector2 *)
-Function 267: CheckCollisionPointLine() (4 input parameters)
+Function 271: CheckCollisionPointLine() (4 input parameters)
Name: CheckCollisionPointLine
Return type: bool
Description: Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold]
@@ -2593,7 +2621,7 @@ Function 267: CheckCollisionPointLine() (4 input parameters)
Param[2]: p1 (type: Vector2)
Param[3]: p2 (type: Vector2)
Param[4]: threshold (type: int)
-Function 268: CheckCollisionCircleLine() (4 input parameters)
+Function 272: CheckCollisionCircleLine() (4 input parameters)
Name: CheckCollisionCircleLine
Return type: bool
Description: Check if circle collides with a line created betweeen two points [p1] and [p2]
@@ -2601,18 +2629,18 @@ Function 268: CheckCollisionCircleLine() (4 input parameters)
Param[2]: radius (type: float)
Param[3]: p1 (type: Vector2)
Param[4]: p2 (type: Vector2)
-Function 269: GetCollisionRec() (2 input parameters)
+Function 273: GetCollisionRec() (2 input parameters)
Name: GetCollisionRec
Return type: Rectangle
Description: Get collision rectangle for two rectangles collision
Param[1]: rec1 (type: Rectangle)
Param[2]: rec2 (type: Rectangle)
-Function 270: LoadImage() (1 input parameters)
+Function 274: LoadImage() (1 input parameters)
Name: LoadImage
Return type: Image
Description: Load image from file into CPU memory (RAM)
Param[1]: fileName (type: const char *)
-Function 271: LoadImageRaw() (5 input parameters)
+Function 275: LoadImageRaw() (5 input parameters)
Name: LoadImageRaw
Return type: Image
Description: Load image from RAW file data
@@ -2621,20 +2649,13 @@ Function 271: LoadImageRaw() (5 input parameters)
Param[3]: height (type: int)
Param[4]: format (type: int)
Param[5]: headerSize (type: int)
-Function 272: LoadImageSvg() (3 input parameters)
- Name: LoadImageSvg
- Return type: Image
- Description: Load image from SVG file data or string with specified size
- Param[1]: fileNameOrString (type: const char *)
- Param[2]: width (type: int)
- Param[3]: height (type: int)
-Function 273: LoadImageAnim() (2 input parameters)
+Function 276: LoadImageAnim() (2 input parameters)
Name: LoadImageAnim
Return type: Image
Description: Load image sequence from file (frames appended to image.data)
Param[1]: fileName (type: const char *)
Param[2]: frames (type: int *)
-Function 274: LoadImageAnimFromMemory() (4 input parameters)
+Function 277: LoadImageAnimFromMemory() (4 input parameters)
Name: LoadImageAnimFromMemory
Return type: Image
Description: Load image sequence from memory buffer
@@ -2642,60 +2663,60 @@ Function 274: LoadImageAnimFromMemory() (4 input parameters)
Param[2]: fileData (type: const unsigned char *)
Param[3]: dataSize (type: int)
Param[4]: frames (type: int *)
-Function 275: LoadImageFromMemory() (3 input parameters)
+Function 278: LoadImageFromMemory() (3 input parameters)
Name: LoadImageFromMemory
Return type: Image
Description: Load image from memory buffer, fileType refers to extension: i.e. '.png'
Param[1]: fileType (type: const char *)
Param[2]: fileData (type: const unsigned char *)
Param[3]: dataSize (type: int)
-Function 276: LoadImageFromTexture() (1 input parameters)
+Function 279: LoadImageFromTexture() (1 input parameters)
Name: LoadImageFromTexture
Return type: Image
Description: Load image from GPU texture data
Param[1]: texture (type: Texture2D)
-Function 277: LoadImageFromScreen() (0 input parameters)
+Function 280: LoadImageFromScreen() (0 input parameters)
Name: LoadImageFromScreen
Return type: Image
Description: Load image from screen buffer and (screenshot)
No input parameters
-Function 278: IsImageReady() (1 input parameters)
- Name: IsImageReady
+Function 281: IsImageValid() (1 input parameters)
+ Name: IsImageValid
Return type: bool
- Description: Check if an image is ready
+ Description: Check if an image is valid (data and parameters)
Param[1]: image (type: Image)
-Function 279: UnloadImage() (1 input parameters)
+Function 282: UnloadImage() (1 input parameters)
Name: UnloadImage
Return type: void
Description: Unload image from CPU memory (RAM)
Param[1]: image (type: Image)
-Function 280: ExportImage() (2 input parameters)
+Function 283: ExportImage() (2 input parameters)
Name: ExportImage
Return type: bool
Description: Export image data to file, returns true on success
Param[1]: image (type: Image)
Param[2]: fileName (type: const char *)
-Function 281: ExportImageToMemory() (3 input parameters)
+Function 284: ExportImageToMemory() (3 input parameters)
Name: ExportImageToMemory
Return type: unsigned char *
Description: Export image to memory buffer
Param[1]: image (type: Image)
Param[2]: fileType (type: const char *)
Param[3]: fileSize (type: int *)
-Function 282: ExportImageAsCode() (2 input parameters)
+Function 285: ExportImageAsCode() (2 input parameters)
Name: ExportImageAsCode
Return type: bool
Description: Export image as code file defining an array of bytes, returns true on success
Param[1]: image (type: Image)
Param[2]: fileName (type: const char *)
-Function 283: GenImageColor() (3 input parameters)
+Function 286: GenImageColor() (3 input parameters)
Name: GenImageColor
Return type: Image
Description: Generate image: plain color
Param[1]: width (type: int)
Param[2]: height (type: int)
Param[3]: color (type: Color)
-Function 284: GenImageGradientLinear() (5 input parameters)
+Function 287: GenImageGradientLinear() (5 input parameters)
Name: GenImageGradientLinear
Return type: Image
Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient
@@ -2704,7 +2725,7 @@ Function 284: GenImageGradientLinear() (5 input parameters)
Param[3]: direction (type: int)
Param[4]: start (type: Color)
Param[5]: end (type: Color)
-Function 285: GenImageGradientRadial() (5 input parameters)
+Function 288: GenImageGradientRadial() (5 input parameters)
Name: GenImageGradientRadial
Return type: Image
Description: Generate image: radial gradient
@@ -2713,7 +2734,7 @@ Function 285: GenImageGradientRadial() (5 input parameters)
Param[3]: density (type: float)
Param[4]: inner (type: Color)
Param[5]: outer (type: Color)
-Function 286: GenImageGradientSquare() (5 input parameters)
+Function 289: GenImageGradientSquare() (5 input parameters)
Name: GenImageGradientSquare
Return type: Image
Description: Generate image: square gradient
@@ -2722,7 +2743,7 @@ Function 286: GenImageGradientSquare() (5 input parameters)
Param[3]: density (type: float)
Param[4]: inner (type: Color)
Param[5]: outer (type: Color)
-Function 287: GenImageChecked() (6 input parameters)
+Function 290: GenImageChecked() (6 input parameters)
Name: GenImageChecked
Return type: Image
Description: Generate image: checked
@@ -2732,14 +2753,14 @@ Function 287: GenImageChecked() (6 input parameters)
Param[4]: checksY (type: int)
Param[5]: col1 (type: Color)
Param[6]: col2 (type: Color)
-Function 288: GenImageWhiteNoise() (3 input parameters)
+Function 291: GenImageWhiteNoise() (3 input parameters)
Name: GenImageWhiteNoise
Return type: Image
Description: Generate image: white noise
Param[1]: width (type: int)
Param[2]: height (type: int)
Param[3]: factor (type: float)
-Function 289: GenImagePerlinNoise() (5 input parameters)
+Function 292: GenImagePerlinNoise() (5 input parameters)
Name: GenImagePerlinNoise
Return type: Image
Description: Generate image: perlin noise
@@ -2748,45 +2769,45 @@ Function 289: GenImagePerlinNoise() (5 input parameters)
Param[3]: offsetX (type: int)
Param[4]: offsetY (type: int)
Param[5]: scale (type: float)
-Function 290: GenImageCellular() (3 input parameters)
+Function 293: GenImageCellular() (3 input parameters)
Name: GenImageCellular
Return type: Image
Description: Generate image: cellular algorithm, bigger tileSize means bigger cells
Param[1]: width (type: int)
Param[2]: height (type: int)
Param[3]: tileSize (type: int)
-Function 291: GenImageText() (3 input parameters)
+Function 294: GenImageText() (3 input parameters)
Name: GenImageText
Return type: Image
Description: Generate image: grayscale image from text data
Param[1]: width (type: int)
Param[2]: height (type: int)
Param[3]: text (type: const char *)
-Function 292: ImageCopy() (1 input parameters)
+Function 295: ImageCopy() (1 input parameters)
Name: ImageCopy
Return type: Image
Description: Create an image duplicate (useful for transformations)
Param[1]: image (type: Image)
-Function 293: ImageFromImage() (2 input parameters)
+Function 296: ImageFromImage() (2 input parameters)
Name: ImageFromImage
Return type: Image
Description: Create an image from another image piece
Param[1]: image (type: Image)
Param[2]: rec (type: Rectangle)
-Function 294: ImageFromChannel() (2 input parameters)
+Function 297: ImageFromChannel() (2 input parameters)
Name: ImageFromChannel
Return type: Image
Description: Create an image from a selected channel of another image (GRAYSCALE)
Param[1]: image (type: Image)
Param[2]: selectedChannel (type: int)
-Function 295: ImageText() (3 input parameters)
+Function 298: ImageText() (3 input parameters)
Name: ImageText
Return type: Image
Description: Create an image from text (default font)
Param[1]: text (type: const char *)
Param[2]: fontSize (type: int)
Param[3]: color (type: Color)
-Function 296: ImageTextEx() (5 input parameters)
+Function 299: ImageTextEx() (5 input parameters)
Name: ImageTextEx
Return type: Image
Description: Create an image from text (custom sprite font)
@@ -2795,76 +2816,76 @@ Function 296: ImageTextEx() (5 input parameters)
Param[3]: fontSize (type: float)
Param[4]: spacing (type: float)
Param[5]: tint (type: Color)
-Function 297: ImageFormat() (2 input parameters)
+Function 300: ImageFormat() (2 input parameters)
Name: ImageFormat
Return type: void
Description: Convert image data to desired format
Param[1]: image (type: Image *)
Param[2]: newFormat (type: int)
-Function 298: ImageToPOT() (2 input parameters)
+Function 301: ImageToPOT() (2 input parameters)
Name: ImageToPOT
Return type: void
Description: Convert image to POT (power-of-two)
Param[1]: image (type: Image *)
Param[2]: fill (type: Color)
-Function 299: ImageCrop() (2 input parameters)
+Function 302: ImageCrop() (2 input parameters)
Name: ImageCrop
Return type: void
Description: Crop an image to a defined rectangle
Param[1]: image (type: Image *)
Param[2]: crop (type: Rectangle)
-Function 300: ImageAlphaCrop() (2 input parameters)
+Function 303: ImageAlphaCrop() (2 input parameters)
Name: ImageAlphaCrop
Return type: void
Description: Crop image depending on alpha value
Param[1]: image (type: Image *)
Param[2]: threshold (type: float)
-Function 301: ImageAlphaClear() (3 input parameters)
+Function 304: ImageAlphaClear() (3 input parameters)
Name: ImageAlphaClear
Return type: void
Description: Clear alpha channel to desired color
Param[1]: image (type: Image *)
Param[2]: color (type: Color)
Param[3]: threshold (type: float)
-Function 302: ImageAlphaMask() (2 input parameters)
+Function 305: ImageAlphaMask() (2 input parameters)
Name: ImageAlphaMask
Return type: void
Description: Apply alpha mask to image
Param[1]: image (type: Image *)
Param[2]: alphaMask (type: Image)
-Function 303: ImageAlphaPremultiply() (1 input parameters)
+Function 306: ImageAlphaPremultiply() (1 input parameters)
Name: ImageAlphaPremultiply
Return type: void
Description: Premultiply alpha channel
Param[1]: image (type: Image *)
-Function 304: ImageBlurGaussian() (2 input parameters)
+Function 307: ImageBlurGaussian() (2 input parameters)
Name: ImageBlurGaussian
Return type: void
Description: Apply Gaussian blur using a box blur approximation
Param[1]: image (type: Image *)
Param[2]: blurSize (type: int)
-Function 305: ImageKernelConvolution() (3 input parameters)
+Function 308: ImageKernelConvolution() (3 input parameters)
Name: ImageKernelConvolution
Return type: void
Description: Apply custom square convolution kernel to image
Param[1]: image (type: Image *)
Param[2]: kernel (type: const float *)
Param[3]: kernelSize (type: int)
-Function 306: ImageResize() (3 input parameters)
+Function 309: ImageResize() (3 input parameters)
Name: ImageResize
Return type: void
Description: Resize image (Bicubic scaling algorithm)
Param[1]: image (type: Image *)
Param[2]: newWidth (type: int)
Param[3]: newHeight (type: int)
-Function 307: ImageResizeNN() (3 input parameters)
+Function 310: ImageResizeNN() (3 input parameters)
Name: ImageResizeNN
Return type: void
Description: Resize image (Nearest-Neighbor scaling algorithm)
Param[1]: image (type: Image *)
Param[2]: newWidth (type: int)
Param[3]: newHeight (type: int)
-Function 308: ImageResizeCanvas() (6 input parameters)
+Function 311: ImageResizeCanvas() (6 input parameters)
Name: ImageResizeCanvas
Return type: void
Description: Resize canvas and fill with color
@@ -2874,12 +2895,12 @@ Function 308: ImageResizeCanvas() (6 input parameters)
Param[4]: offsetX (type: int)
Param[5]: offsetY (type: int)
Param[6]: fill (type: Color)
-Function 309: ImageMipmaps() (1 input parameters)
+Function 312: ImageMipmaps() (1 input parameters)
Name: ImageMipmaps
Return type: void
Description: Compute all mipmap levels for a provided image
Param[1]: image (type: Image *)
-Function 310: ImageDither() (5 input parameters)
+Function 313: ImageDither() (5 input parameters)
Name: ImageDither
Return type: void
Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
@@ -2888,109 +2909,109 @@ Function 310: ImageDither() (5 input parameters)
Param[3]: gBpp (type: int)
Param[4]: bBpp (type: int)
Param[5]: aBpp (type: int)
-Function 311: ImageFlipVertical() (1 input parameters)
+Function 314: ImageFlipVertical() (1 input parameters)
Name: ImageFlipVertical
Return type: void
Description: Flip image vertically
Param[1]: image (type: Image *)
-Function 312: ImageFlipHorizontal() (1 input parameters)
+Function 315: ImageFlipHorizontal() (1 input parameters)
Name: ImageFlipHorizontal
Return type: void
Description: Flip image horizontally
Param[1]: image (type: Image *)
-Function 313: ImageRotate() (2 input parameters)
+Function 316: ImageRotate() (2 input parameters)
Name: ImageRotate
Return type: void
Description: Rotate image by input angle in degrees (-359 to 359)
Param[1]: image (type: Image *)
Param[2]: degrees (type: int)
-Function 314: ImageRotateCW() (1 input parameters)
+Function 317: ImageRotateCW() (1 input parameters)
Name: ImageRotateCW
Return type: void
Description: Rotate image clockwise 90deg
Param[1]: image (type: Image *)
-Function 315: ImageRotateCCW() (1 input parameters)
+Function 318: ImageRotateCCW() (1 input parameters)
Name: ImageRotateCCW
Return type: void
Description: Rotate image counter-clockwise 90deg
Param[1]: image (type: Image *)
-Function 316: ImageColorTint() (2 input parameters)
+Function 319: ImageColorTint() (2 input parameters)
Name: ImageColorTint
Return type: void
Description: Modify image color: tint
Param[1]: image (type: Image *)
Param[2]: color (type: Color)
-Function 317: ImageColorInvert() (1 input parameters)
+Function 320: ImageColorInvert() (1 input parameters)
Name: ImageColorInvert
Return type: void
Description: Modify image color: invert
Param[1]: image (type: Image *)
-Function 318: ImageColorGrayscale() (1 input parameters)
+Function 321: ImageColorGrayscale() (1 input parameters)
Name: ImageColorGrayscale
Return type: void
Description: Modify image color: grayscale
Param[1]: image (type: Image *)
-Function 319: ImageColorContrast() (2 input parameters)
+Function 322: ImageColorContrast() (2 input parameters)
Name: ImageColorContrast
Return type: void
Description: Modify image color: contrast (-100 to 100)
Param[1]: image (type: Image *)
Param[2]: contrast (type: float)
-Function 320: ImageColorBrightness() (2 input parameters)
+Function 323: ImageColorBrightness() (2 input parameters)
Name: ImageColorBrightness
Return type: void
Description: Modify image color: brightness (-255 to 255)
Param[1]: image (type: Image *)
Param[2]: brightness (type: int)
-Function 321: ImageColorReplace() (3 input parameters)
+Function 324: ImageColorReplace() (3 input parameters)
Name: ImageColorReplace
Return type: void
Description: Modify image color: replace color
Param[1]: image (type: Image *)
Param[2]: color (type: Color)
Param[3]: replace (type: Color)
-Function 322: LoadImageColors() (1 input parameters)
+Function 325: LoadImageColors() (1 input parameters)
Name: LoadImageColors
Return type: Color *
Description: Load color data from image as a Color array (RGBA - 32bit)
Param[1]: image (type: Image)
-Function 323: LoadImagePalette() (3 input parameters)
+Function 326: LoadImagePalette() (3 input parameters)
Name: LoadImagePalette
Return type: Color *
Description: Load colors palette from image as a Color array (RGBA - 32bit)
Param[1]: image (type: Image)
Param[2]: maxPaletteSize (type: int)
Param[3]: colorCount (type: int *)
-Function 324: UnloadImageColors() (1 input parameters)
+Function 327: UnloadImageColors() (1 input parameters)
Name: UnloadImageColors
Return type: void
Description: Unload color data loaded with LoadImageColors()
Param[1]: colors (type: Color *)
-Function 325: UnloadImagePalette() (1 input parameters)
+Function 328: UnloadImagePalette() (1 input parameters)
Name: UnloadImagePalette
Return type: void
Description: Unload colors palette loaded with LoadImagePalette()
Param[1]: colors (type: Color *)
-Function 326: GetImageAlphaBorder() (2 input parameters)
+Function 329: GetImageAlphaBorder() (2 input parameters)
Name: GetImageAlphaBorder
Return type: Rectangle
Description: Get image alpha border rectangle
Param[1]: image (type: Image)
Param[2]: threshold (type: float)
-Function 327: GetImageColor() (3 input parameters)
+Function 330: GetImageColor() (3 input parameters)
Name: GetImageColor
Return type: Color
Description: Get image pixel color at (x, y) position
Param[1]: image (type: Image)
Param[2]: x (type: int)
Param[3]: y (type: int)
-Function 328: ImageClearBackground() (2 input parameters)
+Function 331: ImageClearBackground() (2 input parameters)
Name: ImageClearBackground
Return type: void
Description: Clear image background with given color
Param[1]: dst (type: Image *)
Param[2]: color (type: Color)
-Function 329: ImageDrawPixel() (4 input parameters)
+Function 332: ImageDrawPixel() (4 input parameters)
Name: ImageDrawPixel
Return type: void
Description: Draw pixel within an image
@@ -2998,14 +3019,14 @@ Function 329: ImageDrawPixel() (4 input parameters)
Param[2]: posX (type: int)
Param[3]: posY (type: int)
Param[4]: color (type: Color)
-Function 330: ImageDrawPixelV() (3 input parameters)
+Function 333: ImageDrawPixelV() (3 input parameters)
Name: ImageDrawPixelV
Return type: void
Description: Draw pixel within an image (Vector version)
Param[1]: dst (type: Image *)
Param[2]: position (type: Vector2)
Param[3]: color (type: Color)
-Function 331: ImageDrawLine() (6 input parameters)
+Function 334: ImageDrawLine() (6 input parameters)
Name: ImageDrawLine
Return type: void
Description: Draw line within an image
@@ -3015,7 +3036,7 @@ Function 331: ImageDrawLine() (6 input parameters)
Param[4]: endPosX (type: int)
Param[5]: endPosY (type: int)
Param[6]: color (type: Color)
-Function 332: ImageDrawLineV() (4 input parameters)
+Function 335: ImageDrawLineV() (4 input parameters)
Name: ImageDrawLineV
Return type: void
Description: Draw line within an image (Vector version)
@@ -3023,7 +3044,7 @@ Function 332: ImageDrawLineV() (4 input parameters)
Param[2]: start (type: Vector2)
Param[3]: end (type: Vector2)
Param[4]: color (type: Color)
-Function 333: ImageDrawLineEx() (5 input parameters)
+Function 336: ImageDrawLineEx() (5 input parameters)
Name: ImageDrawLineEx
Return type: void
Description: Draw a line defining thickness within an image
@@ -3032,7 +3053,7 @@ Function 333: ImageDrawLineEx() (5 input parameters)
Param[3]: end (type: Vector2)
Param[4]: thick (type: int)
Param[5]: color (type: Color)
-Function 334: ImageDrawCircle() (5 input parameters)
+Function 337: ImageDrawCircle() (5 input parameters)
Name: ImageDrawCircle
Return type: void
Description: Draw a filled circle within an image
@@ -3041,7 +3062,7 @@ Function 334: ImageDrawCircle() (5 input parameters)
Param[3]: centerY (type: int)
Param[4]: radius (type: int)
Param[5]: color (type: Color)
-Function 335: ImageDrawCircleV() (4 input parameters)
+Function 338: ImageDrawCircleV() (4 input parameters)
Name: ImageDrawCircleV
Return type: void
Description: Draw a filled circle within an image (Vector version)
@@ -3049,7 +3070,7 @@ Function 335: ImageDrawCircleV() (4 input parameters)
Param[2]: center (type: Vector2)
Param[3]: radius (type: int)
Param[4]: color (type: Color)
-Function 336: ImageDrawCircleLines() (5 input parameters)
+Function 339: ImageDrawCircleLines() (5 input parameters)
Name: ImageDrawCircleLines
Return type: void
Description: Draw circle outline within an image
@@ -3058,7 +3079,7 @@ Function 336: ImageDrawCircleLines() (5 input parameters)
Param[3]: centerY (type: int)
Param[4]: radius (type: int)
Param[5]: color (type: Color)
-Function 337: ImageDrawCircleLinesV() (4 input parameters)
+Function 340: ImageDrawCircleLinesV() (4 input parameters)
Name: ImageDrawCircleLinesV
Return type: void
Description: Draw circle outline within an image (Vector version)
@@ -3066,7 +3087,7 @@ Function 337: ImageDrawCircleLinesV() (4 input parameters)
Param[2]: center (type: Vector2)
Param[3]: radius (type: int)
Param[4]: color (type: Color)
-Function 338: ImageDrawRectangle() (6 input parameters)
+Function 341: ImageDrawRectangle() (6 input parameters)
Name: ImageDrawRectangle
Return type: void
Description: Draw rectangle within an image
@@ -3076,7 +3097,7 @@ Function 338: ImageDrawRectangle() (6 input parameters)
Param[4]: width (type: int)
Param[5]: height (type: int)
Param[6]: color (type: Color)
-Function 339: ImageDrawRectangleV() (4 input parameters)
+Function 342: ImageDrawRectangleV() (4 input parameters)
Name: ImageDrawRectangleV
Return type: void
Description: Draw rectangle within an image (Vector version)
@@ -3084,14 +3105,14 @@ Function 339: ImageDrawRectangleV() (4 input parameters)
Param[2]: position (type: Vector2)
Param[3]: size (type: Vector2)
Param[4]: color (type: Color)
-Function 340: ImageDrawRectangleRec() (3 input parameters)
+Function 343: ImageDrawRectangleRec() (3 input parameters)
Name: ImageDrawRectangleRec
Return type: void
Description: Draw rectangle within an image
Param[1]: dst (type: Image *)
Param[2]: rec (type: Rectangle)
Param[3]: color (type: Color)
-Function 341: ImageDrawRectangleLines() (4 input parameters)
+Function 344: ImageDrawRectangleLines() (4 input parameters)
Name: ImageDrawRectangleLines
Return type: void
Description: Draw rectangle lines within an image
@@ -3099,7 +3120,7 @@ Function 341: ImageDrawRectangleLines() (4 input parameters)
Param[2]: rec (type: Rectangle)
Param[3]: thick (type: int)
Param[4]: color (type: Color)
-Function 342: ImageDrawTriangle() (5 input parameters)
+Function 345: ImageDrawTriangle() (5 input parameters)
Name: ImageDrawTriangle
Return type: void
Description: Draw triangle within an image
@@ -3108,7 +3129,7 @@ Function 342: ImageDrawTriangle() (5 input parameters)
Param[3]: v2 (type: Vector2)
Param[4]: v3 (type: Vector2)
Param[5]: color (type: Color)
-Function 343: ImageDrawTriangleEx() (7 input parameters)
+Function 346: ImageDrawTriangleEx() (7 input parameters)
Name: ImageDrawTriangleEx
Return type: void
Description: Draw triangle with interpolated colors within an image
@@ -3119,7 +3140,7 @@ Function 343: ImageDrawTriangleEx() (7 input parameters)
Param[5]: c1 (type: Color)
Param[6]: c2 (type: Color)
Param[7]: c3 (type: Color)
-Function 344: ImageDrawTriangleLines() (5 input parameters)
+Function 347: ImageDrawTriangleLines() (5 input parameters)
Name: ImageDrawTriangleLines
Return type: void
Description: Draw triangle outline within an image
@@ -3128,7 +3149,7 @@ Function 344: ImageDrawTriangleLines() (5 input parameters)
Param[3]: v2 (type: Vector2)
Param[4]: v3 (type: Vector2)
Param[5]: color (type: Color)
-Function 345: ImageDrawTriangleFan() (4 input parameters)
+Function 348: ImageDrawTriangleFan() (4 input parameters)
Name: ImageDrawTriangleFan
Return type: void
Description: Draw a triangle fan defined by points within an image (first vertex is the center)
@@ -3136,7 +3157,7 @@ Function 345: ImageDrawTriangleFan() (4 input parameters)
Param[2]: points (type: Vector2 *)
Param[3]: pointCount (type: int)
Param[4]: color (type: Color)
-Function 346: ImageDrawTriangleStrip() (4 input parameters)
+Function 349: ImageDrawTriangleStrip() (4 input parameters)
Name: ImageDrawTriangleStrip
Return type: void
Description: Draw a triangle strip defined by points within an image
@@ -3144,7 +3165,7 @@ Function 346: ImageDrawTriangleStrip() (4 input parameters)
Param[2]: points (type: Vector2 *)
Param[3]: pointCount (type: int)
Param[4]: color (type: Color)
-Function 347: ImageDraw() (5 input parameters)
+Function 350: ImageDraw() (5 input parameters)
Name: ImageDraw
Return type: void
Description: Draw a source image within a destination image (tint applied to source)
@@ -3153,7 +3174,7 @@ Function 347: ImageDraw() (5 input parameters)
Param[3]: srcRec (type: Rectangle)
Param[4]: dstRec (type: Rectangle)
Param[5]: tint (type: Color)
-Function 348: ImageDrawText() (6 input parameters)
+Function 351: ImageDrawText() (6 input parameters)
Name: ImageDrawText
Return type: void
Description: Draw text (using default font) within an image (destination)
@@ -3163,7 +3184,7 @@ Function 348: ImageDrawText() (6 input parameters)
Param[4]: posY (type: int)
Param[5]: fontSize (type: int)
Param[6]: color (type: Color)
-Function 349: ImageDrawTextEx() (7 input parameters)
+Function 352: ImageDrawTextEx() (7 input parameters)
Name: ImageDrawTextEx
Return type: void
Description: Draw text (custom sprite font) within an image (destination)
@@ -3174,79 +3195,79 @@ Function 349: ImageDrawTextEx() (7 input parameters)
Param[5]: fontSize (type: float)
Param[6]: spacing (type: float)
Param[7]: tint (type: Color)
-Function 350: LoadTexture() (1 input parameters)
+Function 353: LoadTexture() (1 input parameters)
Name: LoadTexture
Return type: Texture2D
Description: Load texture from file into GPU memory (VRAM)
Param[1]: fileName (type: const char *)
-Function 351: LoadTextureFromImage() (1 input parameters)
+Function 354: LoadTextureFromImage() (1 input parameters)
Name: LoadTextureFromImage
Return type: Texture2D
Description: Load texture from image data
Param[1]: image (type: Image)
-Function 352: LoadTextureCubemap() (2 input parameters)
+Function 355: LoadTextureCubemap() (2 input parameters)
Name: LoadTextureCubemap
Return type: TextureCubemap
Description: Load cubemap from image, multiple image cubemap layouts supported
Param[1]: image (type: Image)
Param[2]: layout (type: int)
-Function 353: LoadRenderTexture() (2 input parameters)
+Function 356: LoadRenderTexture() (2 input parameters)
Name: LoadRenderTexture
Return type: RenderTexture2D
Description: Load texture for rendering (framebuffer)
Param[1]: width (type: int)
Param[2]: height (type: int)
-Function 354: IsTextureReady() (1 input parameters)
- Name: IsTextureReady
+Function 357: IsTextureValid() (1 input parameters)
+ Name: IsTextureValid
Return type: bool
- Description: Check if a texture is ready
+ Description: Check if a texture is valid (loaded in GPU)
Param[1]: texture (type: Texture2D)
-Function 355: UnloadTexture() (1 input parameters)
+Function 358: UnloadTexture() (1 input parameters)
Name: UnloadTexture
Return type: void
Description: Unload texture from GPU memory (VRAM)
Param[1]: texture (type: Texture2D)
-Function 356: IsRenderTextureReady() (1 input parameters)
- Name: IsRenderTextureReady
+Function 359: IsRenderTextureValid() (1 input parameters)
+ Name: IsRenderTextureValid
Return type: bool
- Description: Check if a render texture is ready
+ Description: Check if a render texture is valid (loaded in GPU)
Param[1]: target (type: RenderTexture2D)
-Function 357: UnloadRenderTexture() (1 input parameters)
+Function 360: UnloadRenderTexture() (1 input parameters)
Name: UnloadRenderTexture
Return type: void
Description: Unload render texture from GPU memory (VRAM)
Param[1]: target (type: RenderTexture2D)
-Function 358: UpdateTexture() (2 input parameters)
+Function 361: UpdateTexture() (2 input parameters)
Name: UpdateTexture
Return type: void
Description: Update GPU texture with new data
Param[1]: texture (type: Texture2D)
Param[2]: pixels (type: const void *)
-Function 359: UpdateTextureRec() (3 input parameters)
+Function 362: UpdateTextureRec() (3 input parameters)
Name: UpdateTextureRec
Return type: void
Description: Update GPU texture rectangle with new data
Param[1]: texture (type: Texture2D)
Param[2]: rec (type: Rectangle)
Param[3]: pixels (type: const void *)
-Function 360: GenTextureMipmaps() (1 input parameters)
+Function 363: GenTextureMipmaps() (1 input parameters)
Name: GenTextureMipmaps
Return type: void
Description: Generate GPU mipmaps for a texture
Param[1]: texture (type: Texture2D *)
-Function 361: SetTextureFilter() (2 input parameters)
+Function 364: SetTextureFilter() (2 input parameters)
Name: SetTextureFilter
Return type: void
Description: Set texture scaling filter mode
Param[1]: texture (type: Texture2D)
Param[2]: filter (type: int)
-Function 362: SetTextureWrap() (2 input parameters)
+Function 365: SetTextureWrap() (2 input parameters)
Name: SetTextureWrap
Return type: void
Description: Set texture wrapping mode
Param[1]: texture (type: Texture2D)
Param[2]: wrap (type: int)
-Function 363: DrawTexture() (4 input parameters)
+Function 366: DrawTexture() (4 input parameters)
Name: DrawTexture
Return type: void
Description: Draw a Texture2D
@@ -3254,14 +3275,14 @@ Function 363: DrawTexture() (4 input parameters)
Param[2]: posX (type: int)
Param[3]: posY (type: int)
Param[4]: tint (type: Color)
-Function 364: DrawTextureV() (3 input parameters)
+Function 367: DrawTextureV() (3 input parameters)
Name: DrawTextureV
Return type: void
Description: Draw a Texture2D with position defined as Vector2
Param[1]: texture (type: Texture2D)
Param[2]: position (type: Vector2)
Param[3]: tint (type: Color)
-Function 365: DrawTextureEx() (5 input parameters)
+Function 368: DrawTextureEx() (5 input parameters)
Name: DrawTextureEx
Return type: void
Description: Draw a Texture2D with extended parameters
@@ -3270,7 +3291,7 @@ Function 365: DrawTextureEx() (5 input parameters)
Param[3]: rotation (type: float)
Param[4]: scale (type: float)
Param[5]: tint (type: Color)
-Function 366: DrawTextureRec() (4 input parameters)
+Function 369: DrawTextureRec() (4 input parameters)
Name: DrawTextureRec
Return type: void
Description: Draw a part of a texture defined by a rectangle
@@ -3278,7 +3299,7 @@ Function 366: DrawTextureRec() (4 input parameters)
Param[2]: source (type: Rectangle)
Param[3]: position (type: Vector2)
Param[4]: tint (type: Color)
-Function 367: DrawTexturePro() (6 input parameters)
+Function 370: DrawTexturePro() (6 input parameters)
Name: DrawTexturePro
Return type: void
Description: Draw a part of a texture defined by a rectangle with 'pro' parameters
@@ -3288,7 +3309,7 @@ Function 367: DrawTexturePro() (6 input parameters)
Param[4]: origin (type: Vector2)
Param[5]: rotation (type: float)
Param[6]: tint (type: Color)
-Function 368: DrawTextureNPatch() (6 input parameters)
+Function 371: DrawTextureNPatch() (6 input parameters)
Name: DrawTextureNPatch
Return type: void
Description: Draws a texture (or part of it) that stretches or shrinks nicely
@@ -3298,127 +3319,134 @@ Function 368: DrawTextureNPatch() (6 input parameters)
Param[4]: origin (type: Vector2)
Param[5]: rotation (type: float)
Param[6]: tint (type: Color)
-Function 369: ColorIsEqual() (2 input parameters)
+Function 372: ColorIsEqual() (2 input parameters)
Name: ColorIsEqual
Return type: bool
Description: Check if two colors are equal
Param[1]: col1 (type: Color)
Param[2]: col2 (type: Color)
-Function 370: Fade() (2 input parameters)
+Function 373: Fade() (2 input parameters)
Name: Fade
Return type: Color
Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f
Param[1]: color (type: Color)
Param[2]: alpha (type: float)
-Function 371: ColorToInt() (1 input parameters)
+Function 374: ColorToInt() (1 input parameters)
Name: ColorToInt
Return type: int
Description: Get hexadecimal value for a Color (0xRRGGBBAA)
Param[1]: color (type: Color)
-Function 372: ColorNormalize() (1 input parameters)
+Function 375: ColorNormalize() (1 input parameters)
Name: ColorNormalize
Return type: Vector4
Description: Get Color normalized as float [0..1]
Param[1]: color (type: Color)
-Function 373: ColorFromNormalized() (1 input parameters)
+Function 376: ColorFromNormalized() (1 input parameters)
Name: ColorFromNormalized
Return type: Color
Description: Get Color from normalized values [0..1]
Param[1]: normalized (type: Vector4)
-Function 374: ColorToHSV() (1 input parameters)
+Function 377: ColorToHSV() (1 input parameters)
Name: ColorToHSV
Return type: Vector3
Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1]
Param[1]: color (type: Color)
-Function 375: ColorFromHSV() (3 input parameters)
+Function 378: ColorFromHSV() (3 input parameters)
Name: ColorFromHSV
Return type: Color
Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1]
Param[1]: hue (type: float)
Param[2]: saturation (type: float)
Param[3]: value (type: float)
-Function 376: ColorTint() (2 input parameters)
+Function 379: ColorTint() (2 input parameters)
Name: ColorTint
Return type: Color
Description: Get color multiplied with another color
Param[1]: color (type: Color)
Param[2]: tint (type: Color)
-Function 377: ColorBrightness() (2 input parameters)
+Function 380: ColorBrightness() (2 input parameters)
Name: ColorBrightness
Return type: Color
Description: Get color with brightness correction, brightness factor goes from -1.0f to 1.0f
Param[1]: color (type: Color)
Param[2]: factor (type: float)
-Function 378: ColorContrast() (2 input parameters)
+Function 381: ColorContrast() (2 input parameters)
Name: ColorContrast
Return type: Color
Description: Get color with contrast correction, contrast values between -1.0f and 1.0f
Param[1]: color (type: Color)
Param[2]: contrast (type: float)
-Function 379: ColorAlpha() (2 input parameters)
+Function 382: ColorAlpha() (2 input parameters)
Name: ColorAlpha
Return type: Color
Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f
Param[1]: color (type: Color)
Param[2]: alpha (type: float)
-Function 380: ColorAlphaBlend() (3 input parameters)
+Function 383: ColorAlphaBlend() (3 input parameters)
Name: ColorAlphaBlend
Return type: Color
Description: Get src alpha-blended into dst color with tint
Param[1]: dst (type: Color)
Param[2]: src (type: Color)
Param[3]: tint (type: Color)
-Function 381: GetColor() (1 input parameters)
+Function 384: ColorLerp() (3 input parameters)
+ Name: ColorLerp
+ Return type: Color
+ Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f]
+ Param[1]: color1 (type: Color)
+ Param[2]: color2 (type: Color)
+ Param[3]: factor (type: float)
+Function 385: GetColor() (1 input parameters)
Name: GetColor
Return type: Color
Description: Get Color structure from hexadecimal value
Param[1]: hexValue (type: unsigned int)
-Function 382: GetPixelColor() (2 input parameters)
+Function 386: GetPixelColor() (2 input parameters)
Name: GetPixelColor
Return type: Color
Description: Get Color from a source pixel pointer of certain format
Param[1]: srcPtr (type: void *)
Param[2]: format (type: int)
-Function 383: SetPixelColor() (3 input parameters)
+Function 387: SetPixelColor() (3 input parameters)
Name: SetPixelColor
Return type: void
Description: Set color formatted into destination pixel pointer
Param[1]: dstPtr (type: void *)
Param[2]: color (type: Color)
Param[3]: format (type: int)
-Function 384: GetPixelDataSize() (3 input parameters)
+Function 388: GetPixelDataSize() (3 input parameters)
Name: GetPixelDataSize
Return type: int
Description: Get pixel data size in bytes for certain format
Param[1]: width (type: int)
Param[2]: height (type: int)
Param[3]: format (type: int)
-Function 385: GetFontDefault() (0 input parameters)
+Function 389: GetFontDefault() (0 input parameters)
Name: GetFontDefault
Return type: Font
Description: Get the default Font
No input parameters
-Function 386: LoadFont() (1 input parameters)
+Function 390: LoadFont() (1 input parameters)
Name: LoadFont
Return type: Font
Description: Load font from file into GPU memory (VRAM)
Param[1]: fileName (type: const char *)
-Function 387: LoadFontEx() (4 input parameters)
+Function 391: LoadFontEx() (4 input parameters)
Name: LoadFontEx
Return type: Font
- Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character setFont
+ Description: Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height
Param[1]: fileName (type: const char *)
Param[2]: fontSize (type: int)
Param[3]: codepoints (type: int *)
Param[4]: codepointCount (type: int)
-Function 388: LoadFontFromImage() (3 input parameters)
+Function 392: LoadFontFromImage() (3 input parameters)
Name: LoadFontFromImage
Return type: Font
Description: Load font from Image (XNA style)
Param[1]: image (type: Image)
Param[2]: key (type: Color)
Param[3]: firstChar (type: int)
-Function 389: LoadFontFromMemory() (6 input parameters)
+Function 393: LoadFontFromMemory() (6 input parameters)
Name: LoadFontFromMemory
Return type: Font
Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
@@ -3428,12 +3456,12 @@ Function 389: LoadFontFromMemory() (6 input parameters)
Param[4]: fontSize (type: int)
Param[5]: codepoints (type: int *)
Param[6]: codepointCount (type: int)
-Function 390: IsFontReady() (1 input parameters)
- Name: IsFontReady
+Function 394: IsFontValid() (1 input parameters)
+ Name: IsFontValid
Return type: bool
- Description: Check if a font is ready
+ Description: Check if a font is valid (font data loaded, WARNING: GPU texture not checked)
Param[1]: font (type: Font)
-Function 391: LoadFontData() (6 input parameters)
+Function 395: LoadFontData() (6 input parameters)
Name: LoadFontData
Return type: GlyphInfo *
Description: Load font data for further use
@@ -3443,7 +3471,7 @@ Function 391: LoadFontData() (6 input parameters)
Param[4]: codepoints (type: int *)
Param[5]: codepointCount (type: int)
Param[6]: type (type: int)
-Function 392: GenImageFontAtlas() (6 input parameters)
+Function 396: GenImageFontAtlas() (6 input parameters)
Name: GenImageFontAtlas
Return type: Image
Description: Generate image font atlas using chars info
@@ -3453,30 +3481,30 @@ Function 392: GenImageFontAtlas() (6 input parameters)
Param[4]: fontSize (type: int)
Param[5]: padding (type: int)
Param[6]: packMethod (type: int)
-Function 393: UnloadFontData() (2 input parameters)
+Function 397: UnloadFontData() (2 input parameters)
Name: UnloadFontData
Return type: void
Description: Unload font chars info data (RAM)
Param[1]: glyphs (type: GlyphInfo *)
Param[2]: glyphCount (type: int)
-Function 394: UnloadFont() (1 input parameters)
+Function 398: UnloadFont() (1 input parameters)
Name: UnloadFont
Return type: void
Description: Unload font from GPU memory (VRAM)
Param[1]: font (type: Font)
-Function 395: ExportFontAsCode() (2 input parameters)
+Function 399: ExportFontAsCode() (2 input parameters)
Name: ExportFontAsCode
Return type: bool
Description: Export font as code file, returns true on success
Param[1]: font (type: Font)
Param[2]: fileName (type: const char *)
-Function 396: DrawFPS() (2 input parameters)
+Function 400: DrawFPS() (2 input parameters)
Name: DrawFPS
Return type: void
Description: Draw current FPS
Param[1]: posX (type: int)
Param[2]: posY (type: int)
-Function 397: DrawText() (5 input parameters)
+Function 401: DrawText() (5 input parameters)
Name: DrawText
Return type: void
Description: Draw text (using default font)
@@ -3485,7 +3513,7 @@ Function 397: DrawText() (5 input parameters)
Param[3]: posY (type: int)
Param[4]: fontSize (type: int)
Param[5]: color (type: Color)
-Function 398: DrawTextEx() (6 input parameters)
+Function 402: DrawTextEx() (6 input parameters)
Name: DrawTextEx
Return type: void
Description: Draw text using font and additional parameters
@@ -3495,7 +3523,7 @@ Function 398: DrawTextEx() (6 input parameters)
Param[4]: fontSize (type: float)
Param[5]: spacing (type: float)
Param[6]: tint (type: Color)
-Function 399: DrawTextPro() (8 input parameters)
+Function 403: DrawTextPro() (8 input parameters)
Name: DrawTextPro
Return type: void
Description: Draw text using Font and pro parameters (rotation)
@@ -3507,7 +3535,7 @@ Function 399: DrawTextPro() (8 input parameters)
Param[6]: fontSize (type: float)
Param[7]: spacing (type: float)
Param[8]: tint (type: Color)
-Function 400: DrawTextCodepoint() (5 input parameters)
+Function 404: DrawTextCodepoint() (5 input parameters)
Name: DrawTextCodepoint
Return type: void
Description: Draw one character (codepoint)
@@ -3516,7 +3544,7 @@ Function 400: DrawTextCodepoint() (5 input parameters)
Param[3]: position (type: Vector2)
Param[4]: fontSize (type: float)
Param[5]: tint (type: Color)
-Function 401: DrawTextCodepoints() (7 input parameters)
+Function 405: DrawTextCodepoints() (7 input parameters)
Name: DrawTextCodepoints
Return type: void
Description: Draw multiple character (codepoint)
@@ -3527,18 +3555,18 @@ Function 401: DrawTextCodepoints() (7 input parameters)
Param[5]: fontSize (type: float)
Param[6]: spacing (type: float)
Param[7]: tint (type: Color)
-Function 402: SetTextLineSpacing() (1 input parameters)
+Function 406: SetTextLineSpacing() (1 input parameters)
Name: SetTextLineSpacing
Return type: void
Description: Set vertical line spacing when drawing with line-breaks
Param[1]: spacing (type: int)
-Function 403: MeasureText() (2 input parameters)
+Function 407: MeasureText() (2 input parameters)
Name: MeasureText
Return type: int
Description: Measure string width for default font
Param[1]: text (type: const char *)
Param[2]: fontSize (type: int)
-Function 404: MeasureTextEx() (4 input parameters)
+Function 408: MeasureTextEx() (4 input parameters)
Name: MeasureTextEx
Return type: Vector2
Description: Measure string size for Font
@@ -3546,195 +3574,195 @@ Function 404: MeasureTextEx() (4 input parameters)
Param[2]: text (type: const char *)
Param[3]: fontSize (type: float)
Param[4]: spacing (type: float)
-Function 405: GetGlyphIndex() (2 input parameters)
+Function 409: GetGlyphIndex() (2 input parameters)
Name: GetGlyphIndex
Return type: int
Description: Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found
Param[1]: font (type: Font)
Param[2]: codepoint (type: int)
-Function 406: GetGlyphInfo() (2 input parameters)
+Function 410: GetGlyphInfo() (2 input parameters)
Name: GetGlyphInfo
Return type: GlyphInfo
Description: Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found
Param[1]: font (type: Font)
Param[2]: codepoint (type: int)
-Function 407: GetGlyphAtlasRec() (2 input parameters)
+Function 411: GetGlyphAtlasRec() (2 input parameters)
Name: GetGlyphAtlasRec
Return type: Rectangle
Description: Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found
Param[1]: font (type: Font)
Param[2]: codepoint (type: int)
-Function 408: LoadUTF8() (2 input parameters)
+Function 412: LoadUTF8() (2 input parameters)
Name: LoadUTF8
Return type: char *
Description: Load UTF-8 text encoded from codepoints array
Param[1]: codepoints (type: const int *)
Param[2]: length (type: int)
-Function 409: UnloadUTF8() (1 input parameters)
+Function 413: UnloadUTF8() (1 input parameters)
Name: UnloadUTF8
Return type: void
Description: Unload UTF-8 text encoded from codepoints array
Param[1]: text (type: char *)
-Function 410: LoadCodepoints() (2 input parameters)
+Function 414: LoadCodepoints() (2 input parameters)
Name: LoadCodepoints
Return type: int *
Description: Load all codepoints from a UTF-8 text string, codepoints count returned by parameter
Param[1]: text (type: const char *)
Param[2]: count (type: int *)
-Function 411: UnloadCodepoints() (1 input parameters)
+Function 415: UnloadCodepoints() (1 input parameters)
Name: UnloadCodepoints
Return type: void
Description: Unload codepoints data from memory
Param[1]: codepoints (type: int *)
-Function 412: GetCodepointCount() (1 input parameters)
+Function 416: GetCodepointCount() (1 input parameters)
Name: GetCodepointCount
Return type: int
Description: Get total number of codepoints in a UTF-8 encoded string
Param[1]: text (type: const char *)
-Function 413: GetCodepoint() (2 input parameters)
+Function 417: GetCodepoint() (2 input parameters)
Name: GetCodepoint
Return type: int
Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
Param[1]: text (type: const char *)
Param[2]: codepointSize (type: int *)
-Function 414: GetCodepointNext() (2 input parameters)
+Function 418: GetCodepointNext() (2 input parameters)
Name: GetCodepointNext
Return type: int
Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
Param[1]: text (type: const char *)
Param[2]: codepointSize (type: int *)
-Function 415: GetCodepointPrevious() (2 input parameters)
+Function 419: GetCodepointPrevious() (2 input parameters)
Name: GetCodepointPrevious
Return type: int
Description: Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
Param[1]: text (type: const char *)
Param[2]: codepointSize (type: int *)
-Function 416: CodepointToUTF8() (2 input parameters)
+Function 420: CodepointToUTF8() (2 input parameters)
Name: CodepointToUTF8
Return type: const char *
Description: Encode one codepoint into UTF-8 byte array (array length returned as parameter)
Param[1]: codepoint (type: int)
Param[2]: utf8Size (type: int *)
-Function 417: TextCopy() (2 input parameters)
+Function 421: TextCopy() (2 input parameters)
Name: TextCopy
Return type: int
Description: Copy one string to another, returns bytes copied
Param[1]: dst (type: char *)
Param[2]: src (type: const char *)
-Function 418: TextIsEqual() (2 input parameters)
+Function 422: TextIsEqual() (2 input parameters)
Name: TextIsEqual
Return type: bool
Description: Check if two text string are equal
Param[1]: text1 (type: const char *)
Param[2]: text2 (type: const char *)
-Function 419: TextLength() (1 input parameters)
+Function 423: TextLength() (1 input parameters)
Name: TextLength
Return type: unsigned int
Description: Get text length, checks for '\0' ending
Param[1]: text (type: const char *)
-Function 420: TextFormat() (2 input parameters)
+Function 424: TextFormat() (2 input parameters)
Name: TextFormat
Return type: const char *
Description: Text formatting with variables (sprintf() style)
Param[1]: text (type: const char *)
Param[2]: args (type: ...)
-Function 421: TextSubtext() (3 input parameters)
+Function 425: TextSubtext() (3 input parameters)
Name: TextSubtext
Return type: const char *
Description: Get a piece of a text string
Param[1]: text (type: const char *)
Param[2]: position (type: int)
Param[3]: length (type: int)
-Function 422: TextReplace() (3 input parameters)
+Function 426: TextReplace() (3 input parameters)
Name: TextReplace
Return type: char *
Description: Replace text string (WARNING: memory must be freed!)
Param[1]: text (type: const char *)
Param[2]: replace (type: const char *)
Param[3]: by (type: const char *)
-Function 423: TextInsert() (3 input parameters)
+Function 427: TextInsert() (3 input parameters)
Name: TextInsert
Return type: char *
Description: Insert text in a position (WARNING: memory must be freed!)
Param[1]: text (type: const char *)
Param[2]: insert (type: const char *)
Param[3]: position (type: int)
-Function 424: TextJoin() (3 input parameters)
+Function 428: TextJoin() (3 input parameters)
Name: TextJoin
Return type: const char *
Description: Join text strings with delimiter
Param[1]: textList (type: const char **)
Param[2]: count (type: int)
Param[3]: delimiter (type: const char *)
-Function 425: TextSplit() (3 input parameters)
+Function 429: TextSplit() (3 input parameters)
Name: TextSplit
Return type: const char **
Description: Split text into multiple strings
Param[1]: text (type: const char *)
Param[2]: delimiter (type: char)
Param[3]: count (type: int *)
-Function 426: TextAppend() (3 input parameters)
+Function 430: TextAppend() (3 input parameters)
Name: TextAppend
Return type: void
Description: Append text at specific position and move cursor!
Param[1]: text (type: char *)
Param[2]: append (type: const char *)
Param[3]: position (type: int *)
-Function 427: TextFindIndex() (2 input parameters)
+Function 431: TextFindIndex() (2 input parameters)
Name: TextFindIndex
Return type: int
Description: Find first text occurrence within a string
Param[1]: text (type: const char *)
Param[2]: find (type: const char *)
-Function 428: TextToUpper() (1 input parameters)
+Function 432: TextToUpper() (1 input parameters)
Name: TextToUpper
Return type: const char *
Description: Get upper case version of provided string
Param[1]: text (type: const char *)
-Function 429: TextToLower() (1 input parameters)
+Function 433: TextToLower() (1 input parameters)
Name: TextToLower
Return type: const char *
Description: Get lower case version of provided string
Param[1]: text (type: const char *)
-Function 430: TextToPascal() (1 input parameters)
+Function 434: TextToPascal() (1 input parameters)
Name: TextToPascal
Return type: const char *
Description: Get Pascal case notation version of provided string
Param[1]: text (type: const char *)
-Function 431: TextToSnake() (1 input parameters)
+Function 435: TextToSnake() (1 input parameters)
Name: TextToSnake
Return type: const char *
Description: Get Snake case notation version of provided string
Param[1]: text (type: const char *)
-Function 432: TextToCamel() (1 input parameters)
+Function 436: TextToCamel() (1 input parameters)
Name: TextToCamel
Return type: const char *
Description: Get Camel case notation version of provided string
Param[1]: text (type: const char *)
-Function 433: TextToInteger() (1 input parameters)
+Function 437: TextToInteger() (1 input parameters)
Name: TextToInteger
Return type: int
Description: Get integer value from text (negative values not supported)
Param[1]: text (type: const char *)
-Function 434: TextToFloat() (1 input parameters)
+Function 438: TextToFloat() (1 input parameters)
Name: TextToFloat
Return type: float
Description: Get float value from text (negative values not supported)
Param[1]: text (type: const char *)
-Function 435: DrawLine3D() (3 input parameters)
+Function 439: DrawLine3D() (3 input parameters)
Name: DrawLine3D
Return type: void
Description: Draw a line in 3D world space
Param[1]: startPos (type: Vector3)
Param[2]: endPos (type: Vector3)
Param[3]: color (type: Color)
-Function 436: DrawPoint3D() (2 input parameters)
+Function 440: DrawPoint3D() (2 input parameters)
Name: DrawPoint3D
Return type: void
Description: Draw a point in 3D space, actually a small line
Param[1]: position (type: Vector3)
Param[2]: color (type: Color)
-Function 437: DrawCircle3D() (5 input parameters)
+Function 441: DrawCircle3D() (5 input parameters)
Name: DrawCircle3D
Return type: void
Description: Draw a circle in 3D world space
@@ -3743,7 +3771,7 @@ Function 437: DrawCircle3D() (5 input parameters)
Param[3]: rotationAxis (type: Vector3)
Param[4]: rotationAngle (type: float)
Param[5]: color (type: Color)
-Function 438: DrawTriangle3D() (4 input parameters)
+Function 442: DrawTriangle3D() (4 input parameters)
Name: DrawTriangle3D
Return type: void
Description: Draw a color-filled triangle (vertex in counter-clockwise order!)
@@ -3751,14 +3779,14 @@ Function 438: DrawTriangle3D() (4 input parameters)
Param[2]: v2 (type: Vector3)
Param[3]: v3 (type: Vector3)
Param[4]: color (type: Color)
-Function 439: DrawTriangleStrip3D() (3 input parameters)
+Function 443: DrawTriangleStrip3D() (3 input parameters)
Name: DrawTriangleStrip3D
Return type: void
Description: Draw a triangle strip defined by points
Param[1]: points (type: const Vector3 *)
Param[2]: pointCount (type: int)
Param[3]: color (type: Color)
-Function 440: DrawCube() (5 input parameters)
+Function 444: DrawCube() (5 input parameters)
Name: DrawCube
Return type: void
Description: Draw cube
@@ -3767,14 +3795,14 @@ Function 440: DrawCube() (5 input parameters)
Param[3]: height (type: float)
Param[4]: length (type: float)
Param[5]: color (type: Color)
-Function 441: DrawCubeV() (3 input parameters)
+Function 445: DrawCubeV() (3 input parameters)
Name: DrawCubeV
Return type: void
Description: Draw cube (Vector version)
Param[1]: position (type: Vector3)
Param[2]: size (type: Vector3)
Param[3]: color (type: Color)
-Function 442: DrawCubeWires() (5 input parameters)
+Function 446: DrawCubeWires() (5 input parameters)
Name: DrawCubeWires
Return type: void
Description: Draw cube wires
@@ -3783,21 +3811,21 @@ Function 442: DrawCubeWires() (5 input parameters)
Param[3]: height (type: float)
Param[4]: length (type: float)
Param[5]: color (type: Color)
-Function 443: DrawCubeWiresV() (3 input parameters)
+Function 447: DrawCubeWiresV() (3 input parameters)
Name: DrawCubeWiresV
Return type: void
Description: Draw cube wires (Vector version)
Param[1]: position (type: Vector3)
Param[2]: size (type: Vector3)
Param[3]: color (type: Color)
-Function 444: DrawSphere() (3 input parameters)
+Function 448: DrawSphere() (3 input parameters)
Name: DrawSphere
Return type: void
Description: Draw sphere
Param[1]: centerPos (type: Vector3)
Param[2]: radius (type: float)
Param[3]: color (type: Color)
-Function 445: DrawSphereEx() (5 input parameters)
+Function 449: DrawSphereEx() (5 input parameters)
Name: DrawSphereEx
Return type: void
Description: Draw sphere with extended parameters
@@ -3806,7 +3834,7 @@ Function 445: DrawSphereEx() (5 input parameters)
Param[3]: rings (type: int)
Param[4]: slices (type: int)
Param[5]: color (type: Color)
-Function 446: DrawSphereWires() (5 input parameters)
+Function 450: DrawSphereWires() (5 input parameters)
Name: DrawSphereWires
Return type: void
Description: Draw sphere wires
@@ -3815,7 +3843,7 @@ Function 446: DrawSphereWires() (5 input parameters)
Param[3]: rings (type: int)
Param[4]: slices (type: int)
Param[5]: color (type: Color)
-Function 447: DrawCylinder() (6 input parameters)
+Function 451: DrawCylinder() (6 input parameters)
Name: DrawCylinder
Return type: void
Description: Draw a cylinder/cone
@@ -3825,7 +3853,7 @@ Function 447: DrawCylinder() (6 input parameters)
Param[4]: height (type: float)
Param[5]: slices (type: int)
Param[6]: color (type: Color)
-Function 448: DrawCylinderEx() (6 input parameters)
+Function 452: DrawCylinderEx() (6 input parameters)
Name: DrawCylinderEx
Return type: void
Description: Draw a cylinder with base at startPos and top at endPos
@@ -3835,7 +3863,7 @@ Function 448: DrawCylinderEx() (6 input parameters)
Param[4]: endRadius (type: float)
Param[5]: sides (type: int)
Param[6]: color (type: Color)
-Function 449: DrawCylinderWires() (6 input parameters)
+Function 453: DrawCylinderWires() (6 input parameters)
Name: DrawCylinderWires
Return type: void
Description: Draw a cylinder/cone wires
@@ -3845,7 +3873,7 @@ Function 449: DrawCylinderWires() (6 input parameters)
Param[4]: height (type: float)
Param[5]: slices (type: int)
Param[6]: color (type: Color)
-Function 450: DrawCylinderWiresEx() (6 input parameters)
+Function 454: DrawCylinderWiresEx() (6 input parameters)
Name: DrawCylinderWiresEx
Return type: void
Description: Draw a cylinder wires with base at startPos and top at endPos
@@ -3855,7 +3883,7 @@ Function 450: DrawCylinderWiresEx() (6 input parameters)
Param[4]: endRadius (type: float)
Param[5]: sides (type: int)
Param[6]: color (type: Color)
-Function 451: DrawCapsule() (6 input parameters)
+Function 455: DrawCapsule() (6 input parameters)
Name: DrawCapsule
Return type: void
Description: Draw a capsule with the center of its sphere caps at startPos and endPos
@@ -3865,7 +3893,7 @@ Function 451: DrawCapsule() (6 input parameters)
Param[4]: slices (type: int)
Param[5]: rings (type: int)
Param[6]: color (type: Color)
-Function 452: DrawCapsuleWires() (6 input parameters)
+Function 456: DrawCapsuleWires() (6 input parameters)
Name: DrawCapsuleWires
Return type: void
Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos
@@ -3875,51 +3903,51 @@ Function 452: DrawCapsuleWires() (6 input parameters)
Param[4]: slices (type: int)
Param[5]: rings (type: int)
Param[6]: color (type: Color)
-Function 453: DrawPlane() (3 input parameters)
+Function 457: DrawPlane() (3 input parameters)
Name: DrawPlane
Return type: void
Description: Draw a plane XZ
Param[1]: centerPos (type: Vector3)
Param[2]: size (type: Vector2)
Param[3]: color (type: Color)
-Function 454: DrawRay() (2 input parameters)
+Function 458: DrawRay() (2 input parameters)
Name: DrawRay
Return type: void
Description: Draw a ray line
Param[1]: ray (type: Ray)
Param[2]: color (type: Color)
-Function 455: DrawGrid() (2 input parameters)
+Function 459: DrawGrid() (2 input parameters)
Name: DrawGrid
Return type: void
Description: Draw a grid (centered at (0, 0, 0))
Param[1]: slices (type: int)
Param[2]: spacing (type: float)
-Function 456: LoadModel() (1 input parameters)
+Function 460: LoadModel() (1 input parameters)
Name: LoadModel
Return type: Model
Description: Load model from files (meshes and materials)
Param[1]: fileName (type: const char *)
-Function 457: LoadModelFromMesh() (1 input parameters)
+Function 461: LoadModelFromMesh() (1 input parameters)
Name: LoadModelFromMesh
Return type: Model
Description: Load model from generated mesh (default material)
Param[1]: mesh (type: Mesh)
-Function 458: IsModelReady() (1 input parameters)
- Name: IsModelReady
+Function 462: IsModelValid() (1 input parameters)
+ Name: IsModelValid
Return type: bool
- Description: Check if a model is ready
+ Description: Check if a model is valid (loaded in GPU, VAO/VBOs)
Param[1]: model (type: Model)
-Function 459: UnloadModel() (1 input parameters)
+Function 463: UnloadModel() (1 input parameters)
Name: UnloadModel
Return type: void
Description: Unload model (including meshes) from memory (RAM and/or VRAM)
Param[1]: model (type: Model)
-Function 460: GetModelBoundingBox() (1 input parameters)
+Function 464: GetModelBoundingBox() (1 input parameters)
Name: GetModelBoundingBox
Return type: BoundingBox
Description: Compute model bounding box limits (considers all meshes)
Param[1]: model (type: Model)
-Function 461: DrawModel() (4 input parameters)
+Function 465: DrawModel() (4 input parameters)
Name: DrawModel
Return type: void
Description: Draw a model (with texture if set)
@@ -3927,7 +3955,7 @@ Function 461: DrawModel() (4 input parameters)
Param[2]: position (type: Vector3)
Param[3]: scale (type: float)
Param[4]: tint (type: Color)
-Function 462: DrawModelEx() (6 input parameters)
+Function 466: DrawModelEx() (6 input parameters)
Name: DrawModelEx
Return type: void
Description: Draw a model with extended parameters
@@ -3937,7 +3965,7 @@ Function 462: DrawModelEx() (6 input parameters)
Param[4]: rotationAngle (type: float)
Param[5]: scale (type: Vector3)
Param[6]: tint (type: Color)
-Function 463: DrawModelWires() (4 input parameters)
+Function 467: DrawModelWires() (4 input parameters)
Name: DrawModelWires
Return type: void
Description: Draw a model wires (with texture if set)
@@ -3945,7 +3973,7 @@ Function 463: DrawModelWires() (4 input parameters)
Param[2]: position (type: Vector3)
Param[3]: scale (type: float)
Param[4]: tint (type: Color)
-Function 464: DrawModelWiresEx() (6 input parameters)
+Function 468: DrawModelWiresEx() (6 input parameters)
Name: DrawModelWiresEx
Return type: void
Description: Draw a model wires (with texture if set) with extended parameters
@@ -3955,13 +3983,31 @@ Function 464: DrawModelWiresEx() (6 input parameters)
Param[4]: rotationAngle (type: float)
Param[5]: scale (type: Vector3)
Param[6]: tint (type: Color)
-Function 465: DrawBoundingBox() (2 input parameters)
+Function 469: DrawModelPoints() (4 input parameters)
+ Name: DrawModelPoints
+ Return type: void
+ Description: Draw a model as points
+ Param[1]: model (type: Model)
+ Param[2]: position (type: Vector3)
+ Param[3]: scale (type: float)
+ Param[4]: tint (type: Color)
+Function 470: DrawModelPointsEx() (6 input parameters)
+ Name: DrawModelPointsEx
+ Return type: void
+ Description: Draw a model as points with extended parameters
+ Param[1]: model (type: Model)
+ Param[2]: position (type: Vector3)
+ Param[3]: rotationAxis (type: Vector3)
+ Param[4]: rotationAngle (type: float)
+ Param[5]: scale (type: Vector3)
+ Param[6]: tint (type: Color)
+Function 471: DrawBoundingBox() (2 input parameters)
Name: DrawBoundingBox
Return type: void
Description: Draw bounding box (wires)
Param[1]: box (type: BoundingBox)
Param[2]: color (type: Color)
-Function 466: DrawBillboard() (5 input parameters)
+Function 472: DrawBillboard() (5 input parameters)
Name: DrawBillboard
Return type: void
Description: Draw a billboard texture
@@ -3970,7 +4016,7 @@ Function 466: DrawBillboard() (5 input parameters)
Param[3]: position (type: Vector3)
Param[4]: scale (type: float)
Param[5]: tint (type: Color)
-Function 467: DrawBillboardRec() (6 input parameters)
+Function 473: DrawBillboardRec() (6 input parameters)
Name: DrawBillboardRec
Return type: void
Description: Draw a billboard texture defined by source
@@ -3980,7 +4026,7 @@ Function 467: DrawBillboardRec() (6 input parameters)
Param[4]: position (type: Vector3)
Param[5]: size (type: Vector2)
Param[6]: tint (type: Color)
-Function 468: DrawBillboardPro() (9 input parameters)
+Function 474: DrawBillboardPro() (9 input parameters)
Name: DrawBillboardPro
Return type: void
Description: Draw a billboard texture defined by source and rotation
@@ -3993,13 +4039,13 @@ Function 468: DrawBillboardPro() (9 input parameters)
Param[7]: origin (type: Vector2)
Param[8]: rotation (type: float)
Param[9]: tint (type: Color)
-Function 469: UploadMesh() (2 input parameters)
+Function 475: UploadMesh() (2 input parameters)
Name: UploadMesh
Return type: void
Description: Upload mesh vertex data in GPU and provide VAO/VBO ids
Param[1]: mesh (type: Mesh *)
Param[2]: dynamic (type: bool)
-Function 470: UpdateMeshBuffer() (5 input parameters)
+Function 476: UpdateMeshBuffer() (5 input parameters)
Name: UpdateMeshBuffer
Return type: void
Description: Update mesh vertex data in GPU for a specific buffer index
@@ -4008,19 +4054,19 @@ Function 470: UpdateMeshBuffer() (5 input parameters)
Param[3]: data (type: const void *)
Param[4]: dataSize (type: int)
Param[5]: offset (type: int)
-Function 471: UnloadMesh() (1 input parameters)
+Function 477: UnloadMesh() (1 input parameters)
Name: UnloadMesh
Return type: void
Description: Unload mesh data from CPU and GPU
Param[1]: mesh (type: Mesh)
-Function 472: DrawMesh() (3 input parameters)
+Function 478: DrawMesh() (3 input parameters)
Name: DrawMesh
Return type: void
Description: Draw a 3d mesh with material and transform
Param[1]: mesh (type: Mesh)
Param[2]: material (type: Material)
Param[3]: transform (type: Matrix)
-Function 473: DrawMeshInstanced() (4 input parameters)
+Function 479: DrawMeshInstanced() (4 input parameters)
Name: DrawMeshInstanced
Return type: void
Description: Draw multiple mesh instances with material and different transforms
@@ -4028,35 +4074,35 @@ Function 473: DrawMeshInstanced() (4 input parameters)
Param[2]: material (type: Material)
Param[3]: transforms (type: const Matrix *)
Param[4]: instances (type: int)
-Function 474: GetMeshBoundingBox() (1 input parameters)
+Function 480: GetMeshBoundingBox() (1 input parameters)
Name: GetMeshBoundingBox
Return type: BoundingBox
Description: Compute mesh bounding box limits
Param[1]: mesh (type: Mesh)
-Function 475: GenMeshTangents() (1 input parameters)
+Function 481: GenMeshTangents() (1 input parameters)
Name: GenMeshTangents
Return type: void
Description: Compute mesh tangents
Param[1]: mesh (type: Mesh *)
-Function 476: ExportMesh() (2 input parameters)
+Function 482: ExportMesh() (2 input parameters)
Name: ExportMesh
Return type: bool
Description: Export mesh data to file, returns true on success
Param[1]: mesh (type: Mesh)
Param[2]: fileName (type: const char *)
-Function 477: ExportMeshAsCode() (2 input parameters)
+Function 483: ExportMeshAsCode() (2 input parameters)
Name: ExportMeshAsCode
Return type: bool
Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes
Param[1]: mesh (type: Mesh)
Param[2]: fileName (type: const char *)
-Function 478: GenMeshPoly() (2 input parameters)
+Function 484: GenMeshPoly() (2 input parameters)
Name: GenMeshPoly
Return type: Mesh
Description: Generate polygonal mesh
Param[1]: sides (type: int)
Param[2]: radius (type: float)
-Function 479: GenMeshPlane() (4 input parameters)
+Function 485: GenMeshPlane() (4 input parameters)
Name: GenMeshPlane
Return type: Mesh
Description: Generate plane mesh (with subdivisions)
@@ -4064,42 +4110,42 @@ Function 479: GenMeshPlane() (4 input parameters)
Param[2]: length (type: float)
Param[3]: resX (type: int)
Param[4]: resZ (type: int)
-Function 480: GenMeshCube() (3 input parameters)
+Function 486: GenMeshCube() (3 input parameters)
Name: GenMeshCube
Return type: Mesh
Description: Generate cuboid mesh
Param[1]: width (type: float)
Param[2]: height (type: float)
Param[3]: length (type: float)
-Function 481: GenMeshSphere() (3 input parameters)
+Function 487: GenMeshSphere() (3 input parameters)
Name: GenMeshSphere
Return type: Mesh
Description: Generate sphere mesh (standard sphere)
Param[1]: radius (type: float)
Param[2]: rings (type: int)
Param[3]: slices (type: int)
-Function 482: GenMeshHemiSphere() (3 input parameters)
+Function 488: GenMeshHemiSphere() (3 input parameters)
Name: GenMeshHemiSphere
Return type: Mesh
Description: Generate half-sphere mesh (no bottom cap)
Param[1]: radius (type: float)
Param[2]: rings (type: int)
Param[3]: slices (type: int)
-Function 483: GenMeshCylinder() (3 input parameters)
+Function 489: GenMeshCylinder() (3 input parameters)
Name: GenMeshCylinder
Return type: Mesh
Description: Generate cylinder mesh
Param[1]: radius (type: float)
Param[2]: height (type: float)
Param[3]: slices (type: int)
-Function 484: GenMeshCone() (3 input parameters)
+Function 490: GenMeshCone() (3 input parameters)
Name: GenMeshCone
Return type: Mesh
Description: Generate cone/pyramid mesh
Param[1]: radius (type: float)
Param[2]: height (type: float)
Param[3]: slices (type: int)
-Function 485: GenMeshTorus() (4 input parameters)
+Function 491: GenMeshTorus() (4 input parameters)
Name: GenMeshTorus
Return type: Mesh
Description: Generate torus mesh
@@ -4107,7 +4153,7 @@ Function 485: GenMeshTorus() (4 input parameters)
Param[2]: size (type: float)
Param[3]: radSeg (type: int)
Param[4]: sides (type: int)
-Function 486: GenMeshKnot() (4 input parameters)
+Function 492: GenMeshKnot() (4 input parameters)
Name: GenMeshKnot
Return type: Mesh
Description: Generate trefoil knot mesh
@@ -4115,84 +4161,91 @@ Function 486: GenMeshKnot() (4 input parameters)
Param[2]: size (type: float)
Param[3]: radSeg (type: int)
Param[4]: sides (type: int)
-Function 487: GenMeshHeightmap() (2 input parameters)
+Function 493: GenMeshHeightmap() (2 input parameters)
Name: GenMeshHeightmap
Return type: Mesh
Description: Generate heightmap mesh from image data
Param[1]: heightmap (type: Image)
Param[2]: size (type: Vector3)
-Function 488: GenMeshCubicmap() (2 input parameters)
+Function 494: GenMeshCubicmap() (2 input parameters)
Name: GenMeshCubicmap
Return type: Mesh
Description: Generate cubes-based map mesh from image data
Param[1]: cubicmap (type: Image)
Param[2]: cubeSize (type: Vector3)
-Function 489: LoadMaterials() (2 input parameters)
+Function 495: LoadMaterials() (2 input parameters)
Name: LoadMaterials
Return type: Material *
Description: Load materials from model file
Param[1]: fileName (type: const char *)
Param[2]: materialCount (type: int *)
-Function 490: LoadMaterialDefault() (0 input parameters)
+Function 496: LoadMaterialDefault() (0 input parameters)
Name: LoadMaterialDefault
Return type: Material
Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
No input parameters
-Function 491: IsMaterialReady() (1 input parameters)
- Name: IsMaterialReady
+Function 497: IsMaterialValid() (1 input parameters)
+ Name: IsMaterialValid
Return type: bool
- Description: Check if a material is ready
+ Description: Check if a material is valid (shader assigned, map textures loaded in GPU)
Param[1]: material (type: Material)
-Function 492: UnloadMaterial() (1 input parameters)
+Function 498: UnloadMaterial() (1 input parameters)
Name: UnloadMaterial
Return type: void
Description: Unload material from GPU memory (VRAM)
Param[1]: material (type: Material)
-Function 493: SetMaterialTexture() (3 input parameters)
+Function 499: SetMaterialTexture() (3 input parameters)
Name: SetMaterialTexture
Return type: void
Description: Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
Param[1]: material (type: Material *)
Param[2]: mapType (type: int)
Param[3]: texture (type: Texture2D)
-Function 494: SetModelMeshMaterial() (3 input parameters)
+Function 500: SetModelMeshMaterial() (3 input parameters)
Name: SetModelMeshMaterial
Return type: void
Description: Set material for a mesh
Param[1]: model (type: Model *)
Param[2]: meshId (type: int)
Param[3]: materialId (type: int)
-Function 495: LoadModelAnimations() (2 input parameters)
+Function 501: LoadModelAnimations() (2 input parameters)
Name: LoadModelAnimations
Return type: ModelAnimation *
Description: Load model animations from file
Param[1]: fileName (type: const char *)
Param[2]: animCount (type: int *)
-Function 496: UpdateModelAnimation() (3 input parameters)
+Function 502: UpdateModelAnimation() (3 input parameters)
Name: UpdateModelAnimation
Return type: void
Description: Update model animation pose
Param[1]: model (type: Model)
Param[2]: anim (type: ModelAnimation)
Param[3]: frame (type: int)
-Function 497: UnloadModelAnimation() (1 input parameters)
+Function 503: UnloadModelAnimation() (1 input parameters)
Name: UnloadModelAnimation
Return type: void
Description: Unload animation data
Param[1]: anim (type: ModelAnimation)
-Function 498: UnloadModelAnimations() (2 input parameters)
+Function 504: UnloadModelAnimations() (2 input parameters)
Name: UnloadModelAnimations
Return type: void
Description: Unload animation array data
Param[1]: animations (type: ModelAnimation *)
Param[2]: animCount (type: int)
-Function 499: IsModelAnimationValid() (2 input parameters)
+Function 505: IsModelAnimationValid() (2 input parameters)
Name: IsModelAnimationValid
Return type: bool
Description: Check model animation skeleton match
Param[1]: model (type: Model)
Param[2]: anim (type: ModelAnimation)
-Function 500: CheckCollisionSpheres() (4 input parameters)
+Function 506: UpdateModelAnimationBoneMatrices() (3 input parameters)
+ Name: UpdateModelAnimationBoneMatrices
+ Return type: void
+ Description: Update model animation mesh bone matrices (Note GPU skinning does not work on Mac)
+ Param[1]: model (type: Model)
+ Param[2]: anim (type: ModelAnimation)
+ Param[3]: frame (type: int)
+Function 507: CheckCollisionSpheres() (4 input parameters)
Name: CheckCollisionSpheres
Return type: bool
Description: Check collision between two spheres
@@ -4200,40 +4253,40 @@ Function 500: CheckCollisionSpheres() (4 input parameters)
Param[2]: radius1 (type: float)
Param[3]: center2 (type: Vector3)
Param[4]: radius2 (type: float)
-Function 501: CheckCollisionBoxes() (2 input parameters)
+Function 508: CheckCollisionBoxes() (2 input parameters)
Name: CheckCollisionBoxes
Return type: bool
Description: Check collision between two bounding boxes
Param[1]: box1 (type: BoundingBox)
Param[2]: box2 (type: BoundingBox)
-Function 502: CheckCollisionBoxSphere() (3 input parameters)
+Function 509: CheckCollisionBoxSphere() (3 input parameters)
Name: CheckCollisionBoxSphere
Return type: bool
Description: Check collision between box and sphere
Param[1]: box (type: BoundingBox)
Param[2]: center (type: Vector3)
Param[3]: radius (type: float)
-Function 503: GetRayCollisionSphere() (3 input parameters)
+Function 510: GetRayCollisionSphere() (3 input parameters)
Name: GetRayCollisionSphere
Return type: RayCollision
Description: Get collision info between ray and sphere
Param[1]: ray (type: Ray)
Param[2]: center (type: Vector3)
Param[3]: radius (type: float)
-Function 504: GetRayCollisionBox() (2 input parameters)
+Function 511: GetRayCollisionBox() (2 input parameters)
Name: GetRayCollisionBox
Return type: RayCollision
Description: Get collision info between ray and box
Param[1]: ray (type: Ray)
Param[2]: box (type: BoundingBox)
-Function 505: GetRayCollisionMesh() (3 input parameters)
+Function 512: GetRayCollisionMesh() (3 input parameters)
Name: GetRayCollisionMesh
Return type: RayCollision
Description: Get collision info between ray and mesh
Param[1]: ray (type: Ray)
Param[2]: mesh (type: Mesh)
Param[3]: transform (type: Matrix)
-Function 506: GetRayCollisionTriangle() (4 input parameters)
+Function 513: GetRayCollisionTriangle() (4 input parameters)
Name: GetRayCollisionTriangle
Return type: RayCollision
Description: Get collision info between ray and triangle
@@ -4241,7 +4294,7 @@ Function 506: GetRayCollisionTriangle() (4 input parameters)
Param[2]: p1 (type: Vector3)
Param[3]: p2 (type: Vector3)
Param[4]: p3 (type: Vector3)
-Function 507: GetRayCollisionQuad() (5 input parameters)
+Function 514: GetRayCollisionQuad() (5 input parameters)
Name: GetRayCollisionQuad
Return type: RayCollision
Description: Get collision info between ray and quad
@@ -4250,158 +4303,158 @@ Function 507: GetRayCollisionQuad() (5 input parameters)
Param[3]: p2 (type: Vector3)
Param[4]: p3 (type: Vector3)
Param[5]: p4 (type: Vector3)
-Function 508: InitAudioDevice() (0 input parameters)
+Function 515: InitAudioDevice() (0 input parameters)
Name: InitAudioDevice
Return type: void
Description: Initialize audio device and context
No input parameters
-Function 509: CloseAudioDevice() (0 input parameters)
+Function 516: CloseAudioDevice() (0 input parameters)
Name: CloseAudioDevice
Return type: void
Description: Close the audio device and context
No input parameters
-Function 510: IsAudioDeviceReady() (0 input parameters)
+Function 517: IsAudioDeviceReady() (0 input parameters)
Name: IsAudioDeviceReady
Return type: bool
Description: Check if audio device has been initialized successfully
No input parameters
-Function 511: SetMasterVolume() (1 input parameters)
+Function 518: SetMasterVolume() (1 input parameters)
Name: SetMasterVolume
Return type: void
Description: Set master volume (listener)
Param[1]: volume (type: float)
-Function 512: GetMasterVolume() (0 input parameters)
+Function 519: GetMasterVolume() (0 input parameters)
Name: GetMasterVolume
Return type: float
Description: Get master volume (listener)
No input parameters
-Function 513: LoadWave() (1 input parameters)
+Function 520: LoadWave() (1 input parameters)
Name: LoadWave
Return type: Wave
Description: Load wave data from file
Param[1]: fileName (type: const char *)
-Function 514: LoadWaveFromMemory() (3 input parameters)
+Function 521: LoadWaveFromMemory() (3 input parameters)
Name: LoadWaveFromMemory
Return type: Wave
Description: Load wave from memory buffer, fileType refers to extension: i.e. '.wav'
Param[1]: fileType (type: const char *)
Param[2]: fileData (type: const unsigned char *)
Param[3]: dataSize (type: int)
-Function 515: IsWaveReady() (1 input parameters)
- Name: IsWaveReady
+Function 522: IsWaveValid() (1 input parameters)
+ Name: IsWaveValid
Return type: bool
- Description: Checks if wave data is ready
+ Description: Checks if wave data is valid (data loaded and parameters)
Param[1]: wave (type: Wave)
-Function 516: LoadSound() (1 input parameters)
+Function 523: LoadSound() (1 input parameters)
Name: LoadSound
Return type: Sound
Description: Load sound from file
Param[1]: fileName (type: const char *)
-Function 517: LoadSoundFromWave() (1 input parameters)
+Function 524: LoadSoundFromWave() (1 input parameters)
Name: LoadSoundFromWave
Return type: Sound
Description: Load sound from wave data
Param[1]: wave (type: Wave)
-Function 518: LoadSoundAlias() (1 input parameters)
+Function 525: LoadSoundAlias() (1 input parameters)
Name: LoadSoundAlias
Return type: Sound
Description: Create a new sound that shares the same sample data as the source sound, does not own the sound data
Param[1]: source (type: Sound)
-Function 519: IsSoundReady() (1 input parameters)
- Name: IsSoundReady
+Function 526: IsSoundValid() (1 input parameters)
+ Name: IsSoundValid
Return type: bool
- Description: Checks if a sound is ready
+ Description: Checks if a sound is valid (data loaded and buffers initialized)
Param[1]: sound (type: Sound)
-Function 520: UpdateSound() (3 input parameters)
+Function 527: UpdateSound() (3 input parameters)
Name: UpdateSound
Return type: void
Description: Update sound buffer with new data
Param[1]: sound (type: Sound)
Param[2]: data (type: const void *)
Param[3]: sampleCount (type: int)
-Function 521: UnloadWave() (1 input parameters)
+Function 528: UnloadWave() (1 input parameters)
Name: UnloadWave
Return type: void
Description: Unload wave data
Param[1]: wave (type: Wave)
-Function 522: UnloadSound() (1 input parameters)
+Function 529: UnloadSound() (1 input parameters)
Name: UnloadSound
Return type: void
Description: Unload sound
Param[1]: sound (type: Sound)
-Function 523: UnloadSoundAlias() (1 input parameters)
+Function 530: UnloadSoundAlias() (1 input parameters)
Name: UnloadSoundAlias
Return type: void
Description: Unload a sound alias (does not deallocate sample data)
Param[1]: alias (type: Sound)
-Function 524: ExportWave() (2 input parameters)
+Function 531: ExportWave() (2 input parameters)
Name: ExportWave
Return type: bool
Description: Export wave data to file, returns true on success
Param[1]: wave (type: Wave)
Param[2]: fileName (type: const char *)
-Function 525: ExportWaveAsCode() (2 input parameters)
+Function 532: ExportWaveAsCode() (2 input parameters)
Name: ExportWaveAsCode
Return type: bool
Description: Export wave sample data to code (.h), returns true on success
Param[1]: wave (type: Wave)
Param[2]: fileName (type: const char *)
-Function 526: PlaySound() (1 input parameters)
+Function 533: PlaySound() (1 input parameters)
Name: PlaySound
Return type: void
Description: Play a sound
Param[1]: sound (type: Sound)
-Function 527: StopSound() (1 input parameters)
+Function 534: StopSound() (1 input parameters)
Name: StopSound
Return type: void
Description: Stop playing a sound
Param[1]: sound (type: Sound)
-Function 528: PauseSound() (1 input parameters)
+Function 535: PauseSound() (1 input parameters)
Name: PauseSound
Return type: void
Description: Pause a sound
Param[1]: sound (type: Sound)
-Function 529: ResumeSound() (1 input parameters)
+Function 536: ResumeSound() (1 input parameters)
Name: ResumeSound
Return type: void
Description: Resume a paused sound
Param[1]: sound (type: Sound)
-Function 530: IsSoundPlaying() (1 input parameters)
+Function 537: IsSoundPlaying() (1 input parameters)
Name: IsSoundPlaying
Return type: bool
Description: Check if a sound is currently playing
Param[1]: sound (type: Sound)
-Function 531: SetSoundVolume() (2 input parameters)
+Function 538: SetSoundVolume() (2 input parameters)
Name: SetSoundVolume
Return type: void
Description: Set volume for a sound (1.0 is max level)
Param[1]: sound (type: Sound)
Param[2]: volume (type: float)
-Function 532: SetSoundPitch() (2 input parameters)
+Function 539: SetSoundPitch() (2 input parameters)
Name: SetSoundPitch
Return type: void
Description: Set pitch for a sound (1.0 is base level)
Param[1]: sound (type: Sound)
Param[2]: pitch (type: float)
-Function 533: SetSoundPan() (2 input parameters)
+Function 540: SetSoundPan() (2 input parameters)
Name: SetSoundPan
Return type: void
Description: Set pan for a sound (0.5 is center)
Param[1]: sound (type: Sound)
Param[2]: pan (type: float)
-Function 534: WaveCopy() (1 input parameters)
+Function 541: WaveCopy() (1 input parameters)
Name: WaveCopy
Return type: Wave
Description: Copy a wave to a new wave
Param[1]: wave (type: Wave)
-Function 535: WaveCrop() (3 input parameters)
+Function 542: WaveCrop() (3 input parameters)
Name: WaveCrop
Return type: void
Description: Crop a wave to defined frames range
Param[1]: wave (type: Wave *)
Param[2]: initFrame (type: int)
Param[3]: finalFrame (type: int)
-Function 536: WaveFormat() (4 input parameters)
+Function 543: WaveFormat() (4 input parameters)
Name: WaveFormat
Return type: void
Description: Convert wave data to desired format
@@ -4409,203 +4462,203 @@ Function 536: WaveFormat() (4 input parameters)
Param[2]: sampleRate (type: int)
Param[3]: sampleSize (type: int)
Param[4]: channels (type: int)
-Function 537: LoadWaveSamples() (1 input parameters)
+Function 544: LoadWaveSamples() (1 input parameters)
Name: LoadWaveSamples
Return type: float *
Description: Load samples data from wave as a 32bit float data array
Param[1]: wave (type: Wave)
-Function 538: UnloadWaveSamples() (1 input parameters)
+Function 545: UnloadWaveSamples() (1 input parameters)
Name: UnloadWaveSamples
Return type: void
Description: Unload samples data loaded with LoadWaveSamples()
Param[1]: samples (type: float *)
-Function 539: LoadMusicStream() (1 input parameters)
+Function 546: LoadMusicStream() (1 input parameters)
Name: LoadMusicStream
Return type: Music
Description: Load music stream from file
Param[1]: fileName (type: const char *)
-Function 540: LoadMusicStreamFromMemory() (3 input parameters)
+Function 547: LoadMusicStreamFromMemory() (3 input parameters)
Name: LoadMusicStreamFromMemory
Return type: Music
Description: Load music stream from data
Param[1]: fileType (type: const char *)
Param[2]: data (type: const unsigned char *)
Param[3]: dataSize (type: int)
-Function 541: IsMusicReady() (1 input parameters)
- Name: IsMusicReady
+Function 548: IsMusicValid() (1 input parameters)
+ Name: IsMusicValid
Return type: bool
- Description: Checks if a music stream is ready
+ Description: Checks if a music stream is valid (context and buffers initialized)
Param[1]: music (type: Music)
-Function 542: UnloadMusicStream() (1 input parameters)
+Function 549: UnloadMusicStream() (1 input parameters)
Name: UnloadMusicStream
Return type: void
Description: Unload music stream
Param[1]: music (type: Music)
-Function 543: PlayMusicStream() (1 input parameters)
+Function 550: PlayMusicStream() (1 input parameters)
Name: PlayMusicStream
Return type: void
Description: Start music playing
Param[1]: music (type: Music)
-Function 544: IsMusicStreamPlaying() (1 input parameters)
+Function 551: IsMusicStreamPlaying() (1 input parameters)
Name: IsMusicStreamPlaying
Return type: bool
Description: Check if music is playing
Param[1]: music (type: Music)
-Function 545: UpdateMusicStream() (1 input parameters)
+Function 552: UpdateMusicStream() (1 input parameters)
Name: UpdateMusicStream
Return type: void
Description: Updates buffers for music streaming
Param[1]: music (type: Music)
-Function 546: StopMusicStream() (1 input parameters)
+Function 553: StopMusicStream() (1 input parameters)
Name: StopMusicStream
Return type: void
Description: Stop music playing
Param[1]: music (type: Music)
-Function 547: PauseMusicStream() (1 input parameters)
+Function 554: PauseMusicStream() (1 input parameters)
Name: PauseMusicStream
Return type: void
Description: Pause music playing
Param[1]: music (type: Music)
-Function 548: ResumeMusicStream() (1 input parameters)
+Function 555: ResumeMusicStream() (1 input parameters)
Name: ResumeMusicStream
Return type: void
Description: Resume playing paused music
Param[1]: music (type: Music)
-Function 549: SeekMusicStream() (2 input parameters)
+Function 556: SeekMusicStream() (2 input parameters)
Name: SeekMusicStream
Return type: void
Description: Seek music to a position (in seconds)
Param[1]: music (type: Music)
Param[2]: position (type: float)
-Function 550: SetMusicVolume() (2 input parameters)
+Function 557: SetMusicVolume() (2 input parameters)
Name: SetMusicVolume
Return type: void
Description: Set volume for music (1.0 is max level)
Param[1]: music (type: Music)
Param[2]: volume (type: float)
-Function 551: SetMusicPitch() (2 input parameters)
+Function 558: SetMusicPitch() (2 input parameters)
Name: SetMusicPitch
Return type: void
Description: Set pitch for a music (1.0 is base level)
Param[1]: music (type: Music)
Param[2]: pitch (type: float)
-Function 552: SetMusicPan() (2 input parameters)
+Function 559: SetMusicPan() (2 input parameters)
Name: SetMusicPan
Return type: void
Description: Set pan for a music (0.5 is center)
Param[1]: music (type: Music)
Param[2]: pan (type: float)
-Function 553: GetMusicTimeLength() (1 input parameters)
+Function 560: GetMusicTimeLength() (1 input parameters)
Name: GetMusicTimeLength
Return type: float
Description: Get music time length (in seconds)
Param[1]: music (type: Music)
-Function 554: GetMusicTimePlayed() (1 input parameters)
+Function 561: GetMusicTimePlayed() (1 input parameters)
Name: GetMusicTimePlayed
Return type: float
Description: Get current music time played (in seconds)
Param[1]: music (type: Music)
-Function 555: LoadAudioStream() (3 input parameters)
+Function 562: LoadAudioStream() (3 input parameters)
Name: LoadAudioStream
Return type: AudioStream
Description: Load audio stream (to stream raw audio pcm data)
Param[1]: sampleRate (type: unsigned int)
Param[2]: sampleSize (type: unsigned int)
Param[3]: channels (type: unsigned int)
-Function 556: IsAudioStreamReady() (1 input parameters)
- Name: IsAudioStreamReady
+Function 563: IsAudioStreamValid() (1 input parameters)
+ Name: IsAudioStreamValid
Return type: bool
- Description: Checks if an audio stream is ready
+ Description: Checks if an audio stream is valid (buffers initialized)
Param[1]: stream (type: AudioStream)
-Function 557: UnloadAudioStream() (1 input parameters)
+Function 564: UnloadAudioStream() (1 input parameters)
Name: UnloadAudioStream
Return type: void
Description: Unload audio stream and free memory
Param[1]: stream (type: AudioStream)
-Function 558: UpdateAudioStream() (3 input parameters)
+Function 565: UpdateAudioStream() (3 input parameters)
Name: UpdateAudioStream
Return type: void
Description: Update audio stream buffers with data
Param[1]: stream (type: AudioStream)
Param[2]: data (type: const void *)
Param[3]: frameCount (type: int)
-Function 559: IsAudioStreamProcessed() (1 input parameters)
+Function 566: IsAudioStreamProcessed() (1 input parameters)
Name: IsAudioStreamProcessed
Return type: bool
Description: Check if any audio stream buffers requires refill
Param[1]: stream (type: AudioStream)
-Function 560: PlayAudioStream() (1 input parameters)
+Function 567: PlayAudioStream() (1 input parameters)
Name: PlayAudioStream
Return type: void
Description: Play audio stream
Param[1]: stream (type: AudioStream)
-Function 561: PauseAudioStream() (1 input parameters)
+Function 568: PauseAudioStream() (1 input parameters)
Name: PauseAudioStream
Return type: void
Description: Pause audio stream
Param[1]: stream (type: AudioStream)
-Function 562: ResumeAudioStream() (1 input parameters)
+Function 569: ResumeAudioStream() (1 input parameters)
Name: ResumeAudioStream
Return type: void
Description: Resume audio stream
Param[1]: stream (type: AudioStream)
-Function 563: IsAudioStreamPlaying() (1 input parameters)
+Function 570: IsAudioStreamPlaying() (1 input parameters)
Name: IsAudioStreamPlaying
Return type: bool
Description: Check if audio stream is playing
Param[1]: stream (type: AudioStream)
-Function 564: StopAudioStream() (1 input parameters)
+Function 571: StopAudioStream() (1 input parameters)
Name: StopAudioStream
Return type: void
Description: Stop audio stream
Param[1]: stream (type: AudioStream)
-Function 565: SetAudioStreamVolume() (2 input parameters)
+Function 572: SetAudioStreamVolume() (2 input parameters)
Name: SetAudioStreamVolume
Return type: void
Description: Set volume for audio stream (1.0 is max level)
Param[1]: stream (type: AudioStream)
Param[2]: volume (type: float)
-Function 566: SetAudioStreamPitch() (2 input parameters)
+Function 573: SetAudioStreamPitch() (2 input parameters)
Name: SetAudioStreamPitch
Return type: void
Description: Set pitch for audio stream (1.0 is base level)
Param[1]: stream (type: AudioStream)
Param[2]: pitch (type: float)
-Function 567: SetAudioStreamPan() (2 input parameters)
+Function 574: SetAudioStreamPan() (2 input parameters)
Name: SetAudioStreamPan
Return type: void
Description: Set pan for audio stream (0.5 is centered)
Param[1]: stream (type: AudioStream)
Param[2]: pan (type: float)
-Function 568: SetAudioStreamBufferSizeDefault() (1 input parameters)
+Function 575: SetAudioStreamBufferSizeDefault() (1 input parameters)
Name: SetAudioStreamBufferSizeDefault
Return type: void
Description: Default size for new audio streams
Param[1]: size (type: int)
-Function 569: SetAudioStreamCallback() (2 input parameters)
+Function 576: SetAudioStreamCallback() (2 input parameters)
Name: SetAudioStreamCallback
Return type: void
Description: Audio thread callback to request new data
Param[1]: stream (type: AudioStream)
Param[2]: callback (type: AudioCallback)
-Function 570: AttachAudioStreamProcessor() (2 input parameters)
+Function 577: AttachAudioStreamProcessor() (2 input parameters)
Name: AttachAudioStreamProcessor
Return type: void
Description: Attach audio stream processor to stream, receives the samples as 'float'
Param[1]: stream (type: AudioStream)
Param[2]: processor (type: AudioCallback)
-Function 571: DetachAudioStreamProcessor() (2 input parameters)
+Function 578: DetachAudioStreamProcessor() (2 input parameters)
Name: DetachAudioStreamProcessor
Return type: void
Description: Detach audio stream processor from stream
Param[1]: stream (type: AudioStream)
Param[2]: processor (type: AudioCallback)
-Function 572: AttachAudioMixedProcessor() (1 input parameters)
+Function 579: AttachAudioMixedProcessor() (1 input parameters)
Name: AttachAudioMixedProcessor
Return type: void
Description: Attach audio stream processor to the entire audio pipeline, receives the samples as 'float'
Param[1]: processor (type: AudioCallback)
-Function 573: DetachAudioMixedProcessor() (1 input parameters)
+Function 580: DetachAudioMixedProcessor() (1 input parameters)
Name: DetachAudioMixedProcessor
Return type: void
Description: Detach audio stream processor from the entire audio pipeline
diff --git a/parser/output/raylib_api.xml b/parser/output/raylib_api.xml
index 8a6560f48..f59faf754 100644
--- a/parser/output/raylib_api.xml
+++ b/parser/output/raylib_api.xml
@@ -160,7 +160,7 @@
-
+
@@ -172,8 +172,10 @@
-
-
+
+
+
+
@@ -505,7 +507,7 @@
-
+
@@ -532,6 +534,9 @@
+
+
+
@@ -670,7 +675,7 @@
-
+
@@ -703,9 +708,9 @@
-
+
-
+
@@ -866,7 +871,7 @@
-
+
@@ -1069,6 +1074,9 @@
+
+
+
@@ -1081,7 +1089,7 @@
-
+
@@ -1118,6 +1126,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1261,7 +1281,7 @@
-
+
@@ -1289,12 +1309,12 @@
-
+
-
+
@@ -1691,11 +1711,6 @@
-
-
-
-
-
@@ -1716,7 +1731,7 @@
-
+
@@ -2101,13 +2116,13 @@
-
+
-
+
@@ -2219,6 +2234,11 @@
+
+
+
+
+
@@ -2241,7 +2261,7 @@
-
+
@@ -2260,7 +2280,7 @@
-
+
@@ -2600,7 +2620,7 @@
-
+
@@ -2637,6 +2657,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2767,7 +2801,7 @@
-
+
@@ -2803,6 +2837,11 @@
+
+
+
+
+
@@ -2864,7 +2903,7 @@
-
+
@@ -2876,7 +2915,7 @@
-
+
@@ -2956,7 +2995,7 @@
-
+
@@ -3007,7 +3046,7 @@
-
+
diff --git a/parser/raylib_parser.c b/parser/raylib_parser.c
index cfb0133c3..94a715562 100644
--- a/parser/raylib_parser.c
+++ b/parser/raylib_parser.c
@@ -72,7 +72,7 @@
#define MAX_CALLBACKS_TO_PARSE 64 // Maximum number of callbacks to parse
#define MAX_FUNCS_TO_PARSE 1024 // Maximum number of functions to parse
-#define MAX_LINE_LENGTH 512 // Maximum length of one line (including comments)
+#define MAX_LINE_LENGTH 1024 // Maximum length of one line (including comments)
#define MAX_STRUCT_FIELDS 64 // Maximum number of struct fields
#define MAX_ENUM_VALUES 512 // Maximum number of enum values
@@ -139,7 +139,7 @@ typedef struct EnumInfo {
// Function info data
typedef struct FunctionInfo {
char name[64]; // Function name
- char desc[128]; // Function description (comment at the end)
+ char desc[512]; // Function description (comment at the end)
char retType[32]; // Return value type
int paramCount; // Number of function parameters
char paramType[MAX_FUNCTION_PARAMETERS][32]; // Parameters type
diff --git a/projects/CMake/CMakeLists.txt b/projects/CMake/CMakeLists.txt
index a95d68a4f..96e33f344 100644
--- a/projects/CMake/CMakeLists.txt
+++ b/projects/CMake/CMakeLists.txt
@@ -30,8 +30,8 @@ target_link_libraries(${PROJECT_NAME} raylib)
# Web Configurations
if (${PLATFORM} STREQUAL "Web")
- # Tell Emscripten to build an example.html file.
- set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html")
+ set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html") # Tell Emscripten to build an example.html file.
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY -s GL_ENABLE_GET_PROC_ADDRESS=1")
endif()
# Checks if OSX and links appropriate frameworks (Only required on MacOS)
diff --git a/projects/CMake/README.md b/projects/CMake/README.md
index f7873c30f..fc4fe5542 100644
--- a/projects/CMake/README.md
+++ b/projects/CMake/README.md
@@ -22,6 +22,6 @@ Compiling for the web requires the [Emscripten SDK](https://emscripten.org/docs/
``` bash
mkdir build
cd build
-emcmake cmake .. -DPLATFORM=Web -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXE_LINKER_FLAGS="-s USE_GLFW=3" -DCMAKE_EXECUTABLE_SUFFIX=".html"
+emcmake cmake .. -DPLATFORM=Web -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXECUTABLE_SUFFIX=".html"
emmake make
-```
\ No newline at end of file
+```
diff --git a/projects/VS2022/examples/models_gpu_skinning.vcxproj b/projects/VS2022/examples/models_gpu_skinning.vcxproj
new file mode 100644
index 000000000..bd596bed6
--- /dev/null
+++ b/projects/VS2022/examples/models_gpu_skinning.vcxproj
@@ -0,0 +1,387 @@
+
+
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}
+ Win32Proj
+ models_loading
+ 10.0
+ models_gpu_skinning
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\models
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln
index 294d0e84d..1dbd38984 100644
--- a/projects/VS2022/raylib.sln
+++ b/projects/VS2022/raylib.sln
@@ -293,12 +293,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_texture_outline", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_texture_tiling", "examples\shaders_texture_tiling.vcxproj", "{EFA150D4-F93B-4D7D-A69C-9E8B4663BECD}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textures_svg_loading", "examples\textures_svg_loading.vcxproj", "{D8026C60-CCBC-45DF-9085-BF21569EB414}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_splines_drawing", "examples\shapes_splines_drawing.vcxproj", "{DF25E545-00FF-4E64-844C-7DF98991F901}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_top_down_lights", "examples\shapes_top_down_lights.vcxproj", "{703BE7BA-5B99-4F70-806D-3A259F6A991E}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "models_gpu_skinning", "examples\models_gpu_skinning.vcxproj", "{8245DAD9-D402-4D5C-8F45-32229CD3B263}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug.DLL|x64 = Debug.DLL|x64
@@ -2531,6 +2531,22 @@ Global
{703BE7BA-5B99-4F70-806D-3A259F6A991E}.Release|x64.Build.0 = Release|x64
{703BE7BA-5B99-4F70-806D-3A259F6A991E}.Release|x86.ActiveCfg = Release|Win32
{703BE7BA-5B99-4F70-806D-3A259F6A991E}.Release|x86.Build.0 = Release|Win32
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x64.ActiveCfg = Debug|x64
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x64.Build.0 = Debug|x64
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x86.ActiveCfg = Debug|Win32
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Debug|x86.Build.0 = Debug|Win32
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x64.ActiveCfg = Release|x64
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x64.Build.0 = Release|x64
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x86.ActiveCfg = Release|Win32
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2682,6 +2698,7 @@ Global
{D8026C60-CCBC-45DF-9085-BF21569EB414} = {DA049009-21FF-4AC0-84E4-830DD1BCD0CE}
{DF25E545-00FF-4E64-844C-7DF98991F901} = {278D8859-20B1-428F-8448-064F46E1F021}
{703BE7BA-5B99-4F70-806D-3A259F6A991E} = {278D8859-20B1-428F-8448-064F46E1F021}
+ {8245DAD9-D402-4D5C-8F45-32229CD3B263} = {AF5BEC5C-1F2B-4DA8-B12D-D09FE569237C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29}
diff --git a/projects/VSCode/Makefile b/projects/VSCode/Makefile
index 2f43c9ead..86febfba0 100644
--- a/projects/VSCode/Makefile
+++ b/projects/VSCode/Makefile
@@ -352,9 +352,9 @@ SRC_DIR = src
OBJ_DIR = obj
# Define all object files from source files
-SRC = $(call rwildcard, *.c, *.h)
+SRC = $(call rwildcard, ./, *.c, *.h)
#OBJS = $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
-OBJS ?= main.c
+OBJS = $(patsubst %.c,%.o,$(filter %.c,$(SRC)))
# For Android platform we call a custom Makefile.Android
ifeq ($(PLATFORM),PLATFORM_ANDROID)
diff --git a/src/Makefile b/src/Makefile
index 4740f1f01..137c28b53 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -109,8 +109,9 @@ RAYLIB_MODULE_RAYGUI_PATH ?= $(RAYLIB_SRC_PATH)/../../raygui/src
# Use external GLFW library instead of rglfw module
USE_EXTERNAL_GLFW ?= FALSE
-# Enable support for both Wayland and X11 by default on Linux when using GLFW
-GLFW_LINUX_ENABLE_WAYLAND ?= TRUE
+# Enable support for X11 by default on Linux when using GLFW
+# NOTE: Wayland is disabled by default, only enable if you are sure
+GLFW_LINUX_ENABLE_WAYLAND ?= FALSE
GLFW_LINUX_ENABLE_X11 ?= TRUE
# PLATFORM_DESKTOP_SDL: It requires SDL library to be provided externally
diff --git a/src/build.zig b/src/build.zig
deleted file mode 100644
index 4e112d78f..000000000
--- a/src/build.zig
+++ /dev/null
@@ -1,377 +0,0 @@
-const std = @import("std");
-const builtin = @import("builtin");
-
-comptime {
- if (builtin.zig_version.minor < 12) @compileError("Raylib requires zig version 0.12.0");
-}
-
-// NOTE(freakmangd): I don't like using a global here, but it prevents having to
-// get the flags a second time when adding raygui
-var raylib_flags_arr: std.ArrayListUnmanaged([]const u8) = .{};
-
-/// we're not inside the actual build script recognized by the
-/// zig build system; use this type where one would otherwise
-/// use `@This()` when inside the actual entrypoint file.
-const BuildScript = @import("../build.zig");
-
-// This has been tested with zig version 0.12.0
-pub fn addRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile {
- const raylib_dep = b.dependencyFromBuildZig(BuildScript, .{
- .target = target,
- .optimize = optimize,
- .raudio = options.raudio,
- .rmodels = options.rmodels,
- .rshapes = options.rshapes,
- .rtext = options.rtext,
- .rtextures = options.rtextures,
- .platform_drm = options.platform_drm,
- .shared = options.shared,
- .linux_display_backend = options.linux_display_backend,
- .opengl_version = options.opengl_version,
- .config = options.config,
- });
- const raylib = raylib_dep.artifact("raylib");
-
- if (options.raygui) {
- const raygui_dep = b.dependency(options.raygui_dependency_name, .{});
- addRaygui(b, raylib, raygui_dep);
- }
-
- return raylib;
-}
-
-fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile {
- raylib_flags_arr.clearRetainingCapacity();
-
- const shared_flags = &[_][]const u8{
- "-fPIC",
- "-DBUILD_LIBTYPE_SHARED",
- };
- try raylib_flags_arr.appendSlice(b.allocator, &[_][]const u8{
- "-std=gnu99",
- "-D_GNU_SOURCE",
- "-DGL_SILENCE_DEPRECATION=199309L",
- "-fno-sanitize=undefined", // https://github.com/raysan5/raylib/issues/3674
- });
- if (options.config) |config| {
- const file = try std.fs.path.join(b.allocator, &.{ std.fs.path.dirname(@src().file) orelse ".", "config.h" });
- defer b.allocator.free(file);
- const content = try std.fs.cwd().readFileAlloc(b.allocator, file, std.math.maxInt(usize));
- defer b.allocator.free(content);
-
- var lines = std.mem.splitScalar(u8, content, '\n');
- while (lines.next()) |line| {
- if (!std.mem.containsAtLeast(u8, line, 1, "SUPPORT")) continue;
- if (std.mem.startsWith(u8, line, "//")) continue;
-
- var flag = std.mem.trimLeft(u8, line, " \t"); // Trim whitespace
- flag = flag["#define ".len - 1 ..]; // Remove #define
- flag = std.mem.trimLeft(u8, flag, " \t"); // Trim whitespace
- flag = flag[0..std.mem.indexOf(u8, flag, " ").?]; // Flag is only one word, so capture till space
- flag = try std.fmt.allocPrint(b.allocator, "-D{s}", .{flag}); // Prepend with -D
-
- // If user specifies the flag skip it
- if (std.mem.containsAtLeast(u8, config, 1, flag)) continue;
-
- // Append default value from config.h to compile flags
- try raylib_flags_arr.append(b.allocator, flag);
- }
-
- // Append config flags supplied by user to compile flags
- try raylib_flags_arr.append(b.allocator, config);
-
- try raylib_flags_arr.append(b.allocator, "-DEXTERNAL_CONFIG_FLAGS");
- }
-
- if (options.shared) {
- try raylib_flags_arr.appendSlice(b.allocator, shared_flags);
- }
-
- const raylib = if (options.shared)
- b.addSharedLibrary(.{
- .name = "raylib",
- .target = target,
- .optimize = optimize,
- })
- else
- b.addStaticLibrary(.{
- .name = "raylib",
- .target = target,
- .optimize = optimize,
- });
- raylib.linkLibC();
-
- // No GLFW required on PLATFORM_DRM
- if (!options.platform_drm) {
- raylib.addIncludePath(b.path("src/external/glfw/include"));
- }
-
- var c_source_files = try std.ArrayList([]const u8).initCapacity(b.allocator, 2);
- c_source_files.appendSliceAssumeCapacity(&.{ "rcore.c", "utils.c" });
-
- if (options.raudio) {
- try c_source_files.append("raudio.c");
- }
- if (options.rmodels) {
- try c_source_files.append("rmodels.c");
- }
- if (options.rshapes) {
- try c_source_files.append("rshapes.c");
- }
- if (options.rtext) {
- try c_source_files.append("rtext.c");
- }
- if (options.rtextures) {
- try c_source_files.append("rtextures.c");
- }
-
- if (options.opengl_version != .auto) {
- raylib.defineCMacro(options.opengl_version.toCMacroStr(), null);
- }
-
- switch (target.result.os.tag) {
- .windows => {
- try c_source_files.append("rglfw.c");
- raylib.linkSystemLibrary("winmm");
- raylib.linkSystemLibrary("gdi32");
- raylib.linkSystemLibrary("opengl32");
-
- raylib.defineCMacro("PLATFORM_DESKTOP", null);
- },
- .linux => {
- if (!options.platform_drm) {
- try c_source_files.append("rglfw.c");
- raylib.linkSystemLibrary("GL");
- raylib.linkSystemLibrary("rt");
- raylib.linkSystemLibrary("dl");
- raylib.linkSystemLibrary("m");
-
- raylib.addLibraryPath(.{ .cwd_relative = "/usr/lib" });
- raylib.addIncludePath(.{ .cwd_relative = "/usr/include" });
- if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) {
- raylib.defineCMacro("_GLFW_X11", null);
- raylib.linkSystemLibrary("X11");
- }
-
- if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) {
- _ = b.findProgram(&.{"wayland-scanner"}, &.{}) catch {
- std.log.err(
- \\ Wayland may not be installed on the system.
- \\ You can switch to X11 in your `build.zig` by changing `Options.linux_display_backend`
- , .{});
- @panic("No Wayland");
- };
- raylib.defineCMacro("_GLFW_WAYLAND", null);
- raylib.linkSystemLibrary("wayland-client");
- raylib.linkSystemLibrary("wayland-cursor");
- raylib.linkSystemLibrary("wayland-egl");
- raylib.linkSystemLibrary("xkbcommon");
- raylib.addIncludePath(b.path("src"));
- waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol");
- waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol");
- waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol");
- waylandGenerate(b, raylib, "viewporter.xml", "viewporter-client-protocol");
- waylandGenerate(b, raylib, "relative-pointer-unstable-v1.xml", "relative-pointer-unstable-v1-client-protocol");
- waylandGenerate(b, raylib, "pointer-constraints-unstable-v1.xml", "pointer-constraints-unstable-v1-client-protocol");
- waylandGenerate(b, raylib, "fractional-scale-v1.xml", "fractional-scale-v1-client-protocol");
- waylandGenerate(b, raylib, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol");
- waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol");
- }
- raylib.defineCMacro("PLATFORM_DESKTOP", null);
- } else {
- if (options.opengl_version == .auto) {
- raylib.linkSystemLibrary("GLESv2");
- raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null);
- }
-
- raylib.linkSystemLibrary("EGL");
- raylib.linkSystemLibrary("drm");
- raylib.linkSystemLibrary("gbm");
- raylib.linkSystemLibrary("pthread");
- raylib.linkSystemLibrary("rt");
- raylib.linkSystemLibrary("m");
- raylib.linkSystemLibrary("dl");
- raylib.addIncludePath(.{ .cwd_relative = "/usr/include/libdrm" });
-
- raylib.defineCMacro("PLATFORM_DRM", null);
- raylib.defineCMacro("EGL_NO_X11", null);
- raylib.defineCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", "2048");
- }
- },
- .freebsd, .openbsd, .netbsd, .dragonfly => {
- try c_source_files.append("rglfw.c");
- raylib.linkSystemLibrary("GL");
- raylib.linkSystemLibrary("rt");
- raylib.linkSystemLibrary("dl");
- raylib.linkSystemLibrary("m");
- raylib.linkSystemLibrary("X11");
- raylib.linkSystemLibrary("Xrandr");
- raylib.linkSystemLibrary("Xinerama");
- raylib.linkSystemLibrary("Xi");
- raylib.linkSystemLibrary("Xxf86vm");
- raylib.linkSystemLibrary("Xcursor");
-
- raylib.defineCMacro("PLATFORM_DESKTOP", null);
- },
- .macos => {
- // On macos rglfw.c include Objective-C files.
- try raylib_flags_arr.append(b.allocator, "-ObjC");
- raylib.root_module.addCSourceFile(.{
- .file = b.path("src/rglfw.c"),
- .flags = raylib_flags_arr.items,
- });
- _ = raylib_flags_arr.pop();
- raylib.linkFramework("Foundation");
- raylib.linkFramework("CoreServices");
- raylib.linkFramework("CoreGraphics");
- raylib.linkFramework("AppKit");
- raylib.linkFramework("IOKit");
-
- raylib.defineCMacro("PLATFORM_DESKTOP", null);
- },
- .emscripten => {
- raylib.defineCMacro("PLATFORM_WEB", null);
- if (options.opengl_version == .auto) {
- raylib.defineCMacro("GRAPHICS_API_OPENGL_ES2", null);
- }
-
- if (b.sysroot == null) {
- @panic("Pass '--sysroot \"$EMSDK/upstream/emscripten\"'");
- }
-
- const cache_include = std.fs.path.join(b.allocator, &.{ b.sysroot.?, "cache", "sysroot", "include" }) catch @panic("Out of memory");
- defer b.allocator.free(cache_include);
-
- var dir = std.fs.openDirAbsolute(cache_include, std.fs.Dir.OpenDirOptions{ .access_sub_paths = true, .no_follow = true }) catch @panic("No emscripten cache. Generate it!");
- dir.close();
- raylib.addIncludePath(.{ .cwd_relative = cache_include });
- },
- else => {
- @panic("Unsupported OS");
- },
- }
-
- raylib.addIncludePath(b.path("src"));
- raylib.root_module.addCSourceFiles(.{
- .root = b.path("src"),
- .files = c_source_files.items,
- .flags = raylib_flags_arr.items,
- });
-
- return raylib;
-}
-
-/// This function does not need to be called if you passed .raygui = true to addRaylib
-pub fn addRaygui(b: *std.Build, raylib: *std.Build.Step.Compile, raygui_dep: *std.Build.Dependency) void {
- if (raylib_flags_arr.items.len == 0) {
- @panic(
- \\argument 2 `raylib` in `addRaygui` must come from b.dependency("raylib", ...).artifact("raylib")
- );
- }
-
- var gen_step = b.addWriteFiles();
- raylib.step.dependOn(&gen_step.step);
-
- const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n");
- raylib.addCSourceFile(.{ .file = raygui_c_path, .flags = raylib_flags_arr.items });
- raylib.addIncludePath(raygui_dep.path("src"));
-
- raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h");
-}
-
-pub const Options = struct {
- raudio: bool = true,
- rmodels: bool = true,
- rshapes: bool = true,
- rtext: bool = true,
- rtextures: bool = true,
- raygui: bool = false,
- platform_drm: bool = false,
- shared: bool = false,
- linux_display_backend: LinuxDisplayBackend = .Both,
- opengl_version: OpenglVersion = .auto,
- config: ?[]const u8 = null,
-
- raygui_dependency_name: []const u8 = "raygui",
-};
-
-pub const OpenglVersion = enum {
- auto,
- gl_1_1,
- gl_2_1,
- gl_3_3,
- gl_4_3,
- gles_2,
- gles_3,
-
- pub fn toCMacroStr(self: @This()) []const u8 {
- switch (self) {
- .auto => @panic("OpenglVersion.auto cannot be turned into a C macro string"),
- .gl_1_1 => return "GRAPHICS_API_OPENGL_11",
- .gl_2_1 => return "GRAPHICS_API_OPENGL_21",
- .gl_3_3 => return "GRAPHICS_API_OPENGL_33",
- .gl_4_3 => return "GRAPHICS_API_OPENGL_43",
- .gles_2 => return "GRAPHICS_API_OPENGL_ES2",
- .gles_3 => return "GRAPHICS_API_OPENGL_ES3",
- }
- }
-};
-
-pub const LinuxDisplayBackend = enum {
- X11,
- Wayland,
- Both,
-};
-
-pub fn build(b: *std.Build) !void {
- // Standard target options allows the person running `zig build` to choose
- // what target to build for. Here we do not override the defaults, which
- // means any target is allowed, and the default is native. Other options
- // for restricting supported target set are available.
- const target = b.standardTargetOptions(.{});
- // Standard optimization options allow the person running `zig build` to select
- // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
- // set a preferred release mode, allowing the user to decide how to optimize.
- const optimize = b.standardOptimizeOption(.{});
-
- const defaults = Options{};
- const options = Options{
- .platform_drm = b.option(bool, "platform_drm", "Compile raylib in native mode (no X11)") orelse defaults.platform_drm,
- .raudio = b.option(bool, "raudio", "Compile with audio support") orelse defaults.raudio,
- .rmodels = b.option(bool, "rmodels", "Compile with models support") orelse defaults.rmodels,
- .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext,
- .rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures,
- .rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes,
- .shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared,
- .linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend,
- .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version,
- .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse null,
- };
-
- const lib = try compileRaylib(b, target, optimize, options);
-
- lib.installHeader(b.path("src/raylib.h"), "raylib.h");
- lib.installHeader(b.path("src/raymath.h"), "raymath.h");
- lib.installHeader(b.path("src/rlgl.h"), "rlgl.h");
-
- b.installArtifact(lib);
-}
-
-const waylandDir = "src/external/glfw/deps/wayland";
-
-fn waylandGenerate(b: *std.Build, raylib: *std.Build.Step.Compile, comptime protocol: []const u8, comptime basename: []const u8) void {
- const protocolDir = waylandDir ++ "/" ++ protocol;
- const clientHeader = basename ++ ".h";
- const privateCode = basename ++ "-code.h";
-
- const client_step = b.addSystemCommand(&.{ "wayland-scanner", "client-header" });
- client_step.addFileArg(b.path(protocolDir));
- raylib.addIncludePath(client_step.addOutputFileArg(clientHeader).dirname());
-
- const private_step = b.addSystemCommand(&.{ "wayland-scanner", "private-code" });
- private_step.addFileArg(b.path(protocolDir));
- raylib.addIncludePath(private_step.addOutputFileArg(privateCode).dirname());
-
- raylib.step.dependOn(&client_step.step);
- raylib.step.dependOn(&private_step.step);
-}
diff --git a/src/config.h b/src/config.h
index c54583e74..9123a2291 100644
--- a/src/config.h
+++ b/src/config.h
@@ -113,12 +113,22 @@
#define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
// Default shader vertex attribute locations
-#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
-#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1
-#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2
-#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3
-#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4
-#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5
+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1
+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2
+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3
+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4
+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5
+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6
+
+
+#define RL_SUPPORT_MESH_GPU_SKINNING // Remove this if your GPU does not support more than 8 VBOs
+
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7
+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
+#endif
+
// Default shader vertex attribute names to set location points
// NOTE: When a new shader is loaded, the following locations are tried to be set for convenience
@@ -170,7 +180,6 @@
//#define SUPPORT_FILEFORMAT_ASTC 1
//#define SUPPORT_FILEFORMAT_PKM 1
//#define SUPPORT_FILEFORMAT_PVR 1
-//#define SUPPORT_FILEFORMAT_SVG 1
// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi)
#define SUPPORT_IMAGE_EXPORT 1
@@ -225,7 +234,12 @@
// rmodels: Configuration values
//------------------------------------------------------------------------------------
#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported
+
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
+#define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh
+#else
#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
+#endif
//------------------------------------------------------------------------------------
// Module: raudio - Configuration Flags
diff --git a/src/external/RGFW.h b/src/external/RGFW.h
index 367a46fa6..fb389d5b4 100644
--- a/src/external/RGFW.h
+++ b/src/external/RGFW.h
@@ -192,7 +192,7 @@
typedef u32 b32;
#endif
-#define RGFW_TRUE 1
+#define RGFW_TRUE (!(0))
#define RGFW_FALSE 0
/* thse OS macros looks better & are standardized */
@@ -276,11 +276,6 @@
#endif
#ifdef RGFW_EGL
- #if defined(__APPLE__)
- #warning EGL is not supported for Cocoa, switching back to the native opengl api
- #undef RGFW_EGL
- #endif
-
#include
#elif defined(RGFW_OSMESA)
#ifndef __APPLE__
@@ -611,10 +606,17 @@ typedef struct RGFW_window {
/** * @defgroup Window_management
* @{ */
+
+/*!
+ * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM
+ * by default the class name will == the root window's name
+*/
+RGFWDEF void RGFW_setClassName(char* name);
+
/*! this has to be set before createWindow is called, else the fulscreen size is used */
RGFWDEF void RGFW_setBufferSize(RGFW_area size); /*!< the buffer cannot be resized (by RGFW) */
-RGFW_window* RGFW_createWindow(
+RGFWDEF RGFW_window* RGFW_createWindow(
const char* name, /* name of the window */
RGFW_rect rect, /* rect of window */
u16 args /* extra arguments (NULL / (u16)0 means no args used)*/
@@ -635,7 +637,7 @@ RGFWDEF RGFW_area RGFW_getScreenSize(void);
although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents`
*/
-RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/
+RGFWDEF RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/
/*!
for RGFW_window_eventWait and RGFW_window_checkEvents
@@ -706,7 +708,7 @@ RGFWDEF void RGFW_window_setName(RGFW_window* win,
char* name
);
-void RGFW_window_setIcon(RGFW_window* win, /*!< source window */
+RGFWDEF void RGFW_window_setIcon(RGFW_window* win, /*!< source window */
u8* icon /*!< icon bitmap */,
RGFW_area a /*!< width and height of the bitmap*/,
i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */
@@ -1609,9 +1611,6 @@ RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) {
if (args & RGFW_FULLSCREEN)
rect = RGFW_RECT(0, 0, screenR.w, screenR.h);
- if (args & RGFW_CENTER)
- rect = RGFW_RECT((screenR.w - rect.w) / 2, (screenR.h - rect.h) / 2, rect.w, rect.h);
-
/* set and init the new window's data */
win->r = rect;
win->event.inFocus = 1;
@@ -1627,7 +1626,7 @@ RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) {
void RGFW_window_scaleToMonitor(RGFW_window* win) {
RGFW_monitor monitor = RGFW_window_getMonitor(win);
- RGFW_window_resize(win, RGFW_AREA(((u32) monitor.scaleX) * win->r.w, ((u32) monitor.scaleX) * win->r.h));
+ RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleX * (float)win->r.h)));
}
#endif
@@ -1637,6 +1636,16 @@ RGFW_window* RGFW_root = NULL;
#define RGFW_HOLD_MOUSE (1L<<2) /*!< hold the moues still */
#define RGFW_MOUSE_LEFT (1L<<3) /* if mouse left the window */
+#ifdef RGFW_MACOS
+RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer);
+RGFWDEF void* RGFW_cocoaGetLayer(void);
+#endif
+
+char* RGFW_className = NULL;
+void RGFW_setClassName(char* name) {
+ RGFW_className = name;
+}
+
void RGFW_clipboardFree(char* str) { RGFW_FREE(str); }
RGFW_keyState RGFW_mouseButtons[5] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} };
@@ -2073,6 +2082,8 @@ void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) {
#ifdef RGFW_WINDOWS
win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc);
+ #elif defined(RGFW_MACOS)
+ win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0);
#else
win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
#endif
@@ -2104,8 +2115,15 @@ void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) {
EGLint numConfigs;
eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs);
-
- win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
+ #if defined(RGFW_MACOS)
+ void* layer = RGFW_cocoaGetLayer();
+
+ RGFW_window_cocoaSetLayer(win, layer);
+
+ win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL);
+ #else
+ win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
+ #endif
EGLint attribs[] = {
EGL_CONTEXT_CLIENT_VERSION,
@@ -2322,7 +2340,7 @@ Start of Linux / Unix defines
u8 RGFW_mouseIconSrc[] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor};
/*atoms needed for drag and drop*/
- Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XdndActionMove, XdndActionLink, XdndActionAsk, XdndActionPrivate;
+ Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XtextPlain, XtextUriList;
Atom wm_delete_window = 0;
@@ -2563,9 +2581,13 @@ Start of Linux / Unix defines
// In your .desktop app, if you set the property
// StartupWMClass=RGFW that will assoicate the launcher icon
// with your application - robrohan
+
+ if (RGFW_className == NULL)
+ RGFW_className = (char*)name;
+
XClassHint *hint = XAllocClassHint();
assert(hint != NULL);
- hint->res_class = (char*)"RGFW";
+ hint->res_class = (char*)RGFW_className;
hint->res_name = (char*)name; // just use the window name as the app name
XSetClassHint((Display*) win->src.display, win->src.window, hint);
XFree(hint);
@@ -2609,6 +2631,11 @@ Start of Linux / Unix defines
RGFW_window_scaleToMonitor(win);
#endif
+ if (args & RGFW_CENTER) {
+ RGFW_area screenR = RGFW_getScreenSize();
+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
+ }
+
if (args & RGFW_NO_RESIZE) { /* make it so the user can't resize the window*/
XSizeHints* sh = XAllocSizeHints();
sh->flags = (1L << 4) | (1L << 5);
@@ -2646,7 +2673,6 @@ Start of Linux / Unix defines
if (args & RGFW_ALLOW_DND) { /* init drag and drop atoms and turn on drag and drop for this window */
win->_winArgs |= RGFW_ALLOW_DND;
- XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False);
XdndTypeList = XInternAtom((Display*) win->src.display, "XdndTypeList", False);
XdndSelection = XInternAtom((Display*) win->src.display, "XdndSelection", False);
@@ -2660,15 +2686,16 @@ Start of Linux / Unix defines
/* actions */
XdndActionCopy = XInternAtom((Display*) win->src.display, "XdndActionCopy", False);
- XdndActionMove = XInternAtom((Display*) win->src.display, "XdndActionMove", False);
- XdndActionLink = XInternAtom((Display*) win->src.display, "XdndActionLink", False);
- XdndActionAsk = XInternAtom((Display*) win->src.display, "XdndActionAsk", False);
- XdndActionPrivate = XInternAtom((Display*) win->src.display, "XdndActionPrivate", False);
- const Atom version = 5;
+
+ XtextUriList = XInternAtom((Display*) win->src.display, "text/uri-list", False);
+ XtextPlain = XInternAtom((Display*) win->src.display, "text/plain", False);
+
+ XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False);
+ const u8 version = 5;
XChangeProperty((Display*) win->src.display, (Window) win->src.window,
XdndAware, 4, 32,
- PropModeReplace, (u8*) &version, 1); /*!< turns on drag and drop */
+ PropModeReplace, &version, 1); /*!< turns on drag and drop */
}
#ifdef RGFW_EGL
@@ -2716,17 +2743,16 @@ Start of Linux / Unix defines
return RGFWMouse;
}
- typedef struct XDND {
- long source, version;
- i32 format;
- } XDND; /*!< data structure for xdnd events */
- XDND xdnd;
-
int xAxis = 0, yAxis = 0;
RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
assert(win != NULL);
+ static struct {
+ long source, version;
+ i32 format;
+ } xdnd;
+
if (win->event.type == 0)
RGFW_resetKey();
@@ -2893,13 +2919,16 @@ Start of Linux / Unix defines
win->event.droppedFilesCount = 0;
- /*
- much of this event (drag and drop code) is source from glfw
- */
-
if ((win->_winArgs & RGFW_ALLOW_DND) == 0)
break;
+ XEvent reply = { ClientMessage };
+ reply.xclient.window = xdnd.source;
+ reply.xclient.format = 32;
+ reply.xclient.data.l[0] = (long) win->src.window;
+ reply.xclient.data.l[1] = 0;
+ reply.xclient.data.l[2] = None;
+
if (E.xclient.message_type == XdndEnter) {
unsigned long count;
Atom* formats;
@@ -2944,28 +2973,11 @@ Start of Linux / Unix defines
formats = real_formats;
}
- u32 i;
- for (i = 0; i < (u32)count; i++) {
- char* name = XGetAtomName((Display*) win->src.display, formats[i]);
-
- char* links[2] = { (char*) (const char*) "text/uri-list", (char*) (const char*) "text/plain" };
- for (; 1; name++) {
- u32 j;
- for (j = 0; j < 2; j++) {
- if (*links[j] != *name) {
- links[j] = (char*) (const char*) "\1";
- continue;
- }
-
- if (*links[j] == '\0' && *name == '\0')
- xdnd.format = formats[i];
-
- if (*links[j] != '\0' && *links[j] != '\1')
- links[j]++;
- }
-
- if (*name == '\0')
- break;
+ unsigned long i;
+ for (i = 0; i < count; i++) {
+ if (formats[i] == XtextUriList || formats[i] == XtextPlain) {
+ xdnd.format = formats[i];
+ break;
}
}
@@ -2994,13 +3006,8 @@ Start of Linux / Unix defines
win->event.point.x = xpos;
win->event.point.y = ypos;
- XEvent reply = { ClientMessage };
reply.xclient.window = xdnd.source;
reply.xclient.message_type = XdndStatus;
- reply.xclient.format = 32;
- reply.xclient.data.l[0] = (long) win->src.window;
- reply.xclient.data.l[2] = 0;
- reply.xclient.data.l[3] = 0;
if (xdnd.format) {
reply.xclient.data.l[1] = 1;
@@ -3035,12 +3042,6 @@ Start of Linux / Unix defines
time);
} else if (xdnd.version >= 2) {
XEvent reply = { ClientMessage };
- reply.xclient.window = xdnd.source;
- reply.xclient.message_type = XdndFinished;
- reply.xclient.format = 32;
- reply.xclient.data.l[0] = (long) win->src.window;
- reply.xclient.data.l[1] = 0;
- reply.xclient.data.l[2] = None;
XSendEvent((Display*) win->src.display, xdnd.source,
False, NoEventMask, &reply);
@@ -3125,11 +3126,7 @@ Start of Linux / Unix defines
XFree(data);
if (xdnd.version >= 2) {
- XEvent reply = { ClientMessage };
- reply.xclient.window = xdnd.source;
reply.xclient.message_type = XdndFinished;
- reply.xclient.format = 32;
- reply.xclient.data.l[0] = (long) win->src.window;
reply.xclient.data.l[1] = result;
reply.xclient.data.l[2] = XdndActionCopy;
@@ -3480,7 +3477,7 @@ Start of Linux / Unix defines
*size = sizeN;
return s;
- }
+ }
/*
almost all of this function is sourced from GLFW
@@ -3520,9 +3517,6 @@ Start of Linux / Unix defines
XEvent reply = { SelectionNotify };
reply.xselection.property = 0;
- const Atom formats[] = { UTF8_STRING, XA_STRING };
- const i32 formatCount = sizeof(formats) / sizeof(formats[0]);
-
if (request->target == TARGETS) {
const Atom targets[] = { TARGETS,
MULTIPLE,
@@ -3552,15 +3546,7 @@ Start of Linux / Unix defines
unsigned long i;
for (i = 0; i < (u32)count; i += 2) {
- i32 j;
-
- for (j = 0; j < formatCount; j++) {
- if (targets[i] == formats[j])
- break;
- }
-
- if (j < formatCount)
- {
+ if (targets[i] == UTF8_STRING || targets[i] == XA_STRING) {
XChangeProperty((Display*) RGFW_root->src.display,
request->requestor,
targets[i + 1],
@@ -3727,32 +3713,54 @@ Start of Linux / Unix defines
RGFW_monitor monitor;
Display* display = XOpenDisplay(NULL);
+
+ RGFW_area size = RGFW_getScreenSize();
- monitor.rect = RGFW_RECT(0, 0, DisplayWidth(display, screen), DisplayHeight(display, screen));
- monitor.physW = (monitor.rect.w * 25.4f / 96.f);
- monitor.physH = (monitor.rect.h * 25.4f / 96.f);
-
- strncpy(monitor.name, DisplayString(display), 128);
-
+ monitor.rect = RGFW_RECT(0, 0, size.w, size.h);
+ monitor.physW = DisplayWidthMM(display, screen);
+ monitor.physH = DisplayHeightMM(display, screen);
+
XGetSystemContentScale(display, &monitor.scaleX, &monitor.scaleY);
-
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen));
XRRCrtcInfo* ci = NULL;
- int crtc = 0;
+ int crtc = screen;
if (sr->ncrtc > crtc) {
ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]);
}
-
+
if (ci == NULL) {
+ float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4));
+ float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4));
+
+ monitor.scaleX = (float) (dpi_width) / (float) 96;
+ monitor.scaleY = (float) (dpi_height) / (float) 96;
XRRFreeScreenResources(sr);
XCloseDisplay(display);
return monitor;
}
+
+ XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]);
+ monitor.physW = info->mm_width;
+ monitor.physH = info->mm_height;
monitor.rect.x = ci->x;
monitor.rect.y = ci->y;
+ monitor.rect.w = ci->width;
+ monitor.rect.h = ci->height;
+
+ float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4));
+ float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4));
+
+ monitor.scaleX = (float) (dpi_width) / (float) 96;
+ monitor.scaleY = (float) (dpi_height) / (float) 96;
+
+ if (monitor.scaleX > 1 && monitor.scaleX < 1.1)
+ monitor.scaleX = 1;
+
+ if (monitor.scaleY > 1 && monitor.scaleY < 1.1)
+ monitor.scaleY = 1;
XRRFreeCrtcInfo(ci);
XRRFreeScreenResources(sr);
@@ -4150,9 +4158,6 @@ RGFW_Event RGFW_eventPipe_pop(RGFW_window* win) {
if (win->src.eventLen >= 0)
ev = win->src.events[win->src.eventLen];
- else {
- printf("H2\n");
- }
return ev;
}
@@ -4675,6 +4680,10 @@ static const struct wl_callback_listener wl_surface_frame_listener = {
decoration_manager, win->src.xdg_toplevel);
}
+ if (args & RGFW_CENTER) {
+ RGFW_area screenR = RGFW_getScreenSize();
+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
+ }
if (args & RGFW_OPENGL_SOFTWARE)
setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
@@ -5007,6 +5016,10 @@ static const struct wl_callback_listener wl_surface_frame_listener = {
#include
#include
+ #include
+
+ __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar);
+
#ifndef RGFW_NO_XINPUT
typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
PFN_XInputGetState XInputGetStateSRC = NULL;
@@ -5224,14 +5237,15 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
}
void RGFW_releaseCursor(RGFW_window* win) {
+ RGFW_UNUSED(win);
ClipCursor(NULL);
const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL };
RegisterRawInputDevices(&id, 1, sizeof(id));
}
void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) {
- RGFW_UNUSED(win)
-
+ RGFW_UNUSED(win); RGFW_UNUSED(rect);
+
RECT clipRect;
GetClientRect(win->src.window, &clipRect);
ClientToScreen(win->src.window, (POINT*) &clipRect.left);
@@ -5252,6 +5266,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
if (RGFW_Shcore_dll == NULL) {
RGFW_Shcore_dll = LoadLibraryA("shcore.dll");
GetDpiForMonitorSRC = (PFN_GetDpiForMonitor)(void*)GetProcAddress(RGFW_Shcore_dll, "GetDpiForMonitor");
+ SetProcessDPIAware();
}
#endif
@@ -5286,7 +5301,10 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
WNDCLASSA Class = { };
#endif
- Class.lpszClassName = name;
+ if (RGFW_className == NULL)
+ RGFW_className = (char*)name;
+
+ Class.lpszClassName = RGFW_className;
Class.hInstance = inh;
Class.hCursor = LoadCursor(NULL, IDC_ARROW);
Class.lpfnWndProc = WndProc;
@@ -5499,6 +5517,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
if (args & RGFW_SCALE_TO_MONITOR)
RGFW_window_scaleToMonitor(win);
#endif
+
+ if (args & RGFW_CENTER) {
+ RGFW_area screenR = RGFW_getScreenSize();
+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
+ }
#ifdef RGFW_EGL
if ((args & RGFW_NO_INIT_API) == 0)
@@ -6100,7 +6123,8 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
if (GetDpiForMonitor != NULL) {
u32 x, y;
- GetDpiForMonitor(src, MDT_ANGULAR_DPI, &x, &y);
+ GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y);
+
monitor.scaleX = (float) (x) / (float) USER_DEFAULT_SCREEN_DPI;
monitor.scaleY = (float) (y) / (float) USER_DEFAULT_SCREEN_DPI;
}
@@ -6115,7 +6139,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
/* Calculate physical height in inches */
monitor.physW = GetSystemMetrics(SM_CYSCREEN) / (float) ppiX;
monitor.physH = GetSystemMetrics(SM_CXSCREEN) / (float) ppiY;
-
+
return monitor;
}
#endif /* RGFW_NO_MONITOR */
@@ -6150,7 +6174,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
RGFW_mInfo info;
info.iIndex = 0;
while (EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info));
-
+
return RGFW_monitors;
}
@@ -7102,7 +7126,6 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
for (int i = 0; i < count; i++) {
id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
- // printf("File: %s\n", filePath);
strncpy(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH);
win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
}
@@ -7206,6 +7229,16 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
#endif
}
+
+ void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) {
+ objc_msgSend_void_id(win->src.view, sel_registerName("setLayer"), layer);
+ }
+
+ void* RGFW_cocoaGetLayer(void) {
+ return objc_msgSend_class(objc_getClass("CAMetalLayer"), sel_registerName("layer"));
+ }
+
+
NSPasteboardType const NSPasteboardTypeURL = "public.url";
NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url";
@@ -7261,6 +7294,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
NSString* str = NSString_stringWithUTF8String(name);
objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str);
+#ifdef RGFW_EGL
+ if ((args & RGFW_NO_INIT_API) == 0)
+ RGFW_createOpenGLContext(win);
+#endif
+
#ifdef RGFW_OPENGL
if ((args & RGFW_NO_INIT_API) == 0) {
void* attrs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE);
@@ -7327,6 +7365,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
RGFW_window_scaleToMonitor(win);
#endif
+ if (args & RGFW_CENTER) {
+ RGFW_area screenR = RGFW_getScreenSize();
+ RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
+ }
+
if (args & RGFW_HIDE_MOUSE)
RGFW_window_showMouse(win, 0);
@@ -7933,6 +7976,7 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
}
void RGFW_releaseCursor(RGFW_window* win) {
+ RGFW_UNUSED(win);
CGAssociateMouseAndMouseCursorPosition(1);
}
@@ -7992,13 +8036,11 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
monitor.rect = RGFW_RECT((int) bounds.origin.x, (int) bounds.origin.y, (int) bounds.size.width, (int) bounds.size.height);
CGSize screenSizeMM = CGDisplayScreenSize(display);
- monitor.physW = screenSizeMM.width / 25.4;
- monitor.physH = screenSizeMM.height / 25.4;
+ monitor.physW = screenSizeMM.width;
+ monitor.physH = screenSizeMM.height;
- monitor.scaleX = (monitor.rect.w / (screenSizeMM.width)) / 2.6;
- monitor.scaleY = (monitor.rect.h / (screenSizeMM.height)) / 2.6;
-
- snprintf(monitor.name, 128, "%i %i %i", CGDisplayModelNumber(display), CGDisplayVendorNumber(display), CGDisplaySerialNumber(display));
+ monitor.scaleX = ((monitor.rect.w / (screenSizeMM.width / 25.4)) / 96) + 0.25;
+ monitor.scaleY = ((monitor.rect.h / (screenSizeMM.height / 25.4)) / 96) + 0.25;
return monitor;
}
@@ -8088,6 +8130,8 @@ RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
#if defined(RGFW_OPENGL)
NSOpenGLContext_setValues(win->src.ctx, &swapInterval, 222);
+ #else
+ RGFW_UNUSED(swapInterval);
#endif
}
#endif
@@ -8530,7 +8574,7 @@ RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
emscripten_webgl_make_context_current(win->src.ctx);
#ifdef LEGACY_GL_EMULATION
- EM_ASM("Module.useWebGL = true; GLImmediate.init();");
+ EM_ASM("Module.useWebGL = true; GLImmediate.init();");
#endif
emscripten_set_canvas_element_size("#canvas", rect.w, rect.h);
@@ -8873,11 +8917,12 @@ u64 RGFW_getTime(void) {
}
void RGFW_releaseCursor(RGFW_window* win) {
+ RGFW_UNUSED(win);
emscripten_exit_pointerlock();
}
void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
- RGFW_UNUSED(win)
+ RGFW_UNUSED(win); RGFW_UNUSED(r);
emscripten_request_pointerlock("#canvas", 1);
}
diff --git a/src/external/glfw/src/mappings.h b/src/external/glfw/src/mappings.h
index 270fa4cd8..7b0f35a26 100644
--- a/src/external/glfw/src/mappings.h
+++ b/src/external/glfw/src/mappings.h
@@ -996,6 +996,7 @@ const char* _glfwDefaultMappings[] =
"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,",
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
+"03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,",
#endif // GLFW_BUILD_LINUX_JOYSTICK
};
diff --git a/src/external/nanosvg.h b/src/external/nanosvg.h
deleted file mode 100644
index b80f540ba..000000000
--- a/src/external/nanosvg.h
+++ /dev/null
@@ -1,3053 +0,0 @@
-/*
- * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- *
- * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example
- * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/)
- *
- * Arc calculation code based on canvg (https://code.google.com/p/canvg/)
- *
- * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
- *
- */
-
-#ifndef NANOSVG_H
-#define NANOSVG_H
-
-#ifndef NANOSVG_CPLUSPLUS
-#ifdef __cplusplus
-extern "C" {
-#endif
-#endif
-
-// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
-//
-// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game.
-//
-// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request!
-//
-// The shapes in the SVG images are transformed by the viewBox and converted to specified units.
-// That is, you should get the same looking data as your designed in your favorite app.
-//
-// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
-// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
-//
-// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
-// DPI (dots-per-inch) controls how the unit conversion is done.
-//
-// If you don't know or care about the units stuff, "px" and 96 should get you going.
-
-
-/* Example Usage:
- // Load SVG
- NSVGimage* image;
- image = nsvgParseFromFile("test.svg", "px", 96);
- printf("size: %f x %f\n", image->width, image->height);
- // Use...
- for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) {
- for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {
- for (int i = 0; i < path->npts-1; i += 3) {
- float* p = &path->pts[i*2];
- drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
- }
- }
- }
- // Delete
- nsvgDelete(image);
-*/
-
-enum NSVGpaintType {
- NSVG_PAINT_NONE = 0,
- NSVG_PAINT_COLOR = 1,
- NSVG_PAINT_LINEAR_GRADIENT = 2,
- NSVG_PAINT_RADIAL_GRADIENT = 3
-};
-
-enum NSVGspreadType {
- NSVG_SPREAD_PAD = 0,
- NSVG_SPREAD_REFLECT = 1,
- NSVG_SPREAD_REPEAT = 2
-};
-
-enum NSVGlineJoin {
- NSVG_JOIN_MITER = 0,
- NSVG_JOIN_ROUND = 1,
- NSVG_JOIN_BEVEL = 2
-};
-
-enum NSVGlineCap {
- NSVG_CAP_BUTT = 0,
- NSVG_CAP_ROUND = 1,
- NSVG_CAP_SQUARE = 2
-};
-
-enum NSVGfillRule {
- NSVG_FILLRULE_NONZERO = 0,
- NSVG_FILLRULE_EVENODD = 1
-};
-
-enum NSVGflags {
- NSVG_FLAGS_VISIBLE = 0x01
-};
-
-typedef struct NSVGgradientStop {
- unsigned int color;
- float offset;
-} NSVGgradientStop;
-
-typedef struct NSVGgradient {
- float xform[6];
- char spread;
- float fx, fy;
- int nstops;
- NSVGgradientStop stops[1];
-} NSVGgradient;
-
-typedef struct NSVGpaint {
- char type;
- union {
- unsigned int color;
- NSVGgradient* gradient;
- };
-} NSVGpaint;
-
-typedef struct NSVGpath
-{
- float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
- int npts; // Total number of bezier points.
- char closed; // Flag indicating if shapes should be treated as closed.
- float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
- struct NSVGpath* next; // Pointer to next path, or NULL if last element.
-} NSVGpath;
-
-typedef struct NSVGshape
-{
- char id[64]; // Optional 'id' attr of the shape or its group
- NSVGpaint fill; // Fill paint
- NSVGpaint stroke; // Stroke paint
- float opacity; // Opacity of the shape.
- float strokeWidth; // Stroke width (scaled).
- float strokeDashOffset; // Stroke dash offset (scaled).
- float strokeDashArray[8]; // Stroke dash array (scaled).
- char strokeDashCount; // Number of dash values in dash array.
- char strokeLineJoin; // Stroke join type.
- char strokeLineCap; // Stroke cap type.
- float miterLimit; // Miter limit
- char fillRule; // Fill rule, see NSVGfillRule.
- unsigned char flags; // Logical or of NSVG_FLAGS_* flags
- float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
- NSVGpath* paths; // Linked list of paths in the image.
- struct NSVGshape* next; // Pointer to next shape, or NULL if last element.
-} NSVGshape;
-
-typedef struct NSVGimage
-{
- float width; // Width of the image.
- float height; // Height of the image.
- NSVGshape* shapes; // Linked list of shapes in the image.
-} NSVGimage;
-
-// Parses SVG file from a file, returns SVG image as paths.
-NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi);
-
-// Parses SVG file from a null terminated string, returns SVG image as paths.
-// Important note: changes the string.
-NSVGimage* nsvgParse(char* input, const char* units, float dpi);
-
-// Duplicates a path.
-NSVGpath* nsvgDuplicatePath(NSVGpath* p);
-
-// Deletes an image.
-void nsvgDelete(NSVGimage* image);
-
-#ifndef NANOSVG_CPLUSPLUS
-#ifdef __cplusplus
-}
-#endif
-#endif
-
-#ifdef NANOSVG_IMPLEMENTATION
-
-#include
-#include
-#include
-#include
-
-#define NSVG_PI (3.14159265358979323846264338327f)
-#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs.
-
-#define NSVG_ALIGN_MIN 0
-#define NSVG_ALIGN_MID 1
-#define NSVG_ALIGN_MAX 2
-#define NSVG_ALIGN_NONE 0
-#define NSVG_ALIGN_MEET 1
-#define NSVG_ALIGN_SLICE 2
-
-#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0)
-#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16))
-
-#ifdef _MSC_VER
- #pragma warning (disable: 4996) // Switch off security warnings
- #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings
- #ifdef __cplusplus
- #define NSVG_INLINE inline
- #else
- #define NSVG_INLINE
- #endif
-#else
- #define NSVG_INLINE inline
-#endif
-
-
-static int nsvg__isspace(char c)
-{
- return strchr(" \t\n\v\f\r", c) != 0;
-}
-
-static int nsvg__isdigit(char c)
-{
- return c >= '0' && c <= '9';
-}
-
-static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; }
-static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; }
-
-
-// Simple XML parser
-
-#define NSVG_XML_TAG 1
-#define NSVG_XML_CONTENT 2
-#define NSVG_XML_MAX_ATTRIBS 256
-
-static void nsvg__parseContent(char* s,
- void (*contentCb)(void* ud, const char* s),
- void* ud)
-{
- // Trim start white spaces
- while (*s && nsvg__isspace(*s)) s++;
- if (!*s) return;
-
- if (contentCb)
- (*contentCb)(ud, s);
-}
-
-static void nsvg__parseElement(char* s,
- void (*startelCb)(void* ud, const char* el, const char** attr),
- void (*endelCb)(void* ud, const char* el),
- void* ud)
-{
- const char* attr[NSVG_XML_MAX_ATTRIBS];
- int nattr = 0;
- char* name;
- int start = 0;
- int end = 0;
- char quote;
-
- // Skip white space after the '<'
- while (*s && nsvg__isspace(*s)) s++;
-
- // Check if the tag is end tag
- if (*s == '/') {
- s++;
- end = 1;
- } else {
- start = 1;
- }
-
- // Skip comments, data and preprocessor stuff.
- if (!*s || *s == '?' || *s == '!')
- return;
-
- // Get tag name
- name = s;
- while (*s && !nsvg__isspace(*s)) s++;
- if (*s) { *s++ = '\0'; }
-
- // Get attribs
- while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
- char* name = NULL;
- char* value = NULL;
-
- // Skip white space before the attrib name
- while (*s && nsvg__isspace(*s)) s++;
- if (!*s) break;
- if (*s == '/') {
- end = 1;
- break;
- }
- name = s;
- // Find end of the attrib name.
- while (*s && !nsvg__isspace(*s) && *s != '=') s++;
- if (*s) { *s++ = '\0'; }
- // Skip until the beginning of the value.
- while (*s && *s != '\"' && *s != '\'') s++;
- if (!*s) break;
- quote = *s;
- s++;
- // Store value and find the end of it.
- value = s;
- while (*s && *s != quote) s++;
- if (*s) { *s++ = '\0'; }
-
- // Store only well formed attributes
- if (name && value) {
- attr[nattr++] = name;
- attr[nattr++] = value;
- }
- }
-
- // List terminator
- attr[nattr++] = 0;
- attr[nattr++] = 0;
-
- // Call callbacks.
- if (start && startelCb)
- (*startelCb)(ud, name, attr);
- if (end && endelCb)
- (*endelCb)(ud, name);
-}
-
-int nsvg__parseXML(char* input,
- void (*startelCb)(void* ud, const char* el, const char** attr),
- void (*endelCb)(void* ud, const char* el),
- void (*contentCb)(void* ud, const char* s),
- void* ud)
-{
- char* s = input;
- char* mark = s;
- int state = NSVG_XML_CONTENT;
- while (*s) {
- if (*s == '<' && state == NSVG_XML_CONTENT) {
- // Start of a tag
- *s++ = '\0';
- nsvg__parseContent(mark, contentCb, ud);
- mark = s;
- state = NSVG_XML_TAG;
- } else if (*s == '>' && state == NSVG_XML_TAG) {
- // Start of a content or new tag.
- *s++ = '\0';
- nsvg__parseElement(mark, startelCb, endelCb, ud);
- mark = s;
- state = NSVG_XML_CONTENT;
- } else {
- s++;
- }
- }
-
- return 1;
-}
-
-
-/* Simple SVG parser. */
-
-#define NSVG_MAX_ATTR 128
-
-enum NSVGgradientUnits {
- NSVG_USER_SPACE = 0,
- NSVG_OBJECT_SPACE = 1
-};
-
-#define NSVG_MAX_DASHES 8
-
-enum NSVGunits {
- NSVG_UNITS_USER,
- NSVG_UNITS_PX,
- NSVG_UNITS_PT,
- NSVG_UNITS_PC,
- NSVG_UNITS_MM,
- NSVG_UNITS_CM,
- NSVG_UNITS_IN,
- NSVG_UNITS_PERCENT,
- NSVG_UNITS_EM,
- NSVG_UNITS_EX
-};
-
-typedef struct NSVGcoordinate {
- float value;
- int units;
-} NSVGcoordinate;
-
-typedef struct NSVGlinearData {
- NSVGcoordinate x1, y1, x2, y2;
-} NSVGlinearData;
-
-typedef struct NSVGradialData {
- NSVGcoordinate cx, cy, r, fx, fy;
-} NSVGradialData;
-
-typedef struct NSVGgradientData
-{
- char id[64];
- char ref[64];
- char type;
- union {
- NSVGlinearData linear;
- NSVGradialData radial;
- };
- char spread;
- char units;
- float xform[6];
- int nstops;
- NSVGgradientStop* stops;
- struct NSVGgradientData* next;
-} NSVGgradientData;
-
-typedef struct NSVGattrib
-{
- char id[64];
- float xform[6];
- unsigned int fillColor;
- unsigned int strokeColor;
- float opacity;
- float fillOpacity;
- float strokeOpacity;
- char fillGradient[64];
- char strokeGradient[64];
- float strokeWidth;
- float strokeDashOffset;
- float strokeDashArray[NSVG_MAX_DASHES];
- int strokeDashCount;
- char strokeLineJoin;
- char strokeLineCap;
- float miterLimit;
- char fillRule;
- float fontSize;
- unsigned int stopColor;
- float stopOpacity;
- float stopOffset;
- char hasFill;
- char hasStroke;
- char visible;
-} NSVGattrib;
-
-typedef struct NSVGparser
-{
- NSVGattrib attr[NSVG_MAX_ATTR];
- int attrHead;
- float* pts;
- int npts;
- int cpts;
- NSVGpath* plist;
- NSVGimage* image;
- NSVGgradientData* gradients;
- NSVGshape* shapesTail;
- float viewMinx, viewMiny, viewWidth, viewHeight;
- int alignX, alignY, alignType;
- float dpi;
- char pathFlag;
- char defsFlag;
-} NSVGparser;
-
-static void nsvg__xformIdentity(float* t)
-{
- t[0] = 1.0f; t[1] = 0.0f;
- t[2] = 0.0f; t[3] = 1.0f;
- t[4] = 0.0f; t[5] = 0.0f;
-}
-
-static void nsvg__xformSetTranslation(float* t, float tx, float ty)
-{
- t[0] = 1.0f; t[1] = 0.0f;
- t[2] = 0.0f; t[3] = 1.0f;
- t[4] = tx; t[5] = ty;
-}
-
-static void nsvg__xformSetScale(float* t, float sx, float sy)
-{
- t[0] = sx; t[1] = 0.0f;
- t[2] = 0.0f; t[3] = sy;
- t[4] = 0.0f; t[5] = 0.0f;
-}
-
-static void nsvg__xformSetSkewX(float* t, float a)
-{
- t[0] = 1.0f; t[1] = 0.0f;
- t[2] = tanf(a); t[3] = 1.0f;
- t[4] = 0.0f; t[5] = 0.0f;
-}
-
-static void nsvg__xformSetSkewY(float* t, float a)
-{
- t[0] = 1.0f; t[1] = tanf(a);
- t[2] = 0.0f; t[3] = 1.0f;
- t[4] = 0.0f; t[5] = 0.0f;
-}
-
-static void nsvg__xformSetRotation(float* t, float a)
-{
- float cs = cosf(a), sn = sinf(a);
- t[0] = cs; t[1] = sn;
- t[2] = -sn; t[3] = cs;
- t[4] = 0.0f; t[5] = 0.0f;
-}
-
-static void nsvg__xformMultiply(float* t, float* s)
-{
- float t0 = t[0] * s[0] + t[1] * s[2];
- float t2 = t[2] * s[0] + t[3] * s[2];
- float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
- t[1] = t[0] * s[1] + t[1] * s[3];
- t[3] = t[2] * s[1] + t[3] * s[3];
- t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
- t[0] = t0;
- t[2] = t2;
- t[4] = t4;
-}
-
-static void nsvg__xformInverse(float* inv, float* t)
-{
- double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1];
- if (det > -1e-6 && det < 1e-6) {
- nsvg__xformIdentity(t);
- return;
- }
- invdet = 1.0 / det;
- inv[0] = (float)(t[3] * invdet);
- inv[2] = (float)(-t[2] * invdet);
- inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);
- inv[1] = (float)(-t[1] * invdet);
- inv[3] = (float)(t[0] * invdet);
- inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);
-}
-
-static void nsvg__xformPremultiply(float* t, float* s)
-{
- float s2[6];
- memcpy(s2, s, sizeof(float)*6);
- nsvg__xformMultiply(s2, t);
- memcpy(t, s2, sizeof(float)*6);
-}
-
-static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t)
-{
- *dx = x*t[0] + y*t[2] + t[4];
- *dy = x*t[1] + y*t[3] + t[5];
-}
-
-static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t)
-{
- *dx = x*t[0] + y*t[2];
- *dy = x*t[1] + y*t[3];
-}
-
-#define NSVG_EPSILON (1e-12)
-
-static int nsvg__ptInBounds(float* pt, float* bounds)
-{
- return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3];
-}
-
-
-static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3)
-{
- double it = 1.0-t;
- return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3;
-}
-
-static void nsvg__curveBounds(float* bounds, float* curve)
-{
- int i, j, count;
- double roots[2], a, b, c, b2ac, t, v;
- float* v0 = &curve[0];
- float* v1 = &curve[2];
- float* v2 = &curve[4];
- float* v3 = &curve[6];
-
- // Start the bounding box by end points
- bounds[0] = nsvg__minf(v0[0], v3[0]);
- bounds[1] = nsvg__minf(v0[1], v3[1]);
- bounds[2] = nsvg__maxf(v0[0], v3[0]);
- bounds[3] = nsvg__maxf(v0[1], v3[1]);
-
- // Bezier curve fits inside the convex hull of it's control points.
- // If control points are inside the bounds, we're done.
- if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds))
- return;
-
- // Add bezier curve inflection points in X and Y.
- for (i = 0; i < 2; i++) {
- a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i];
- b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i];
- c = 3.0 * v1[i] - 3.0 * v0[i];
- count = 0;
- if (fabs(a) < NSVG_EPSILON) {
- if (fabs(b) > NSVG_EPSILON) {
- t = -c / b;
- if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
- roots[count++] = t;
- }
- } else {
- b2ac = b*b - 4.0*c*a;
- if (b2ac > NSVG_EPSILON) {
- t = (-b + sqrt(b2ac)) / (2.0 * a);
- if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
- roots[count++] = t;
- t = (-b - sqrt(b2ac)) / (2.0 * a);
- if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
- roots[count++] = t;
- }
- }
- for (j = 0; j < count; j++) {
- v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]);
- bounds[0+i] = nsvg__minf(bounds[0+i], (float)v);
- bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v);
- }
- }
-}
-
-static NSVGparser* nsvg__createParser(void)
-{
- NSVGparser* p;
- p = (NSVGparser*)malloc(sizeof(NSVGparser));
- if (p == NULL) goto error;
- memset(p, 0, sizeof(NSVGparser));
-
- p->image = (NSVGimage*)malloc(sizeof(NSVGimage));
- if (p->image == NULL) goto error;
- memset(p->image, 0, sizeof(NSVGimage));
-
- // Init style
- nsvg__xformIdentity(p->attr[0].xform);
- memset(p->attr[0].id, 0, sizeof p->attr[0].id);
- p->attr[0].fillColor = NSVG_RGB(0,0,0);
- p->attr[0].strokeColor = NSVG_RGB(0,0,0);
- p->attr[0].opacity = 1;
- p->attr[0].fillOpacity = 1;
- p->attr[0].strokeOpacity = 1;
- p->attr[0].stopOpacity = 1;
- p->attr[0].strokeWidth = 1;
- p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
- p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
- p->attr[0].miterLimit = 4;
- p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
- p->attr[0].hasFill = 1;
- p->attr[0].visible = 1;
-
- return p;
-
-error:
- if (p) {
- if (p->image) free(p->image);
- free(p);
- }
- return NULL;
-}
-
-static void nsvg__deletePaths(NSVGpath* path)
-{
- while (path) {
- NSVGpath *next = path->next;
- if (path->pts != NULL)
- free(path->pts);
- free(path);
- path = next;
- }
-}
-
-static void nsvg__deletePaint(NSVGpaint* paint)
-{
- if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT)
- free(paint->gradient);
-}
-
-static void nsvg__deleteGradientData(NSVGgradientData* grad)
-{
- NSVGgradientData* next;
- while (grad != NULL) {
- next = grad->next;
- free(grad->stops);
- free(grad);
- grad = next;
- }
-}
-
-static void nsvg__deleteParser(NSVGparser* p)
-{
- if (p != NULL) {
- nsvg__deletePaths(p->plist);
- nsvg__deleteGradientData(p->gradients);
- nsvgDelete(p->image);
- free(p->pts);
- free(p);
- }
-}
-
-static void nsvg__resetPath(NSVGparser* p)
-{
- p->npts = 0;
-}
-
-static void nsvg__addPoint(NSVGparser* p, float x, float y)
-{
- if (p->npts+1 > p->cpts) {
- p->cpts = p->cpts ? p->cpts*2 : 8;
- p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float));
- if (!p->pts) return;
- }
- p->pts[p->npts*2+0] = x;
- p->pts[p->npts*2+1] = y;
- p->npts++;
-}
-
-static void nsvg__moveTo(NSVGparser* p, float x, float y)
-{
- if (p->npts > 0) {
- p->pts[(p->npts-1)*2+0] = x;
- p->pts[(p->npts-1)*2+1] = y;
- } else {
- nsvg__addPoint(p, x, y);
- }
-}
-
-static void nsvg__lineTo(NSVGparser* p, float x, float y)
-{
- float px,py, dx,dy;
- if (p->npts > 0) {
- px = p->pts[(p->npts-1)*2+0];
- py = p->pts[(p->npts-1)*2+1];
- dx = x - px;
- dy = y - py;
- nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f);
- nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f);
- nsvg__addPoint(p, x, y);
- }
-}
-
-static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y)
-{
- if (p->npts > 0) {
- nsvg__addPoint(p, cpx1, cpy1);
- nsvg__addPoint(p, cpx2, cpy2);
- nsvg__addPoint(p, x, y);
- }
-}
-
-static NSVGattrib* nsvg__getAttr(NSVGparser* p)
-{
- return &p->attr[p->attrHead];
-}
-
-static void nsvg__pushAttr(NSVGparser* p)
-{
- if (p->attrHead < NSVG_MAX_ATTR-1) {
- p->attrHead++;
- memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib));
- }
-}
-
-static void nsvg__popAttr(NSVGparser* p)
-{
- if (p->attrHead > 0)
- p->attrHead--;
-}
-
-static float nsvg__actualOrigX(NSVGparser* p)
-{
- return p->viewMinx;
-}
-
-static float nsvg__actualOrigY(NSVGparser* p)
-{
- return p->viewMiny;
-}
-
-static float nsvg__actualWidth(NSVGparser* p)
-{
- return p->viewWidth;
-}
-
-static float nsvg__actualHeight(NSVGparser* p)
-{
- return p->viewHeight;
-}
-
-static float nsvg__actualLength(NSVGparser* p)
-{
- float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p);
- return sqrtf(w*w + h*h) / sqrtf(2.0f);
-}
-
-static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length)
-{
- NSVGattrib* attr = nsvg__getAttr(p);
- switch (c.units) {
- case NSVG_UNITS_USER: return c.value;
- case NSVG_UNITS_PX: return c.value;
- case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi;
- case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi;
- case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi;
- case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi;
- case NSVG_UNITS_IN: return c.value * p->dpi;
- case NSVG_UNITS_EM: return c.value * attr->fontSize;
- case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica.
- case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length;
- default: return c.value;
- }
- return c.value;
-}
-
-static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
-{
- NSVGgradientData* grad = p->gradients;
- if (id == NULL || *id == '\0')
- return NULL;
- while (grad != NULL) {
- if (strcmp(grad->id, id) == 0)
- return grad;
- grad = grad->next;
- }
- return NULL;
-}
-
-static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType)
-{
- NSVGattrib* attr = nsvg__getAttr(p);
- NSVGgradientData* data = NULL;
- NSVGgradientData* ref = NULL;
- NSVGgradientStop* stops = NULL;
- NSVGgradient* grad;
- float ox, oy, sw, sh, sl;
- int nstops = 0;
- int refIter;
-
- data = nsvg__findGradientData(p, id);
- if (data == NULL) return NULL;
-
- // TODO: use ref to fill in all unset values too.
- ref = data;
- refIter = 0;
- while (ref != NULL) {
- NSVGgradientData* nextRef = NULL;
- if (stops == NULL && ref->stops != NULL) {
- stops = ref->stops;
- nstops = ref->nstops;
- break;
- }
- nextRef = nsvg__findGradientData(p, ref->ref);
- if (nextRef == ref) break; // prevent infite loops on malformed data
- ref = nextRef;
- refIter++;
- if (refIter > 32) break; // prevent infite loops on malformed data
- }
- if (stops == NULL) return NULL;
-
- grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1));
- if (grad == NULL) return NULL;
-
- // The shape width and height.
- if (data->units == NSVG_OBJECT_SPACE) {
- ox = localBounds[0];
- oy = localBounds[1];
- sw = localBounds[2] - localBounds[0];
- sh = localBounds[3] - localBounds[1];
- } else {
- ox = nsvg__actualOrigX(p);
- oy = nsvg__actualOrigY(p);
- sw = nsvg__actualWidth(p);
- sh = nsvg__actualHeight(p);
- }
- sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f);
-
- if (data->type == NSVG_PAINT_LINEAR_GRADIENT) {
- float x1, y1, x2, y2, dx, dy;
- x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw);
- y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh);
- x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw);
- y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh);
- // Calculate transform aligned to the line
- dx = x2 - x1;
- dy = y2 - y1;
- grad->xform[0] = dy; grad->xform[1] = -dx;
- grad->xform[2] = dx; grad->xform[3] = dy;
- grad->xform[4] = x1; grad->xform[5] = y1;
- } else {
- float cx, cy, fx, fy, r;
- cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw);
- cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh);
- fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw);
- fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh);
- r = nsvg__convertToPixels(p, data->radial.r, 0, sl);
- // Calculate transform aligned to the circle
- grad->xform[0] = r; grad->xform[1] = 0;
- grad->xform[2] = 0; grad->xform[3] = r;
- grad->xform[4] = cx; grad->xform[5] = cy;
- grad->fx = fx / r;
- grad->fy = fy / r;
- }
-
- nsvg__xformMultiply(grad->xform, data->xform);
- nsvg__xformMultiply(grad->xform, attr->xform);
-
- grad->spread = data->spread;
- memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop));
- grad->nstops = nstops;
-
- *paintType = data->type;
-
- return grad;
-}
-
-static float nsvg__getAverageScale(float* t)
-{
- float sx = sqrtf(t[0]*t[0] + t[2]*t[2]);
- float sy = sqrtf(t[1]*t[1] + t[3]*t[3]);
- return (sx + sy) * 0.5f;
-}
-
-static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform)
-{
- NSVGpath* path;
- float curve[4*2], curveBounds[4];
- int i, first = 1;
- for (path = shape->paths; path != NULL; path = path->next) {
- nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform);
- for (i = 0; i < path->npts-1; i += 3) {
- nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform);
- nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform);
- nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform);
- nsvg__curveBounds(curveBounds, curve);
- if (first) {
- bounds[0] = curveBounds[0];
- bounds[1] = curveBounds[1];
- bounds[2] = curveBounds[2];
- bounds[3] = curveBounds[3];
- first = 0;
- } else {
- bounds[0] = nsvg__minf(bounds[0], curveBounds[0]);
- bounds[1] = nsvg__minf(bounds[1], curveBounds[1]);
- bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]);
- bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]);
- }
- curve[0] = curve[6];
- curve[1] = curve[7];
- }
- }
-}
-
-static void nsvg__addShape(NSVGparser* p)
-{
- NSVGattrib* attr = nsvg__getAttr(p);
- float scale = 1.0f;
- NSVGshape* shape;
- NSVGpath* path;
- int i;
-
- if (p->plist == NULL)
- return;
-
- shape = (NSVGshape*)malloc(sizeof(NSVGshape));
- if (shape == NULL) goto error;
- memset(shape, 0, sizeof(NSVGshape));
-
- memcpy(shape->id, attr->id, sizeof shape->id);
- scale = nsvg__getAverageScale(attr->xform);
- shape->strokeWidth = attr->strokeWidth * scale;
- shape->strokeDashOffset = attr->strokeDashOffset * scale;
- shape->strokeDashCount = (char)attr->strokeDashCount;
- for (i = 0; i < attr->strokeDashCount; i++)
- shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
- shape->strokeLineJoin = attr->strokeLineJoin;
- shape->strokeLineCap = attr->strokeLineCap;
- shape->miterLimit = attr->miterLimit;
- shape->fillRule = attr->fillRule;
- shape->opacity = attr->opacity;
-
- shape->paths = p->plist;
- p->plist = NULL;
-
- // Calculate shape bounds
- shape->bounds[0] = shape->paths->bounds[0];
- shape->bounds[1] = shape->paths->bounds[1];
- shape->bounds[2] = shape->paths->bounds[2];
- shape->bounds[3] = shape->paths->bounds[3];
- for (path = shape->paths->next; path != NULL; path = path->next) {
- shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]);
- shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]);
- shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]);
- shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]);
- }
-
- // Set fill
- if (attr->hasFill == 0) {
- shape->fill.type = NSVG_PAINT_NONE;
- } else if (attr->hasFill == 1) {
- shape->fill.type = NSVG_PAINT_COLOR;
- shape->fill.color = attr->fillColor;
- shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24;
- } else if (attr->hasFill == 2) {
- float inv[6], localBounds[4];
- nsvg__xformInverse(inv, attr->xform);
- nsvg__getLocalBounds(localBounds, shape, inv);
- shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type);
- if (shape->fill.gradient == NULL) {
- shape->fill.type = NSVG_PAINT_NONE;
- }
- }
-
- // Set stroke
- if (attr->hasStroke == 0) {
- shape->stroke.type = NSVG_PAINT_NONE;
- } else if (attr->hasStroke == 1) {
- shape->stroke.type = NSVG_PAINT_COLOR;
- shape->stroke.color = attr->strokeColor;
- shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24;
- } else if (attr->hasStroke == 2) {
- float inv[6], localBounds[4];
- nsvg__xformInverse(inv, attr->xform);
- nsvg__getLocalBounds(localBounds, shape, inv);
- shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type);
- if (shape->stroke.gradient == NULL)
- shape->stroke.type = NSVG_PAINT_NONE;
- }
-
- // Set flags
- shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
-
- // Add to tail
- if (p->image->shapes == NULL)
- p->image->shapes = shape;
- else
- p->shapesTail->next = shape;
- p->shapesTail = shape;
-
- return;
-
-error:
- if (shape) free(shape);
-}
-
-static void nsvg__addPath(NSVGparser* p, char closed)
-{
- NSVGattrib* attr = nsvg__getAttr(p);
- NSVGpath* path = NULL;
- float bounds[4];
- float* curve;
- int i;
-
- if (p->npts < 4)
- return;
-
- if (closed)
- nsvg__lineTo(p, p->pts[0], p->pts[1]);
-
- // Expect 1 + N*3 points (N = number of cubic bezier segments).
- if ((p->npts % 3) != 1)
- return;
-
- path = (NSVGpath*)malloc(sizeof(NSVGpath));
- if (path == NULL) goto error;
- memset(path, 0, sizeof(NSVGpath));
-
- path->pts = (float*)malloc(p->npts*2*sizeof(float));
- if (path->pts == NULL) goto error;
- path->closed = closed;
- path->npts = p->npts;
-
- // Transform path.
- for (i = 0; i < p->npts; ++i)
- nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform);
-
- // Find bounds
- for (i = 0; i < path->npts-1; i += 3) {
- curve = &path->pts[i*2];
- nsvg__curveBounds(bounds, curve);
- if (i == 0) {
- path->bounds[0] = bounds[0];
- path->bounds[1] = bounds[1];
- path->bounds[2] = bounds[2];
- path->bounds[3] = bounds[3];
- } else {
- path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]);
- path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]);
- path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]);
- path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]);
- }
- }
-
- path->next = p->plist;
- p->plist = path;
-
- return;
-
-error:
- if (path != NULL) {
- if (path->pts != NULL) free(path->pts);
- free(path);
- }
-}
-
-// We roll our own string to float because the std library one uses locale and messes things up.
-static double nsvg__atof(const char* s)
-{
- char* cur = (char*)s;
- char* end = NULL;
- double res = 0.0, sign = 1.0;
- long long intPart = 0, fracPart = 0;
- char hasIntPart = 0, hasFracPart = 0;
-
- // Parse optional sign
- if (*cur == '+') {
- cur++;
- } else if (*cur == '-') {
- sign = -1;
- cur++;
- }
-
- // Parse integer part
- if (nsvg__isdigit(*cur)) {
- // Parse digit sequence
- intPart = strtoll(cur, &end, 10);
- if (cur != end) {
- res = (double)intPart;
- hasIntPart = 1;
- cur = end;
- }
- }
-
- // Parse fractional part.
- if (*cur == '.') {
- cur++; // Skip '.'
- if (nsvg__isdigit(*cur)) {
- // Parse digit sequence
- fracPart = strtoll(cur, &end, 10);
- if (cur != end) {
- res += (double)fracPart / pow(10.0, (double)(end - cur));
- hasFracPart = 1;
- cur = end;
- }
- }
- }
-
- // A valid number should have integer or fractional part.
- if (!hasIntPart && !hasFracPart)
- return 0.0;
-
- // Parse optional exponent
- if (*cur == 'e' || *cur == 'E') {
- long expPart = 0;
- cur++; // skip 'E'
- expPart = strtol(cur, &end, 10); // Parse digit sequence with sign
- if (cur != end) {
- res *= pow(10.0, (double)expPart);
- }
- }
-
- return res * sign;
-}
-
-
-static const char* nsvg__parseNumber(const char* s, char* it, const int size)
-{
- const int last = size-1;
- int i = 0;
-
- // sign
- if (*s == '-' || *s == '+') {
- if (i < last) it[i++] = *s;
- s++;
- }
- // integer part
- while (*s && nsvg__isdigit(*s)) {
- if (i < last) it[i++] = *s;
- s++;
- }
- if (*s == '.') {
- // decimal point
- if (i < last) it[i++] = *s;
- s++;
- // fraction part
- while (*s && nsvg__isdigit(*s)) {
- if (i < last) it[i++] = *s;
- s++;
- }
- }
- // exponent
- if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
- if (i < last) it[i++] = *s;
- s++;
- if (*s == '-' || *s == '+') {
- if (i < last) it[i++] = *s;
- s++;
- }
- while (*s && nsvg__isdigit(*s)) {
- if (i < last) it[i++] = *s;
- s++;
- }
- }
- it[i] = '\0';
-
- return s;
-}
-
-static const char* nsvg__getNextPathItem(const char* s, char* it)
-{
- it[0] = '\0';
- // Skip white spaces and commas
- while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
- if (!*s) return s;
- if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) {
- s = nsvg__parseNumber(s, it, 64);
- } else {
- // Parse command
- it[0] = *s++;
- it[1] = '\0';
- return s;
- }
-
- return s;
-}
-
-static unsigned int nsvg__parseColorHex(const char* str)
-{
- unsigned int r=0, g=0, b=0;
- if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex
- return NSVG_RGB(r, g, b);
- if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa
- return NSVG_RGB(r*17, g*17, b*17); // same effect as (r<<4|r), (g<<4|g), ..
- return NSVG_RGB(128, 128, 128);
-}
-
-// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters).
-// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors
-// for backwards compatibility. Note: other image viewers return black instead.
-
-static unsigned int nsvg__parseColorRGB(const char* str)
-{
- int i;
- unsigned int rgbi[3];
- float rgbf[3];
- // try decimal integers first
- if (sscanf(str, "rgb(%u, %u, %u)", &rgbi[0], &rgbi[1], &rgbi[2]) != 3) {
- // integers failed, try percent values (float, locale independent)
- const char delimiter[3] = {',', ',', ')'};
- str += 4; // skip "rgb("
- for (i = 0; i < 3; i++) {
- while (*str && (nsvg__isspace(*str))) str++; // skip leading spaces
- if (*str == '+') str++; // skip '+' (don't allow '-')
- if (!*str) break;
- rgbf[i] = nsvg__atof(str);
-
- // Note 1: it would be great if nsvg__atof() returned how many
- // bytes it consumed but it doesn't. We need to skip the number,
- // the '%' character, spaces, and the delimiter ',' or ')'.
-
- // Note 2: The following code does not allow values like "33.%",
- // i.e. a decimal point w/o fractional part, but this is consistent
- // with other image viewers, e.g. firefox, chrome, eog, gimp.
-
- while (*str && nsvg__isdigit(*str)) str++; // skip integer part
- if (*str == '.') {
- str++;
- if (!nsvg__isdigit(*str)) break; // error: no digit after '.'
- while (*str && nsvg__isdigit(*str)) str++; // skip fractional part
- }
- if (*str == '%') str++; else break;
- while (nsvg__isspace(*str)) str++;
- if (*str == delimiter[i]) str++;
- else break;
- }
- if (i == 3) {
- rgbi[0] = roundf(rgbf[0] * 2.55f);
- rgbi[1] = roundf(rgbf[1] * 2.55f);
- rgbi[2] = roundf(rgbf[2] * 2.55f);
- } else {
- rgbi[0] = rgbi[1] = rgbi[2] = 128;
- }
- }
- // clip values as the CSS spec requires
- for (i = 0; i < 3; i++) {
- if (rgbi[i] > 255) rgbi[i] = 255;
- }
- return NSVG_RGB(rgbi[0], rgbi[1], rgbi[2]);
-}
-
-typedef struct NSVGNamedColor {
- const char* name;
- unsigned int color;
-} NSVGNamedColor;
-
-NSVGNamedColor nsvg__colors[] = {
-
- { "red", NSVG_RGB(255, 0, 0) },
- { "green", NSVG_RGB( 0, 128, 0) },
- { "blue", NSVG_RGB( 0, 0, 255) },
- { "yellow", NSVG_RGB(255, 255, 0) },
- { "cyan", NSVG_RGB( 0, 255, 255) },
- { "magenta", NSVG_RGB(255, 0, 255) },
- { "black", NSVG_RGB( 0, 0, 0) },
- { "grey", NSVG_RGB(128, 128, 128) },
- { "gray", NSVG_RGB(128, 128, 128) },
- { "white", NSVG_RGB(255, 255, 255) },
-
-#ifdef NANOSVG_ALL_COLOR_KEYWORDS
- { "aliceblue", NSVG_RGB(240, 248, 255) },
- { "antiquewhite", NSVG_RGB(250, 235, 215) },
- { "aqua", NSVG_RGB( 0, 255, 255) },
- { "aquamarine", NSVG_RGB(127, 255, 212) },
- { "azure", NSVG_RGB(240, 255, 255) },
- { "beige", NSVG_RGB(245, 245, 220) },
- { "bisque", NSVG_RGB(255, 228, 196) },
- { "blanchedalmond", NSVG_RGB(255, 235, 205) },
- { "blueviolet", NSVG_RGB(138, 43, 226) },
- { "brown", NSVG_RGB(165, 42, 42) },
- { "burlywood", NSVG_RGB(222, 184, 135) },
- { "cadetblue", NSVG_RGB( 95, 158, 160) },
- { "chartreuse", NSVG_RGB(127, 255, 0) },
- { "chocolate", NSVG_RGB(210, 105, 30) },
- { "coral", NSVG_RGB(255, 127, 80) },
- { "cornflowerblue", NSVG_RGB(100, 149, 237) },
- { "cornsilk", NSVG_RGB(255, 248, 220) },
- { "crimson", NSVG_RGB(220, 20, 60) },
- { "darkblue", NSVG_RGB( 0, 0, 139) },
- { "darkcyan", NSVG_RGB( 0, 139, 139) },
- { "darkgoldenrod", NSVG_RGB(184, 134, 11) },
- { "darkgray", NSVG_RGB(169, 169, 169) },
- { "darkgreen", NSVG_RGB( 0, 100, 0) },
- { "darkgrey", NSVG_RGB(169, 169, 169) },
- { "darkkhaki", NSVG_RGB(189, 183, 107) },
- { "darkmagenta", NSVG_RGB(139, 0, 139) },
- { "darkolivegreen", NSVG_RGB( 85, 107, 47) },
- { "darkorange", NSVG_RGB(255, 140, 0) },
- { "darkorchid", NSVG_RGB(153, 50, 204) },
- { "darkred", NSVG_RGB(139, 0, 0) },
- { "darksalmon", NSVG_RGB(233, 150, 122) },
- { "darkseagreen", NSVG_RGB(143, 188, 143) },
- { "darkslateblue", NSVG_RGB( 72, 61, 139) },
- { "darkslategray", NSVG_RGB( 47, 79, 79) },
- { "darkslategrey", NSVG_RGB( 47, 79, 79) },
- { "darkturquoise", NSVG_RGB( 0, 206, 209) },
- { "darkviolet", NSVG_RGB(148, 0, 211) },
- { "deeppink", NSVG_RGB(255, 20, 147) },
- { "deepskyblue", NSVG_RGB( 0, 191, 255) },
- { "dimgray", NSVG_RGB(105, 105, 105) },
- { "dimgrey", NSVG_RGB(105, 105, 105) },
- { "dodgerblue", NSVG_RGB( 30, 144, 255) },
- { "firebrick", NSVG_RGB(178, 34, 34) },
- { "floralwhite", NSVG_RGB(255, 250, 240) },
- { "forestgreen", NSVG_RGB( 34, 139, 34) },
- { "fuchsia", NSVG_RGB(255, 0, 255) },
- { "gainsboro", NSVG_RGB(220, 220, 220) },
- { "ghostwhite", NSVG_RGB(248, 248, 255) },
- { "gold", NSVG_RGB(255, 215, 0) },
- { "goldenrod", NSVG_RGB(218, 165, 32) },
- { "greenyellow", NSVG_RGB(173, 255, 47) },
- { "honeydew", NSVG_RGB(240, 255, 240) },
- { "hotpink", NSVG_RGB(255, 105, 180) },
- { "indianred", NSVG_RGB(205, 92, 92) },
- { "indigo", NSVG_RGB( 75, 0, 130) },
- { "ivory", NSVG_RGB(255, 255, 240) },
- { "khaki", NSVG_RGB(240, 230, 140) },
- { "lavender", NSVG_RGB(230, 230, 250) },
- { "lavenderblush", NSVG_RGB(255, 240, 245) },
- { "lawngreen", NSVG_RGB(124, 252, 0) },
- { "lemonchiffon", NSVG_RGB(255, 250, 205) },
- { "lightblue", NSVG_RGB(173, 216, 230) },
- { "lightcoral", NSVG_RGB(240, 128, 128) },
- { "lightcyan", NSVG_RGB(224, 255, 255) },
- { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) },
- { "lightgray", NSVG_RGB(211, 211, 211) },
- { "lightgreen", NSVG_RGB(144, 238, 144) },
- { "lightgrey", NSVG_RGB(211, 211, 211) },
- { "lightpink", NSVG_RGB(255, 182, 193) },
- { "lightsalmon", NSVG_RGB(255, 160, 122) },
- { "lightseagreen", NSVG_RGB( 32, 178, 170) },
- { "lightskyblue", NSVG_RGB(135, 206, 250) },
- { "lightslategray", NSVG_RGB(119, 136, 153) },
- { "lightslategrey", NSVG_RGB(119, 136, 153) },
- { "lightsteelblue", NSVG_RGB(176, 196, 222) },
- { "lightyellow", NSVG_RGB(255, 255, 224) },
- { "lime", NSVG_RGB( 0, 255, 0) },
- { "limegreen", NSVG_RGB( 50, 205, 50) },
- { "linen", NSVG_RGB(250, 240, 230) },
- { "maroon", NSVG_RGB(128, 0, 0) },
- { "mediumaquamarine", NSVG_RGB(102, 205, 170) },
- { "mediumblue", NSVG_RGB( 0, 0, 205) },
- { "mediumorchid", NSVG_RGB(186, 85, 211) },
- { "mediumpurple", NSVG_RGB(147, 112, 219) },
- { "mediumseagreen", NSVG_RGB( 60, 179, 113) },
- { "mediumslateblue", NSVG_RGB(123, 104, 238) },
- { "mediumspringgreen", NSVG_RGB( 0, 250, 154) },
- { "mediumturquoise", NSVG_RGB( 72, 209, 204) },
- { "mediumvioletred", NSVG_RGB(199, 21, 133) },
- { "midnightblue", NSVG_RGB( 25, 25, 112) },
- { "mintcream", NSVG_RGB(245, 255, 250) },
- { "mistyrose", NSVG_RGB(255, 228, 225) },
- { "moccasin", NSVG_RGB(255, 228, 181) },
- { "navajowhite", NSVG_RGB(255, 222, 173) },
- { "navy", NSVG_RGB( 0, 0, 128) },
- { "oldlace", NSVG_RGB(253, 245, 230) },
- { "olive", NSVG_RGB(128, 128, 0) },
- { "olivedrab", NSVG_RGB(107, 142, 35) },
- { "orange", NSVG_RGB(255, 165, 0) },
- { "orangered", NSVG_RGB(255, 69, 0) },
- { "orchid", NSVG_RGB(218, 112, 214) },
- { "palegoldenrod", NSVG_RGB(238, 232, 170) },
- { "palegreen", NSVG_RGB(152, 251, 152) },
- { "paleturquoise", NSVG_RGB(175, 238, 238) },
- { "palevioletred", NSVG_RGB(219, 112, 147) },
- { "papayawhip", NSVG_RGB(255, 239, 213) },
- { "peachpuff", NSVG_RGB(255, 218, 185) },
- { "peru", NSVG_RGB(205, 133, 63) },
- { "pink", NSVG_RGB(255, 192, 203) },
- { "plum", NSVG_RGB(221, 160, 221) },
- { "powderblue", NSVG_RGB(176, 224, 230) },
- { "purple", NSVG_RGB(128, 0, 128) },
- { "rosybrown", NSVG_RGB(188, 143, 143) },
- { "royalblue", NSVG_RGB( 65, 105, 225) },
- { "saddlebrown", NSVG_RGB(139, 69, 19) },
- { "salmon", NSVG_RGB(250, 128, 114) },
- { "sandybrown", NSVG_RGB(244, 164, 96) },
- { "seagreen", NSVG_RGB( 46, 139, 87) },
- { "seashell", NSVG_RGB(255, 245, 238) },
- { "sienna", NSVG_RGB(160, 82, 45) },
- { "silver", NSVG_RGB(192, 192, 192) },
- { "skyblue", NSVG_RGB(135, 206, 235) },
- { "slateblue", NSVG_RGB(106, 90, 205) },
- { "slategray", NSVG_RGB(112, 128, 144) },
- { "slategrey", NSVG_RGB(112, 128, 144) },
- { "snow", NSVG_RGB(255, 250, 250) },
- { "springgreen", NSVG_RGB( 0, 255, 127) },
- { "steelblue", NSVG_RGB( 70, 130, 180) },
- { "tan", NSVG_RGB(210, 180, 140) },
- { "teal", NSVG_RGB( 0, 128, 128) },
- { "thistle", NSVG_RGB(216, 191, 216) },
- { "tomato", NSVG_RGB(255, 99, 71) },
- { "turquoise", NSVG_RGB( 64, 224, 208) },
- { "violet", NSVG_RGB(238, 130, 238) },
- { "wheat", NSVG_RGB(245, 222, 179) },
- { "whitesmoke", NSVG_RGB(245, 245, 245) },
- { "yellowgreen", NSVG_RGB(154, 205, 50) },
-#endif
-};
-
-static unsigned int nsvg__parseColorName(const char* str)
-{
- int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor);
-
- for (i = 0; i < ncolors; i++) {
- if (strcmp(nsvg__colors[i].name, str) == 0) {
- return nsvg__colors[i].color;
- }
- }
-
- return NSVG_RGB(128, 128, 128);
-}
-
-static unsigned int nsvg__parseColor(const char* str)
-{
- size_t len = 0;
- while(*str == ' ') ++str;
- len = strlen(str);
- if (len >= 1 && *str == '#')
- return nsvg__parseColorHex(str);
- else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(')
- return nsvg__parseColorRGB(str);
- return nsvg__parseColorName(str);
-}
-
-static float nsvg__parseOpacity(const char* str)
-{
- float val = nsvg__atof(str);
- if (val < 0.0f) val = 0.0f;
- if (val > 1.0f) val = 1.0f;
- return val;
-}
-
-static float nsvg__parseMiterLimit(const char* str)
-{
- float val = nsvg__atof(str);
- if (val < 0.0f) val = 0.0f;
- return val;
-}
-
-static int nsvg__parseUnits(const char* units)
-{
- if (units[0] == 'p' && units[1] == 'x')
- return NSVG_UNITS_PX;
- else if (units[0] == 'p' && units[1] == 't')
- return NSVG_UNITS_PT;
- else if (units[0] == 'p' && units[1] == 'c')
- return NSVG_UNITS_PC;
- else if (units[0] == 'm' && units[1] == 'm')
- return NSVG_UNITS_MM;
- else if (units[0] == 'c' && units[1] == 'm')
- return NSVG_UNITS_CM;
- else if (units[0] == 'i' && units[1] == 'n')
- return NSVG_UNITS_IN;
- else if (units[0] == '%')
- return NSVG_UNITS_PERCENT;
- else if (units[0] == 'e' && units[1] == 'm')
- return NSVG_UNITS_EM;
- else if (units[0] == 'e' && units[1] == 'x')
- return NSVG_UNITS_EX;
- return NSVG_UNITS_USER;
-}
-
-static int nsvg__isCoordinate(const char* s)
-{
- // optional sign
- if (*s == '-' || *s == '+')
- s++;
- // must have at least one digit, or start by a dot
- return (nsvg__isdigit(*s) || *s == '.');
-}
-
-static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
-{
- NSVGcoordinate coord = {0, NSVG_UNITS_USER};
- char buf[64];
- coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));
- coord.value = nsvg__atof(buf);
- return coord;
-}
-
-static NSVGcoordinate nsvg__coord(float v, int units)
-{
- NSVGcoordinate coord = {v, units};
- return coord;
-}
-
-static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length)
-{
- NSVGcoordinate coord = nsvg__parseCoordinateRaw(str);
- return nsvg__convertToPixels(p, coord, orig, length);
-}
-
-static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na)
-{
- const char* end;
- const char* ptr;
- char it[64];
-
- *na = 0;
- ptr = str;
- while (*ptr && *ptr != '(') ++ptr;
- if (*ptr == 0)
- return 1;
- end = ptr;
- while (*end && *end != ')') ++end;
- if (*end == 0)
- return 1;
-
- while (ptr < end) {
- if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {
- if (*na >= maxNa) return 0;
- ptr = nsvg__parseNumber(ptr, it, 64);
- args[(*na)++] = (float)nsvg__atof(it);
- } else {
- ++ptr;
- }
- }
- return (int)(end - str);
-}
-
-
-static int nsvg__parseMatrix(float* xform, const char* str)
-{
- float t[6];
- int na = 0;
- int len = nsvg__parseTransformArgs(str, t, 6, &na);
- if (na != 6) return len;
- memcpy(xform, t, sizeof(float)*6);
- return len;
-}
-
-static int nsvg__parseTranslate(float* xform, const char* str)
-{
- float args[2];
- float t[6];
- int na = 0;
- int len = nsvg__parseTransformArgs(str, args, 2, &na);
- if (na == 1) args[1] = 0.0;
-
- nsvg__xformSetTranslation(t, args[0], args[1]);
- memcpy(xform, t, sizeof(float)*6);
- return len;
-}
-
-static int nsvg__parseScale(float* xform, const char* str)
-{
- float args[2];
- int na = 0;
- float t[6];
- int len = nsvg__parseTransformArgs(str, args, 2, &na);
- if (na == 1) args[1] = args[0];
- nsvg__xformSetScale(t, args[0], args[1]);
- memcpy(xform, t, sizeof(float)*6);
- return len;
-}
-
-static int nsvg__parseSkewX(float* xform, const char* str)
-{
- float args[1];
- int na = 0;
- float t[6];
- int len = nsvg__parseTransformArgs(str, args, 1, &na);
- nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI);
- memcpy(xform, t, sizeof(float)*6);
- return len;
-}
-
-static int nsvg__parseSkewY(float* xform, const char* str)
-{
- float args[1];
- int na = 0;
- float t[6];
- int len = nsvg__parseTransformArgs(str, args, 1, &na);
- nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI);
- memcpy(xform, t, sizeof(float)*6);
- return len;
-}
-
-static int nsvg__parseRotate(float* xform, const char* str)
-{
- float args[3];
- int na = 0;
- float m[6];
- float t[6];
- int len = nsvg__parseTransformArgs(str, args, 3, &na);
- if (na == 1)
- args[1] = args[2] = 0.0f;
- nsvg__xformIdentity(m);
-
- if (na > 1) {
- nsvg__xformSetTranslation(t, -args[1], -args[2]);
- nsvg__xformMultiply(m, t);
- }
-
- nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI);
- nsvg__xformMultiply(m, t);
-
- if (na > 1) {
- nsvg__xformSetTranslation(t, args[1], args[2]);
- nsvg__xformMultiply(m, t);
- }
-
- memcpy(xform, m, sizeof(float)*6);
-
- return len;
-}
-
-static void nsvg__parseTransform(float* xform, const char* str)
-{
- float t[6];
- int len;
- nsvg__xformIdentity(xform);
- while (*str)
- {
- if (strncmp(str, "matrix", 6) == 0)
- len = nsvg__parseMatrix(t, str);
- else if (strncmp(str, "translate", 9) == 0)
- len = nsvg__parseTranslate(t, str);
- else if (strncmp(str, "scale", 5) == 0)
- len = nsvg__parseScale(t, str);
- else if (strncmp(str, "rotate", 6) == 0)
- len = nsvg__parseRotate(t, str);
- else if (strncmp(str, "skewX", 5) == 0)
- len = nsvg__parseSkewX(t, str);
- else if (strncmp(str, "skewY", 5) == 0)
- len = nsvg__parseSkewY(t, str);
- else{
- ++str;
- continue;
- }
- if (len != 0) {
- str += len;
- } else {
- ++str;
- continue;
- }
-
- nsvg__xformPremultiply(xform, t);
- }
-}
-
-static void nsvg__parseUrl(char* id, const char* str)
-{
- int i = 0;
- str += 4; // "url(";
- if (*str && *str == '#')
- str++;
- while (i < 63 && *str && *str != ')') {
- id[i] = *str++;
- i++;
- }
- id[i] = '\0';
-}
-
-static char nsvg__parseLineCap(const char* str)
-{
- if (strcmp(str, "butt") == 0)
- return NSVG_CAP_BUTT;
- else if (strcmp(str, "round") == 0)
- return NSVG_CAP_ROUND;
- else if (strcmp(str, "square") == 0)
- return NSVG_CAP_SQUARE;
- // TODO: handle inherit.
- return NSVG_CAP_BUTT;
-}
-
-static char nsvg__parseLineJoin(const char* str)
-{
- if (strcmp(str, "miter") == 0)
- return NSVG_JOIN_MITER;
- else if (strcmp(str, "round") == 0)
- return NSVG_JOIN_ROUND;
- else if (strcmp(str, "bevel") == 0)
- return NSVG_JOIN_BEVEL;
- // TODO: handle inherit.
- return NSVG_JOIN_MITER;
-}
-
-static char nsvg__parseFillRule(const char* str)
-{
- if (strcmp(str, "nonzero") == 0)
- return NSVG_FILLRULE_NONZERO;
- else if (strcmp(str, "evenodd") == 0)
- return NSVG_FILLRULE_EVENODD;
- // TODO: handle inherit.
- return NSVG_FILLRULE_NONZERO;
-}
-
-static const char* nsvg__getNextDashItem(const char* s, char* it)
-{
- int n = 0;
- it[0] = '\0';
- // Skip white spaces and commas
- while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
- // Advance until whitespace, comma or end.
- while (*s && (!nsvg__isspace(*s) && *s != ',')) {
- if (n < 63)
- it[n++] = *s;
- s++;
- }
- it[n++] = '\0';
- return s;
-}
-
-static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray)
-{
- char item[64];
- int count = 0, i;
- float sum = 0.0f;
-
- // Handle "none"
- if (str[0] == 'n')
- return 0;
-
- // Parse dashes
- while (*str) {
- str = nsvg__getNextDashItem(str, item);
- if (!*item) break;
- if (count < NSVG_MAX_DASHES)
- strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p)));
- }
-
- for (i = 0; i < count; i++)
- sum += strokeDashArray[i];
- if (sum <= 1e-6f)
- count = 0;
-
- return count;
-}
-
-static void nsvg__parseStyle(NSVGparser* p, const char* str);
-
-static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
-{
- float xform[6];
- NSVGattrib* attr = nsvg__getAttr(p);
- if (!attr) return 0;
-
- if (strcmp(name, "style") == 0) {
- nsvg__parseStyle(p, value);
- } else if (strcmp(name, "display") == 0) {
- if (strcmp(value, "none") == 0)
- attr->visible = 0;
- // Don't reset ->visible on display:inline, one display:none hides the whole subtree
-
- } else if (strcmp(name, "fill") == 0) {
- if (strcmp(value, "none") == 0) {
- attr->hasFill = 0;
- } else if (strncmp(value, "url(", 4) == 0) {
- attr->hasFill = 2;
- nsvg__parseUrl(attr->fillGradient, value);
- } else {
- attr->hasFill = 1;
- attr->fillColor = nsvg__parseColor(value);
- }
- } else if (strcmp(name, "opacity") == 0) {
- attr->opacity = nsvg__parseOpacity(value);
- } else if (strcmp(name, "fill-opacity") == 0) {
- attr->fillOpacity = nsvg__parseOpacity(value);
- } else if (strcmp(name, "stroke") == 0) {
- if (strcmp(value, "none") == 0) {
- attr->hasStroke = 0;
- } else if (strncmp(value, "url(", 4) == 0) {
- attr->hasStroke = 2;
- nsvg__parseUrl(attr->strokeGradient, value);
- } else {
- attr->hasStroke = 1;
- attr->strokeColor = nsvg__parseColor(value);
- }
- } else if (strcmp(name, "stroke-width") == 0) {
- attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
- } else if (strcmp(name, "stroke-dasharray") == 0) {
- attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray);
- } else if (strcmp(name, "stroke-dashoffset") == 0) {
- attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
- } else if (strcmp(name, "stroke-opacity") == 0) {
- attr->strokeOpacity = nsvg__parseOpacity(value);
- } else if (strcmp(name, "stroke-linecap") == 0) {
- attr->strokeLineCap = nsvg__parseLineCap(value);
- } else if (strcmp(name, "stroke-linejoin") == 0) {
- attr->strokeLineJoin = nsvg__parseLineJoin(value);
- } else if (strcmp(name, "stroke-miterlimit") == 0) {
- attr->miterLimit = nsvg__parseMiterLimit(value);
- } else if (strcmp(name, "fill-rule") == 0) {
- attr->fillRule = nsvg__parseFillRule(value);
- } else if (strcmp(name, "font-size") == 0) {
- attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p));
- } else if (strcmp(name, "transform") == 0) {
- nsvg__parseTransform(xform, value);
- nsvg__xformPremultiply(attr->xform, xform);
- } else if (strcmp(name, "stop-color") == 0) {
- attr->stopColor = nsvg__parseColor(value);
- } else if (strcmp(name, "stop-opacity") == 0) {
- attr->stopOpacity = nsvg__parseOpacity(value);
- } else if (strcmp(name, "offset") == 0) {
- attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f);
- } else if (strcmp(name, "id") == 0) {
- strncpy(attr->id, value, 63);
- attr->id[63] = '\0';
- } else {
- return 0;
- }
- return 1;
-}
-
-static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end)
-{
- const char* str;
- const char* val;
- char name[512];
- char value[512];
- int n;
-
- str = start;
- while (str < end && *str != ':') ++str;
-
- val = str;
-
- // Right Trim
- while (str > start && (*str == ':' || nsvg__isspace(*str))) --str;
- ++str;
-
- n = (int)(str - start);
- if (n > 511) n = 511;
- if (n) memcpy(name, start, n);
- name[n] = 0;
-
- while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val;
-
- n = (int)(end - val);
- if (n > 511) n = 511;
- if (n) memcpy(value, val, n);
- value[n] = 0;
-
- return nsvg__parseAttr(p, name, value);
-}
-
-static void nsvg__parseStyle(NSVGparser* p, const char* str)
-{
- const char* start;
- const char* end;
-
- while (*str) {
- // Left Trim
- while(*str && nsvg__isspace(*str)) ++str;
- start = str;
- while(*str && *str != ';') ++str;
- end = str;
-
- // Right Trim
- while (end > start && (*end == ';' || nsvg__isspace(*end))) --end;
- ++end;
-
- nsvg__parseNameValue(p, start, end);
- if (*str) ++str;
- }
-}
-
-static void nsvg__parseAttribs(NSVGparser* p, const char** attr)
-{
- int i;
- for (i = 0; attr[i]; i += 2)
- {
- if (strcmp(attr[i], "style") == 0)
- nsvg__parseStyle(p, attr[i + 1]);
- else
- nsvg__parseAttr(p, attr[i], attr[i + 1]);
- }
-}
-
-static int nsvg__getArgsPerElement(char cmd)
-{
- switch (cmd) {
- case 'v':
- case 'V':
- case 'h':
- case 'H':
- return 1;
- case 'm':
- case 'M':
- case 'l':
- case 'L':
- case 't':
- case 'T':
- return 2;
- case 'q':
- case 'Q':
- case 's':
- case 'S':
- return 4;
- case 'c':
- case 'C':
- return 6;
- case 'a':
- case 'A':
- return 7;
- case 'z':
- case 'Z':
- return 0;
- }
- return -1;
-}
-
-static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
-{
- if (rel) {
- *cpx += args[0];
- *cpy += args[1];
- } else {
- *cpx = args[0];
- *cpy = args[1];
- }
- nsvg__moveTo(p, *cpx, *cpy);
-}
-
-static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
-{
- if (rel) {
- *cpx += args[0];
- *cpy += args[1];
- } else {
- *cpx = args[0];
- *cpy = args[1];
- }
- nsvg__lineTo(p, *cpx, *cpy);
-}
-
-static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
-{
- if (rel)
- *cpx += args[0];
- else
- *cpx = args[0];
- nsvg__lineTo(p, *cpx, *cpy);
-}
-
-static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
-{
- if (rel)
- *cpy += args[0];
- else
- *cpy = args[0];
- nsvg__lineTo(p, *cpx, *cpy);
-}
-
-static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy,
- float* cpx2, float* cpy2, float* args, int rel)
-{
- float x2, y2, cx1, cy1, cx2, cy2;
-
- if (rel) {
- cx1 = *cpx + args[0];
- cy1 = *cpy + args[1];
- cx2 = *cpx + args[2];
- cy2 = *cpy + args[3];
- x2 = *cpx + args[4];
- y2 = *cpy + args[5];
- } else {
- cx1 = args[0];
- cy1 = args[1];
- cx2 = args[2];
- cy2 = args[3];
- x2 = args[4];
- y2 = args[5];
- }
-
- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
-
- *cpx2 = cx2;
- *cpy2 = cy2;
- *cpx = x2;
- *cpy = y2;
-}
-
-static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy,
- float* cpx2, float* cpy2, float* args, int rel)
-{
- float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
-
- x1 = *cpx;
- y1 = *cpy;
- if (rel) {
- cx2 = *cpx + args[0];
- cy2 = *cpy + args[1];
- x2 = *cpx + args[2];
- y2 = *cpy + args[3];
- } else {
- cx2 = args[0];
- cy2 = args[1];
- x2 = args[2];
- y2 = args[3];
- }
-
- cx1 = 2*x1 - *cpx2;
- cy1 = 2*y1 - *cpy2;
-
- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
-
- *cpx2 = cx2;
- *cpy2 = cy2;
- *cpx = x2;
- *cpy = y2;
-}
-
-static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy,
- float* cpx2, float* cpy2, float* args, int rel)
-{
- float x1, y1, x2, y2, cx, cy;
- float cx1, cy1, cx2, cy2;
-
- x1 = *cpx;
- y1 = *cpy;
- if (rel) {
- cx = *cpx + args[0];
- cy = *cpy + args[1];
- x2 = *cpx + args[2];
- y2 = *cpy + args[3];
- } else {
- cx = args[0];
- cy = args[1];
- x2 = args[2];
- y2 = args[3];
- }
-
- // Convert to cubic bezier
- cx1 = x1 + 2.0f/3.0f*(cx - x1);
- cy1 = y1 + 2.0f/3.0f*(cy - y1);
- cx2 = x2 + 2.0f/3.0f*(cx - x2);
- cy2 = y2 + 2.0f/3.0f*(cy - y2);
-
- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
-
- *cpx2 = cx;
- *cpy2 = cy;
- *cpx = x2;
- *cpy = y2;
-}
-
-static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy,
- float* cpx2, float* cpy2, float* args, int rel)
-{
- float x1, y1, x2, y2, cx, cy;
- float cx1, cy1, cx2, cy2;
-
- x1 = *cpx;
- y1 = *cpy;
- if (rel) {
- x2 = *cpx + args[0];
- y2 = *cpy + args[1];
- } else {
- x2 = args[0];
- y2 = args[1];
- }
-
- cx = 2*x1 - *cpx2;
- cy = 2*y1 - *cpy2;
-
- // Convert to cubix bezier
- cx1 = x1 + 2.0f/3.0f*(cx - x1);
- cy1 = y1 + 2.0f/3.0f*(cy - y1);
- cx2 = x2 + 2.0f/3.0f*(cx - x2);
- cy2 = y2 + 2.0f/3.0f*(cy - y2);
-
- nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
-
- *cpx2 = cx;
- *cpy2 = cy;
- *cpx = x2;
- *cpy = y2;
-}
-
-static float nsvg__sqr(float x) { return x*x; }
-static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); }
-
-static float nsvg__vecrat(float ux, float uy, float vx, float vy)
-{
- return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy));
-}
-
-static float nsvg__vecang(float ux, float uy, float vx, float vy)
-{
- float r = nsvg__vecrat(ux,uy, vx,vy);
- if (r < -1.0f) r = -1.0f;
- if (r > 1.0f) r = 1.0f;
- return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r);
-}
-
-static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel)
-{
- // Ported from canvg (https://code.google.com/p/canvg/)
- float rx, ry, rotx;
- float x1, y1, x2, y2, cx, cy, dx, dy, d;
- float x1p, y1p, cxp, cyp, s, sa, sb;
- float ux, uy, vx, vy, a1, da;
- float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6];
- float sinrx, cosrx;
- int fa, fs;
- int i, ndivs;
- float hda, kappa;
-
- rx = fabsf(args[0]); // y radius
- ry = fabsf(args[1]); // x radius
- rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle
- fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc
- fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction
- x1 = *cpx; // start point
- y1 = *cpy;
- if (rel) { // end point
- x2 = *cpx + args[5];
- y2 = *cpy + args[6];
- } else {
- x2 = args[5];
- y2 = args[6];
- }
-
- dx = x1 - x2;
- dy = y1 - y2;
- d = sqrtf(dx*dx + dy*dy);
- if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) {
- // The arc degenerates to a line
- nsvg__lineTo(p, x2, y2);
- *cpx = x2;
- *cpy = y2;
- return;
- }
-
- sinrx = sinf(rotx);
- cosrx = cosf(rotx);
-
- // Convert to center point parameterization.
- // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
- // 1) Compute x1', y1'
- x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f;
- y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f;
- d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry);
- if (d > 1) {
- d = sqrtf(d);
- rx *= d;
- ry *= d;
- }
- // 2) Compute cx', cy'
- s = 0.0f;
- sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p);
- sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p);
- if (sa < 0.0f) sa = 0.0f;
- if (sb > 0.0f)
- s = sqrtf(sa / sb);
- if (fa == fs)
- s = -s;
- cxp = s * rx * y1p / ry;
- cyp = s * -ry * x1p / rx;
-
- // 3) Compute cx,cy from cx',cy'
- cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp;
- cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp;
-
- // 4) Calculate theta1, and delta theta.
- ux = (x1p - cxp) / rx;
- uy = (y1p - cyp) / ry;
- vx = (-x1p - cxp) / rx;
- vy = (-y1p - cyp) / ry;
- a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle
- da = nsvg__vecang(ux,uy, vx,vy); // Delta angle
-
-// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
-// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
-
- if (fs == 0 && da > 0)
- da -= 2 * NSVG_PI;
- else if (fs == 1 && da < 0)
- da += 2 * NSVG_PI;
-
- // Approximate the arc using cubic spline segments.
- t[0] = cosrx; t[1] = sinrx;
- t[2] = -sinrx; t[3] = cosrx;
- t[4] = cx; t[5] = cy;
-
- // Split arc into max 90 degree segments.
- // The loop assumes an iteration per end point (including start and end), this +1.
- ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f);
- hda = (da / (float)ndivs) / 2.0f;
- // Fix for ticket #179: division by 0: avoid cotangens around 0 (infinite)
- if ((hda < 1e-3f) && (hda > -1e-3f))
- hda *= 0.5f;
- else
- hda = (1.0f - cosf(hda)) / sinf(hda);
- kappa = fabsf(4.0f / 3.0f * hda);
- if (da < 0.0f)
- kappa = -kappa;
-
- for (i = 0; i <= ndivs; i++) {
- a = a1 + da * ((float)i/(float)ndivs);
- dx = cosf(a);
- dy = sinf(a);
- nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position
- nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent
- if (i > 0)
- nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y);
- px = x;
- py = y;
- ptanx = tanx;
- ptany = tany;
- }
-
- *cpx = x2;
- *cpy = y2;
-}
-
-static void nsvg__parsePath(NSVGparser* p, const char** attr)
-{
- const char* s = NULL;
- char cmd = '\0';
- float args[10];
- int nargs;
- int rargs = 0;
- char initPoint;
- float cpx, cpy, cpx2, cpy2;
- const char* tmp[4];
- char closedFlag;
- int i;
- char item[64];
-
- for (i = 0; attr[i]; i += 2) {
- if (strcmp(attr[i], "d") == 0) {
- s = attr[i + 1];
- } else {
- tmp[0] = attr[i];
- tmp[1] = attr[i + 1];
- tmp[2] = 0;
- tmp[3] = 0;
- nsvg__parseAttribs(p, tmp);
- }
- }
-
- if (s) {
- nsvg__resetPath(p);
- cpx = 0; cpy = 0;
- cpx2 = 0; cpy2 = 0;
- initPoint = 0;
- closedFlag = 0;
- nargs = 0;
-
- while (*s) {
- s = nsvg__getNextPathItem(s, item);
- if (!*item) break;
- if (cmd != '\0' && nsvg__isCoordinate(item)) {
- if (nargs < 10)
- args[nargs++] = (float)nsvg__atof(item);
- if (nargs >= rargs) {
- switch (cmd) {
- case 'm':
- case 'M':
- nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0);
- // Moveto can be followed by multiple coordinate pairs,
- // which should be treated as linetos.
- cmd = (cmd == 'm') ? 'l' : 'L';
- rargs = nsvg__getArgsPerElement(cmd);
- cpx2 = cpx; cpy2 = cpy;
- initPoint = 1;
- break;
- case 'l':
- case 'L':
- nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
- break;
- case 'H':
- case 'h':
- nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
- break;
- case 'V':
- case 'v':
- nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
- break;
- case 'C':
- case 'c':
- nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0);
- break;
- case 'S':
- case 's':
- nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0);
- break;
- case 'Q':
- case 'q':
- nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0);
- break;
- case 'T':
- case 't':
- nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0);
- break;
- case 'A':
- case 'a':
- nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);
- cpx2 = cpx; cpy2 = cpy;
- break;
- default:
- if (nargs >= 2) {
- cpx = args[nargs-2];
- cpy = args[nargs-1];
- cpx2 = cpx; cpy2 = cpy;
- }
- break;
- }
- nargs = 0;
- }
- } else {
- cmd = item[0];
- if (cmd == 'M' || cmd == 'm') {
- // Commit path.
- if (p->npts > 0)
- nsvg__addPath(p, closedFlag);
- // Start new subpath.
- nsvg__resetPath(p);
- closedFlag = 0;
- nargs = 0;
- } else if (initPoint == 0) {
- // Do not allow other commands until initial point has been set (moveTo called once).
- cmd = '\0';
- }
- if (cmd == 'Z' || cmd == 'z') {
- closedFlag = 1;
- // Commit path.
- if (p->npts > 0) {
- // Move current point to first point
- cpx = p->pts[0];
- cpy = p->pts[1];
- cpx2 = cpx; cpy2 = cpy;
- nsvg__addPath(p, closedFlag);
- }
- // Start new subpath.
- nsvg__resetPath(p);
- nsvg__moveTo(p, cpx, cpy);
- closedFlag = 0;
- nargs = 0;
- }
- rargs = nsvg__getArgsPerElement(cmd);
- if (rargs == -1) {
- // Command not recognized
- cmd = '\0';
- rargs = 0;
- }
- }
- }
- // Commit path.
- if (p->npts)
- nsvg__addPath(p, closedFlag);
- }
-
- nsvg__addShape(p);
-}
-
-static void nsvg__parseRect(NSVGparser* p, const char** attr)
-{
- float x = 0.0f;
- float y = 0.0f;
- float w = 0.0f;
- float h = 0.0f;
- float rx = -1.0f; // marks not set
- float ry = -1.0f;
- int i;
-
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
- if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
- if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p));
- if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p));
- if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
- if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
- }
- }
-
- if (rx < 0.0f && ry > 0.0f) rx = ry;
- if (ry < 0.0f && rx > 0.0f) ry = rx;
- if (rx < 0.0f) rx = 0.0f;
- if (ry < 0.0f) ry = 0.0f;
- if (rx > w/2.0f) rx = w/2.0f;
- if (ry > h/2.0f) ry = h/2.0f;
-
- if (w != 0.0f && h != 0.0f) {
- nsvg__resetPath(p);
-
- if (rx < 0.00001f || ry < 0.0001f) {
- nsvg__moveTo(p, x, y);
- nsvg__lineTo(p, x+w, y);
- nsvg__lineTo(p, x+w, y+h);
- nsvg__lineTo(p, x, y+h);
- } else {
- // Rounded rectangle
- nsvg__moveTo(p, x+rx, y);
- nsvg__lineTo(p, x+w-rx, y);
- nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry);
- nsvg__lineTo(p, x+w, y+h-ry);
- nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h);
- nsvg__lineTo(p, x+rx, y+h);
- nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry);
- nsvg__lineTo(p, x, y+ry);
- nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y);
- }
-
- nsvg__addPath(p, 1);
-
- nsvg__addShape(p);
- }
-}
-
-static void nsvg__parseCircle(NSVGparser* p, const char** attr)
-{
- float cx = 0.0f;
- float cy = 0.0f;
- float r = 0.0f;
- int i;
-
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
- if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
- if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p)));
- }
- }
-
- if (r > 0.0f) {
- nsvg__resetPath(p);
-
- nsvg__moveTo(p, cx+r, cy);
- nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r);
- nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy);
- nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r);
- nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy);
-
- nsvg__addPath(p, 1);
-
- nsvg__addShape(p);
- }
-}
-
-static void nsvg__parseEllipse(NSVGparser* p, const char** attr)
-{
- float cx = 0.0f;
- float cy = 0.0f;
- float rx = 0.0f;
- float ry = 0.0f;
- int i;
-
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
- if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
- if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
- if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
- }
- }
-
- if (rx > 0.0f && ry > 0.0f) {
-
- nsvg__resetPath(p);
-
- nsvg__moveTo(p, cx+rx, cy);
- nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry);
- nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy);
- nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);
- nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy);
-
- nsvg__addPath(p, 1);
-
- nsvg__addShape(p);
- }
-}
-
-static void nsvg__parseLine(NSVGparser* p, const char** attr)
-{
- float x1 = 0.0;
- float y1 = 0.0;
- float x2 = 0.0;
- float y2 = 0.0;
- int i;
-
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
- if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
- if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
- if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p));
- }
- }
-
- nsvg__resetPath(p);
-
- nsvg__moveTo(p, x1, y1);
- nsvg__lineTo(p, x2, y2);
-
- nsvg__addPath(p, 0);
-
- nsvg__addShape(p);
-}
-
-static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
-{
- int i;
- const char* s;
- float args[2];
- int nargs, npts = 0;
- char item[64];
-
- nsvg__resetPath(p);
-
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "points") == 0) {
- s = attr[i + 1];
- nargs = 0;
- while (*s) {
- s = nsvg__getNextPathItem(s, item);
- args[nargs++] = (float)nsvg__atof(item);
- if (nargs >= 2) {
- if (npts == 0)
- nsvg__moveTo(p, args[0], args[1]);
- else
- nsvg__lineTo(p, args[0], args[1]);
- nargs = 0;
- npts++;
- }
- }
- }
- }
- }
-
- nsvg__addPath(p, (char)closeFlag);
-
- nsvg__addShape(p);
-}
-
-static void nsvg__parseSVG(NSVGparser* p, const char** attr)
-{
- int i;
- for (i = 0; attr[i]; i += 2) {
- if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "width") == 0) {
- p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
- } else if (strcmp(attr[i], "height") == 0) {
- p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
- } else if (strcmp(attr[i], "viewBox") == 0) {
- const char *s = attr[i + 1];
- char buf[64];
- s = nsvg__parseNumber(s, buf, 64);
- p->viewMinx = nsvg__atof(buf);
- while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
- if (!*s) return;
- s = nsvg__parseNumber(s, buf, 64);
- p->viewMiny = nsvg__atof(buf);
- while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
- if (!*s) return;
- s = nsvg__parseNumber(s, buf, 64);
- p->viewWidth = nsvg__atof(buf);
- while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
- if (!*s) return;
- s = nsvg__parseNumber(s, buf, 64);
- p->viewHeight = nsvg__atof(buf);
- } else if (strcmp(attr[i], "preserveAspectRatio") == 0) {
- if (strstr(attr[i + 1], "none") != 0) {
- // No uniform scaling
- p->alignType = NSVG_ALIGN_NONE;
- } else {
- // Parse X align
- if (strstr(attr[i + 1], "xMin") != 0)
- p->alignX = NSVG_ALIGN_MIN;
- else if (strstr(attr[i + 1], "xMid") != 0)
- p->alignX = NSVG_ALIGN_MID;
- else if (strstr(attr[i + 1], "xMax") != 0)
- p->alignX = NSVG_ALIGN_MAX;
- // Parse X align
- if (strstr(attr[i + 1], "yMin") != 0)
- p->alignY = NSVG_ALIGN_MIN;
- else if (strstr(attr[i + 1], "yMid") != 0)
- p->alignY = NSVG_ALIGN_MID;
- else if (strstr(attr[i + 1], "yMax") != 0)
- p->alignY = NSVG_ALIGN_MAX;
- // Parse meet/slice
- p->alignType = NSVG_ALIGN_MEET;
- if (strstr(attr[i + 1], "slice") != 0)
- p->alignType = NSVG_ALIGN_SLICE;
- }
- }
- }
- }
-}
-
-static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type)
-{
- int i;
- NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData));
- if (grad == NULL) return;
- memset(grad, 0, sizeof(NSVGgradientData));
- grad->units = NSVG_OBJECT_SPACE;
- grad->type = type;
- if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) {
- grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
- grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
- grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT);
- grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
- } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) {
- grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
- grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
- grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
- }
-
- nsvg__xformIdentity(grad->xform);
-
- for (i = 0; attr[i]; i += 2) {
- if (strcmp(attr[i], "id") == 0) {
- strncpy(grad->id, attr[i+1], 63);
- grad->id[63] = '\0';
- } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
- if (strcmp(attr[i], "gradientUnits") == 0) {
- if (strcmp(attr[i+1], "objectBoundingBox") == 0)
- grad->units = NSVG_OBJECT_SPACE;
- else
- grad->units = NSVG_USER_SPACE;
- } else if (strcmp(attr[i], "gradientTransform") == 0) {
- nsvg__parseTransform(grad->xform, attr[i + 1]);
- } else if (strcmp(attr[i], "cx") == 0) {
- grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "cy") == 0) {
- grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "r") == 0) {
- grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "fx") == 0) {
- grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "fy") == 0) {
- grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "x1") == 0) {
- grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "y1") == 0) {
- grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "x2") == 0) {
- grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "y2") == 0) {
- grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]);
- } else if (strcmp(attr[i], "spreadMethod") == 0) {
- if (strcmp(attr[i+1], "pad") == 0)
- grad->spread = NSVG_SPREAD_PAD;
- else if (strcmp(attr[i+1], "reflect") == 0)
- grad->spread = NSVG_SPREAD_REFLECT;
- else if (strcmp(attr[i+1], "repeat") == 0)
- grad->spread = NSVG_SPREAD_REPEAT;
- } else if (strcmp(attr[i], "xlink:href") == 0) {
- const char *href = attr[i+1];
- strncpy(grad->ref, href+1, 62);
- grad->ref[62] = '\0';
- }
- }
- }
-
- grad->next = p->gradients;
- p->gradients = grad;
-}
-
-static void nsvg__parseGradientStop(NSVGparser* p, const char** attr)
-{
- NSVGattrib* curAttr = nsvg__getAttr(p);
- NSVGgradientData* grad;
- NSVGgradientStop* stop;
- int i, idx;
-
- curAttr->stopOffset = 0;
- curAttr->stopColor = 0;
- curAttr->stopOpacity = 1.0f;
-
- for (i = 0; attr[i]; i += 2) {
- nsvg__parseAttr(p, attr[i], attr[i + 1]);
- }
-
- // Add stop to the last gradient.
- grad = p->gradients;
- if (grad == NULL) return;
-
- grad->nstops++;
- grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops);
- if (grad->stops == NULL) return;
-
- // Insert
- idx = grad->nstops-1;
- for (i = 0; i < grad->nstops-1; i++) {
- if (curAttr->stopOffset < grad->stops[i].offset) {
- idx = i;
- break;
- }
- }
- if (idx != grad->nstops-1) {
- for (i = grad->nstops-1; i > idx; i--)
- grad->stops[i] = grad->stops[i-1];
- }
-
- stop = &grad->stops[idx];
- stop->color = curAttr->stopColor;
- stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24;
- stop->offset = curAttr->stopOffset;
-}
-
-static void nsvg__startElement(void* ud, const char* el, const char** attr)
-{
- NSVGparser* p = (NSVGparser*)ud;
-
- if (p->defsFlag) {
- // Skip everything but gradients in defs
- if (strcmp(el, "linearGradient") == 0) {
- nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
- } else if (strcmp(el, "radialGradient") == 0) {
- nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
- } else if (strcmp(el, "stop") == 0) {
- nsvg__parseGradientStop(p, attr);
- }
- return;
- }
-
- if (strcmp(el, "g") == 0) {
- nsvg__pushAttr(p);
- nsvg__parseAttribs(p, attr);
- } else if (strcmp(el, "path") == 0) {
- if (p->pathFlag) // Do not allow nested paths.
- return;
- nsvg__pushAttr(p);
- nsvg__parsePath(p, attr);
- nsvg__popAttr(p);
- } else if (strcmp(el, "rect") == 0) {
- nsvg__pushAttr(p);
- nsvg__parseRect(p, attr);
- nsvg__popAttr(p);
- } else if (strcmp(el, "circle") == 0) {
- nsvg__pushAttr(p);
- nsvg__parseCircle(p, attr);
- nsvg__popAttr(p);
- } else if (strcmp(el, "ellipse") == 0) {
- nsvg__pushAttr(p);
- nsvg__parseEllipse(p, attr);
- nsvg__popAttr(p);
- } else if (strcmp(el, "line") == 0) {
- nsvg__pushAttr(p);
- nsvg__parseLine(p, attr);
- nsvg__popAttr(p);
- } else if (strcmp(el, "polyline") == 0) {
- nsvg__pushAttr(p);
- nsvg__parsePoly(p, attr, 0);
- nsvg__popAttr(p);
- } else if (strcmp(el, "polygon") == 0) {
- nsvg__pushAttr(p);
- nsvg__parsePoly(p, attr, 1);
- nsvg__popAttr(p);
- } else if (strcmp(el, "linearGradient") == 0) {
- nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
- } else if (strcmp(el, "radialGradient") == 0) {
- nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
- } else if (strcmp(el, "stop") == 0) {
- nsvg__parseGradientStop(p, attr);
- } else if (strcmp(el, "defs") == 0) {
- p->defsFlag = 1;
- } else if (strcmp(el, "svg") == 0) {
- nsvg__parseSVG(p, attr);
- }
-}
-
-static void nsvg__endElement(void* ud, const char* el)
-{
- NSVGparser* p = (NSVGparser*)ud;
-
- if (strcmp(el, "g") == 0) {
- nsvg__popAttr(p);
- } else if (strcmp(el, "path") == 0) {
- p->pathFlag = 0;
- } else if (strcmp(el, "defs") == 0) {
- p->defsFlag = 0;
- }
-}
-
-static void nsvg__content(void* ud, const char* s)
-{
- NSVG_NOTUSED(ud);
- NSVG_NOTUSED(s);
- // empty
-}
-
-static void nsvg__imageBounds(NSVGparser* p, float* bounds)
-{
- NSVGshape* shape;
- shape = p->image->shapes;
- if (shape == NULL) {
- bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
- return;
- }
- bounds[0] = shape->bounds[0];
- bounds[1] = shape->bounds[1];
- bounds[2] = shape->bounds[2];
- bounds[3] = shape->bounds[3];
- for (shape = shape->next; shape != NULL; shape = shape->next) {
- bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
- bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);
- bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);
- bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);
- }
-}
-
-static float nsvg__viewAlign(float content, float container, int type)
-{
- if (type == NSVG_ALIGN_MIN)
- return 0;
- else if (type == NSVG_ALIGN_MAX)
- return container - content;
- // mid
- return (container - content) * 0.5f;
-}
-
-static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)
-{
- float t[6];
- nsvg__xformSetTranslation(t, tx, ty);
- nsvg__xformMultiply (grad->xform, t);
-
- nsvg__xformSetScale(t, sx, sy);
- nsvg__xformMultiply (grad->xform, t);
-}
-
-static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
-{
- NSVGshape* shape;
- NSVGpath* path;
- float tx, ty, sx, sy, us, bounds[4], t[6], avgs;
- int i;
- float* pt;
-
- // Guess image size if not set completely.
- nsvg__imageBounds(p, bounds);
-
- if (p->viewWidth == 0) {
- if (p->image->width > 0) {
- p->viewWidth = p->image->width;
- } else {
- p->viewMinx = bounds[0];
- p->viewWidth = bounds[2] - bounds[0];
- }
- }
- if (p->viewHeight == 0) {
- if (p->image->height > 0) {
- p->viewHeight = p->image->height;
- } else {
- p->viewMiny = bounds[1];
- p->viewHeight = bounds[3] - bounds[1];
- }
- }
- if (p->image->width == 0)
- p->image->width = p->viewWidth;
- if (p->image->height == 0)
- p->image->height = p->viewHeight;
-
- tx = -p->viewMinx;
- ty = -p->viewMiny;
- sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0;
- sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0;
- // Unit scaling
- us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f);
-
- // Fix aspect ratio
- if (p->alignType == NSVG_ALIGN_MEET) {
- // fit whole image into viewbox
- sx = sy = nsvg__minf(sx, sy);
- tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
- ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
- } else if (p->alignType == NSVG_ALIGN_SLICE) {
- // fill whole viewbox with image
- sx = sy = nsvg__maxf(sx, sy);
- tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx;
- ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy;
- }
-
- // Transform
- sx *= us;
- sy *= us;
- avgs = (sx+sy) / 2.0f;
- for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
- shape->bounds[0] = (shape->bounds[0] + tx) * sx;
- shape->bounds[1] = (shape->bounds[1] + ty) * sy;
- shape->bounds[2] = (shape->bounds[2] + tx) * sx;
- shape->bounds[3] = (shape->bounds[3] + ty) * sy;
- for (path = shape->paths; path != NULL; path = path->next) {
- path->bounds[0] = (path->bounds[0] + tx) * sx;
- path->bounds[1] = (path->bounds[1] + ty) * sy;
- path->bounds[2] = (path->bounds[2] + tx) * sx;
- path->bounds[3] = (path->bounds[3] + ty) * sy;
- for (i =0; i < path->npts; i++) {
- pt = &path->pts[i*2];
- pt[0] = (pt[0] + tx) * sx;
- pt[1] = (pt[1] + ty) * sy;
- }
- }
-
- if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) {
- nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy);
- memcpy(t, shape->fill.gradient->xform, sizeof(float)*6);
- nsvg__xformInverse(shape->fill.gradient->xform, t);
- }
- if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) {
- nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy);
- memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6);
- nsvg__xformInverse(shape->stroke.gradient->xform, t);
- }
-
- shape->strokeWidth *= avgs;
- shape->strokeDashOffset *= avgs;
- for (i = 0; i < shape->strokeDashCount; i++)
- shape->strokeDashArray[i] *= avgs;
- }
-}
-
-NSVGimage* nsvgParse(char* input, const char* units, float dpi)
-{
- NSVGparser* p;
- NSVGimage* ret = 0;
-
- p = nsvg__createParser();
- if (p == NULL) {
- return NULL;
- }
- p->dpi = dpi;
-
- nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);
-
- // Scale to viewBox
- nsvg__scaleToViewbox(p, units);
-
- ret = p->image;
- p->image = NULL;
-
- nsvg__deleteParser(p);
-
- return ret;
-}
-
-NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
-{
- FILE* fp = NULL;
- size_t size;
- char* data = NULL;
- NSVGimage* image = NULL;
-
- fp = fopen(filename, "rb");
- if (!fp) goto error;
- fseek(fp, 0, SEEK_END);
- size = ftell(fp);
- fseek(fp, 0, SEEK_SET);
- data = (char*)malloc(size+1);
- if (data == NULL) goto error;
- if (fread(data, 1, size, fp) != size) goto error;
- data[size] = '\0'; // Must be null terminated.
- fclose(fp);
- image = nsvgParse(data, units, dpi);
- free(data);
-
- return image;
-
-error:
- if (fp) fclose(fp);
- if (data) free(data);
- if (image) nsvgDelete(image);
- return NULL;
-}
-
-NSVGpath* nsvgDuplicatePath(NSVGpath* p)
-{
- NSVGpath* res = NULL;
-
- if (p == NULL)
- return NULL;
-
- res = (NSVGpath*)malloc(sizeof(NSVGpath));
- if (res == NULL) goto error;
- memset(res, 0, sizeof(NSVGpath));
-
- res->pts = (float*)malloc(p->npts*2*sizeof(float));
- if (res->pts == NULL) goto error;
- memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2);
- res->npts = p->npts;
-
- memcpy(res->bounds, p->bounds, sizeof(p->bounds));
-
- res->closed = p->closed;
-
- return res;
-
-error:
- if (res != NULL) {
- free(res->pts);
- free(res);
- }
- return NULL;
-}
-
-void nsvgDelete(NSVGimage* image)
-{
- NSVGshape *snext, *shape;
- if (image == NULL) return;
- shape = image->shapes;
- while (shape != NULL) {
- snext = shape->next;
- nsvg__deletePaths(shape->paths);
- nsvg__deletePaint(&shape->fill);
- nsvg__deletePaint(&shape->stroke);
- free(shape);
- shape = snext;
- }
- free(image);
-}
-
-#endif // NANOSVG_IMPLEMENTATION
-
-#endif // NANOSVG_H
diff --git a/src/external/nanosvgrast.h b/src/external/nanosvgrast.h
deleted file mode 100644
index 6e23acb7b..000000000
--- a/src/external/nanosvgrast.h
+++ /dev/null
@@ -1,1458 +0,0 @@
-/*
- * Copyright (c) 2013-14 Mikko Mononen memon@inside.org
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- *
- * The polygon rasterization is heavily based on stb_truetype rasterizer
- * by Sean Barrett - http://nothings.org/
- *
- */
-
-#ifndef NANOSVGRAST_H
-#define NANOSVGRAST_H
-
-#include "nanosvg.h"
-
-#ifndef NANOSVGRAST_CPLUSPLUS
-#ifdef __cplusplus
-extern "C" {
-#endif
-#endif
-
-typedef struct NSVGrasterizer NSVGrasterizer;
-
-/* Example Usage:
- // Load SVG
- NSVGimage* image;
- image = nsvgParseFromFile("test.svg", "px", 96);
-
- // Create rasterizer (can be used to render multiple images).
- struct NSVGrasterizer* rast = nsvgCreateRasterizer();
- // Allocate memory for image
- unsigned char* img = malloc(w*h*4);
- // Rasterize
- nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4);
-*/
-
-// Allocated rasterizer context.
-NSVGrasterizer* nsvgCreateRasterizer(void);
-
-// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha)
-// r - pointer to rasterizer context
-// image - pointer to image to rasterize
-// tx,ty - image offset (applied after scaling)
-// scale - image scale
-// dst - pointer to destination image data, 4 bytes per pixel (RGBA)
-// w - width of the image to render
-// h - height of the image to render
-// stride - number of bytes per scaleline in the destination buffer
-void nsvgRasterize(NSVGrasterizer* r,
- NSVGimage* image, float tx, float ty, float scale,
- unsigned char* dst, int w, int h, int stride);
-
-// Deletes rasterizer context.
-void nsvgDeleteRasterizer(NSVGrasterizer*);
-
-
-#ifndef NANOSVGRAST_CPLUSPLUS
-#ifdef __cplusplus
-}
-#endif
-#endif
-
-#ifdef NANOSVGRAST_IMPLEMENTATION
-
-#include
-#include
-#include
-
-#define NSVG__SUBSAMPLES 5
-#define NSVG__FIXSHIFT 10
-#define NSVG__FIX (1 << NSVG__FIXSHIFT)
-#define NSVG__FIXMASK (NSVG__FIX-1)
-#define NSVG__MEMPAGE_SIZE 1024
-
-typedef struct NSVGedge {
- float x0,y0, x1,y1;
- int dir;
- struct NSVGedge* next;
-} NSVGedge;
-
-typedef struct NSVGpoint {
- float x, y;
- float dx, dy;
- float len;
- float dmx, dmy;
- unsigned char flags;
-} NSVGpoint;
-
-typedef struct NSVGactiveEdge {
- int x,dx;
- float ey;
- int dir;
- struct NSVGactiveEdge *next;
-} NSVGactiveEdge;
-
-typedef struct NSVGmemPage {
- unsigned char mem[NSVG__MEMPAGE_SIZE];
- int size;
- struct NSVGmemPage* next;
-} NSVGmemPage;
-
-typedef struct NSVGcachedPaint {
- char type;
- char spread;
- float xform[6];
- unsigned int colors[256];
-} NSVGcachedPaint;
-
-struct NSVGrasterizer
-{
- float px, py;
-
- float tessTol;
- float distTol;
-
- NSVGedge* edges;
- int nedges;
- int cedges;
-
- NSVGpoint* points;
- int npoints;
- int cpoints;
-
- NSVGpoint* points2;
- int npoints2;
- int cpoints2;
-
- NSVGactiveEdge* freelist;
- NSVGmemPage* pages;
- NSVGmemPage* curpage;
-
- unsigned char* scanline;
- int cscanline;
-
- unsigned char* bitmap;
- int width, height, stride;
-};
-
-NSVGrasterizer* nsvgCreateRasterizer(void)
-{
- NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer));
- if (r == NULL) goto error;
- memset(r, 0, sizeof(NSVGrasterizer));
-
- r->tessTol = 0.25f;
- r->distTol = 0.01f;
-
- return r;
-
-error:
- nsvgDeleteRasterizer(r);
- return NULL;
-}
-
-void nsvgDeleteRasterizer(NSVGrasterizer* r)
-{
- NSVGmemPage* p;
-
- if (r == NULL) return;
-
- p = r->pages;
- while (p != NULL) {
- NSVGmemPage* next = p->next;
- free(p);
- p = next;
- }
-
- if (r->edges) free(r->edges);
- if (r->points) free(r->points);
- if (r->points2) free(r->points2);
- if (r->scanline) free(r->scanline);
-
- free(r);
-}
-
-static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur)
-{
- NSVGmemPage *newp;
-
- // If using existing chain, return the next page in chain
- if (cur != NULL && cur->next != NULL) {
- return cur->next;
- }
-
- // Alloc new page
- newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage));
- if (newp == NULL) return NULL;
- memset(newp, 0, sizeof(NSVGmemPage));
-
- // Add to linked list
- if (cur != NULL)
- cur->next = newp;
- else
- r->pages = newp;
-
- return newp;
-}
-
-static void nsvg__resetPool(NSVGrasterizer* r)
-{
- NSVGmemPage* p = r->pages;
- while (p != NULL) {
- p->size = 0;
- p = p->next;
- }
- r->curpage = r->pages;
-}
-
-static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size)
-{
- unsigned char* buf;
- if (size > NSVG__MEMPAGE_SIZE) return NULL;
- if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) {
- r->curpage = nsvg__nextPage(r, r->curpage);
- }
- buf = &r->curpage->mem[r->curpage->size];
- r->curpage->size += size;
- return buf;
-}
-
-static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol)
-{
- float dx = x2 - x1;
- float dy = y2 - y1;
- return dx*dx + dy*dy < tol*tol;
-}
-
-static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags)
-{
- NSVGpoint* pt;
-
- if (r->npoints > 0) {
- pt = &r->points[r->npoints-1];
- if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) {
- pt->flags = (unsigned char)(pt->flags | flags);
- return;
- }
- }
-
- if (r->npoints+1 > r->cpoints) {
- r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
- r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
- if (r->points == NULL) return;
- }
-
- pt = &r->points[r->npoints];
- pt->x = x;
- pt->y = y;
- pt->flags = (unsigned char)flags;
- r->npoints++;
-}
-
-static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt)
-{
- if (r->npoints+1 > r->cpoints) {
- r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64;
- r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints);
- if (r->points == NULL) return;
- }
- r->points[r->npoints] = pt;
- r->npoints++;
-}
-
-static void nsvg__duplicatePoints(NSVGrasterizer* r)
-{
- if (r->npoints > r->cpoints2) {
- r->cpoints2 = r->npoints;
- r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2);
- if (r->points2 == NULL) return;
- }
-
- memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints);
- r->npoints2 = r->npoints;
-}
-
-static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1)
-{
- NSVGedge* e;
-
- // Skip horizontal edges
- if (y0 == y1)
- return;
-
- if (r->nedges+1 > r->cedges) {
- r->cedges = r->cedges > 0 ? r->cedges * 2 : 64;
- r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges);
- if (r->edges == NULL) return;
- }
-
- e = &r->edges[r->nedges];
- r->nedges++;
-
- if (y0 < y1) {
- e->x0 = x0;
- e->y0 = y0;
- e->x1 = x1;
- e->y1 = y1;
- e->dir = 1;
- } else {
- e->x0 = x1;
- e->y0 = y1;
- e->x1 = x0;
- e->y1 = y0;
- e->dir = -1;
- }
-}
-
-static float nsvg__normalize(float *x, float* y)
-{
- float d = sqrtf((*x)*(*x) + (*y)*(*y));
- if (d > 1e-6f) {
- float id = 1.0f / d;
- *x *= id;
- *y *= id;
- }
- return d;
-}
-
-static float nsvg__absf(float x) { return x < 0 ? -x : x; }
-
-static void nsvg__flattenCubicBez(NSVGrasterizer* r,
- float x1, float y1, float x2, float y2,
- float x3, float y3, float x4, float y4,
- int level, int type)
-{
- float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234;
- float dx,dy,d2,d3;
-
- if (level > 10) return;
-
- x12 = (x1+x2)*0.5f;
- y12 = (y1+y2)*0.5f;
- x23 = (x2+x3)*0.5f;
- y23 = (y2+y3)*0.5f;
- x34 = (x3+x4)*0.5f;
- y34 = (y3+y4)*0.5f;
- x123 = (x12+x23)*0.5f;
- y123 = (y12+y23)*0.5f;
-
- dx = x4 - x1;
- dy = y4 - y1;
- d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx));
- d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx));
-
- if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) {
- nsvg__addPathPoint(r, x4, y4, type);
- return;
- }
-
- x234 = (x23+x34)*0.5f;
- y234 = (y23+y34)*0.5f;
- x1234 = (x123+x234)*0.5f;
- y1234 = (y123+y234)*0.5f;
-
- nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0);
- nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type);
-}
-
-static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale)
-{
- int i, j;
- NSVGpath* path;
-
- for (path = shape->paths; path != NULL; path = path->next) {
- r->npoints = 0;
- // Flatten path
- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
- for (i = 0; i < path->npts-1; i += 3) {
- float* p = &path->pts[i*2];
- nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0);
- }
- // Close path
- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0);
- // Build edges
- for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
- nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
- }
-}
-
-enum NSVGpointFlags
-{
- NSVG_PT_CORNER = 0x01,
- NSVG_PT_BEVEL = 0x02,
- NSVG_PT_LEFT = 0x04
-};
-
-static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
-{
- float w = lineWidth * 0.5f;
- float dx = p1->x - p0->x;
- float dy = p1->y - p0->y;
- float len = nsvg__normalize(&dx, &dy);
- float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f;
- float dlx = dy, dly = -dx;
- float lx = px - dlx*w, ly = py - dly*w;
- float rx = px + dlx*w, ry = py + dly*w;
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
-{
- float w = lineWidth * 0.5f;
- float px = p->x, py = p->y;
- float dlx = dy, dly = -dx;
- float lx = px - dlx*w, ly = py - dly*w;
- float rx = px + dlx*w, ry = py + dly*w;
-
- nsvg__addEdge(r, lx, ly, rx, ry);
-
- if (connect) {
- nsvg__addEdge(r, left->x, left->y, lx, ly);
- nsvg__addEdge(r, rx, ry, right->x, right->y);
- }
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect)
-{
- float w = lineWidth * 0.5f;
- float px = p->x - dx*w, py = p->y - dy*w;
- float dlx = dy, dly = -dx;
- float lx = px - dlx*w, ly = py - dly*w;
- float rx = px + dlx*w, ry = py + dly*w;
-
- nsvg__addEdge(r, lx, ly, rx, ry);
-
- if (connect) {
- nsvg__addEdge(r, left->x, left->y, lx, ly);
- nsvg__addEdge(r, rx, ry, right->x, right->y);
- }
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-#ifndef NSVG_PI
-#define NSVG_PI (3.14159265358979323846264338327f)
-#endif
-
-static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect)
-{
- int i;
- float w = lineWidth * 0.5f;
- float px = p->x, py = p->y;
- float dlx = dy, dly = -dx;
- float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0;
-
- for (i = 0; i < ncap; i++) {
- float a = (float)i/(float)(ncap-1)*NSVG_PI;
- float ax = cosf(a) * w, ay = sinf(a) * w;
- float x = px - dlx*ax - dx*ay;
- float y = py - dly*ax - dy*ay;
-
- if (i > 0)
- nsvg__addEdge(r, prevx, prevy, x, y);
-
- prevx = x;
- prevy = y;
-
- if (i == 0) {
- lx = x; ly = y;
- } else if (i == ncap-1) {
- rx = x; ry = y;
- }
- }
-
- if (connect) {
- nsvg__addEdge(r, left->x, left->y, lx, ly);
- nsvg__addEdge(r, rx, ry, right->x, right->y);
- }
-
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
-{
- float w = lineWidth * 0.5f;
- float dlx0 = p0->dy, dly0 = -p0->dx;
- float dlx1 = p1->dy, dly1 = -p1->dx;
- float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w);
- float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w);
- float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w);
- float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w);
-
- nsvg__addEdge(r, lx0, ly0, left->x, left->y);
- nsvg__addEdge(r, lx1, ly1, lx0, ly0);
-
- nsvg__addEdge(r, right->x, right->y, rx0, ry0);
- nsvg__addEdge(r, rx0, ry0, rx1, ry1);
-
- left->x = lx1; left->y = ly1;
- right->x = rx1; right->y = ry1;
-}
-
-static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth)
-{
- float w = lineWidth * 0.5f;
- float dlx0 = p0->dy, dly0 = -p0->dx;
- float dlx1 = p1->dy, dly1 = -p1->dx;
- float lx0, rx0, lx1, rx1;
- float ly0, ry0, ly1, ry1;
-
- if (p1->flags & NSVG_PT_LEFT) {
- lx0 = lx1 = p1->x - p1->dmx * w;
- ly0 = ly1 = p1->y - p1->dmy * w;
- nsvg__addEdge(r, lx1, ly1, left->x, left->y);
-
- rx0 = p1->x + (dlx0 * w);
- ry0 = p1->y + (dly0 * w);
- rx1 = p1->x + (dlx1 * w);
- ry1 = p1->y + (dly1 * w);
- nsvg__addEdge(r, right->x, right->y, rx0, ry0);
- nsvg__addEdge(r, rx0, ry0, rx1, ry1);
- } else {
- lx0 = p1->x - (dlx0 * w);
- ly0 = p1->y - (dly0 * w);
- lx1 = p1->x - (dlx1 * w);
- ly1 = p1->y - (dly1 * w);
- nsvg__addEdge(r, lx0, ly0, left->x, left->y);
- nsvg__addEdge(r, lx1, ly1, lx0, ly0);
-
- rx0 = rx1 = p1->x + p1->dmx * w;
- ry0 = ry1 = p1->y + p1->dmy * w;
- nsvg__addEdge(r, right->x, right->y, rx1, ry1);
- }
-
- left->x = lx1; left->y = ly1;
- right->x = rx1; right->y = ry1;
-}
-
-static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap)
-{
- int i, n;
- float w = lineWidth * 0.5f;
- float dlx0 = p0->dy, dly0 = -p0->dx;
- float dlx1 = p1->dy, dly1 = -p1->dx;
- float a0 = atan2f(dly0, dlx0);
- float a1 = atan2f(dly1, dlx1);
- float da = a1 - a0;
- float lx, ly, rx, ry;
-
- if (da < NSVG_PI) da += NSVG_PI*2;
- if (da > NSVG_PI) da -= NSVG_PI*2;
-
- n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap);
- if (n < 2) n = 2;
- if (n > ncap) n = ncap;
-
- lx = left->x;
- ly = left->y;
- rx = right->x;
- ry = right->y;
-
- for (i = 0; i < n; i++) {
- float u = (float)i/(float)(n-1);
- float a = a0 + u*da;
- float ax = cosf(a) * w, ay = sinf(a) * w;
- float lx1 = p1->x - ax, ly1 = p1->y - ay;
- float rx1 = p1->x + ax, ry1 = p1->y + ay;
-
- nsvg__addEdge(r, lx1, ly1, lx, ly);
- nsvg__addEdge(r, rx, ry, rx1, ry1);
-
- lx = lx1; ly = ly1;
- rx = rx1; ry = ry1;
- }
-
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth)
-{
- float w = lineWidth * 0.5f;
- float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w);
- float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w);
-
- nsvg__addEdge(r, lx, ly, left->x, left->y);
- nsvg__addEdge(r, right->x, right->y, rx, ry);
-
- left->x = lx; left->y = ly;
- right->x = rx; right->y = ry;
-}
-
-static int nsvg__curveDivs(float r, float arc, float tol)
-{
- float da = acosf(r / (r + tol)) * 2.0f;
- int divs = (int)ceilf(arc / da);
- if (divs < 2) divs = 2;
- return divs;
-}
-
-static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth)
-{
- int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle.
- NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0};
- NSVGpoint* p0, *p1;
- int j, s, e;
-
- // Build stroke edges
- if (closed) {
- // Looping
- p0 = &points[npoints-1];
- p1 = &points[0];
- s = 0;
- e = npoints;
- } else {
- // Add cap
- p0 = &points[0];
- p1 = &points[1];
- s = 1;
- e = npoints-1;
- }
-
- if (closed) {
- nsvg__initClosed(&left, &right, p0, p1, lineWidth);
- firstLeft = left;
- firstRight = right;
- } else {
- // Add cap
- float dx = p1->x - p0->x;
- float dy = p1->y - p0->y;
- nsvg__normalize(&dx, &dy);
- if (lineCap == NSVG_CAP_BUTT)
- nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
- else if (lineCap == NSVG_CAP_SQUARE)
- nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0);
- else if (lineCap == NSVG_CAP_ROUND)
- nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0);
- }
-
- for (j = s; j < e; ++j) {
- if (p1->flags & NSVG_PT_CORNER) {
- if (lineJoin == NSVG_JOIN_ROUND)
- nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap);
- else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL))
- nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth);
- else
- nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth);
- } else {
- nsvg__straightJoin(r, &left, &right, p1, lineWidth);
- }
- p0 = p1++;
- }
-
- if (closed) {
- // Loop it
- nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y);
- nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y);
- } else {
- // Add cap
- float dx = p1->x - p0->x;
- float dy = p1->y - p0->y;
- nsvg__normalize(&dx, &dy);
- if (lineCap == NSVG_CAP_BUTT)
- nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
- else if (lineCap == NSVG_CAP_SQUARE)
- nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1);
- else if (lineCap == NSVG_CAP_ROUND)
- nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1);
- }
-}
-
-static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin)
-{
- int i, j;
- NSVGpoint* p0, *p1;
-
- p0 = &r->points[r->npoints-1];
- p1 = &r->points[0];
- for (i = 0; i < r->npoints; i++) {
- // Calculate segment direction and length
- p0->dx = p1->x - p0->x;
- p0->dy = p1->y - p0->y;
- p0->len = nsvg__normalize(&p0->dx, &p0->dy);
- // Advance
- p0 = p1++;
- }
-
- // calculate joins
- p0 = &r->points[r->npoints-1];
- p1 = &r->points[0];
- for (j = 0; j < r->npoints; j++) {
- float dlx0, dly0, dlx1, dly1, dmr2, cross;
- dlx0 = p0->dy;
- dly0 = -p0->dx;
- dlx1 = p1->dy;
- dly1 = -p1->dx;
- // Calculate extrusions
- p1->dmx = (dlx0 + dlx1) * 0.5f;
- p1->dmy = (dly0 + dly1) * 0.5f;
- dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy;
- if (dmr2 > 0.000001f) {
- float s2 = 1.0f / dmr2;
- if (s2 > 600.0f) {
- s2 = 600.0f;
- }
- p1->dmx *= s2;
- p1->dmy *= s2;
- }
-
- // Clear flags, but keep the corner.
- p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0;
-
- // Keep track of left turns.
- cross = p1->dx * p0->dy - p0->dx * p1->dy;
- if (cross > 0.0f)
- p1->flags |= NSVG_PT_LEFT;
-
- // Check to see if the corner needs to be beveled.
- if (p1->flags & NSVG_PT_CORNER) {
- if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) {
- p1->flags |= NSVG_PT_BEVEL;
- }
- }
-
- p0 = p1++;
- }
-}
-
-static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale)
-{
- int i, j, closed;
- NSVGpath* path;
- NSVGpoint* p0, *p1;
- float miterLimit = shape->miterLimit;
- int lineJoin = shape->strokeLineJoin;
- int lineCap = shape->strokeLineCap;
- float lineWidth = shape->strokeWidth * scale;
-
- for (path = shape->paths; path != NULL; path = path->next) {
- // Flatten path
- r->npoints = 0;
- nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER);
- for (i = 0; i < path->npts-1; i += 3) {
- float* p = &path->pts[i*2];
- nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER);
- }
- if (r->npoints < 2)
- continue;
-
- closed = path->closed;
-
- // If the first and last points are the same, remove the last, mark as closed path.
- p0 = &r->points[r->npoints-1];
- p1 = &r->points[0];
- if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
- r->npoints--;
- p0 = &r->points[r->npoints-1];
- closed = 1;
- }
-
- if (shape->strokeDashCount > 0) {
- int idash = 0, dashState = 1;
- float totalDist = 0, dashLen, allDashLen, dashOffset;
- NSVGpoint cur;
-
- if (closed)
- nsvg__appendPathPoint(r, r->points[0]);
-
- // Duplicate points -> points2.
- nsvg__duplicatePoints(r);
-
- r->npoints = 0;
- cur = r->points2[0];
- nsvg__appendPathPoint(r, cur);
-
- // Figure out dash offset.
- allDashLen = 0;
- for (j = 0; j < shape->strokeDashCount; j++)
- allDashLen += shape->strokeDashArray[j];
- if (shape->strokeDashCount & 1)
- allDashLen *= 2.0f;
- // Find location inside pattern
- dashOffset = fmodf(shape->strokeDashOffset, allDashLen);
- if (dashOffset < 0.0f)
- dashOffset += allDashLen;
-
- while (dashOffset > shape->strokeDashArray[idash]) {
- dashOffset -= shape->strokeDashArray[idash];
- idash = (idash + 1) % shape->strokeDashCount;
- }
- dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale;
-
- for (j = 1; j < r->npoints2; ) {
- float dx = r->points2[j].x - cur.x;
- float dy = r->points2[j].y - cur.y;
- float dist = sqrtf(dx*dx + dy*dy);
-
- if ((totalDist + dist) > dashLen) {
- // Calculate intermediate point
- float d = (dashLen - totalDist) / dist;
- float x = cur.x + dx * d;
- float y = cur.y + dy * d;
- nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);
-
- // Stroke
- if (r->npoints > 1 && dashState) {
- nsvg__prepareStroke(r, miterLimit, lineJoin);
- nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
- }
- // Advance dash pattern
- dashState = !dashState;
- idash = (idash+1) % shape->strokeDashCount;
- dashLen = shape->strokeDashArray[idash] * scale;
- // Restart
- cur.x = x;
- cur.y = y;
- cur.flags = NSVG_PT_CORNER;
- totalDist = 0.0f;
- r->npoints = 0;
- nsvg__appendPathPoint(r, cur);
- } else {
- totalDist += dist;
- cur = r->points2[j];
- nsvg__appendPathPoint(r, cur);
- j++;
- }
- }
- // Stroke any leftover path
- if (r->npoints > 1 && dashState)
- nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth);
- } else {
- nsvg__prepareStroke(r, miterLimit, lineJoin);
- nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth);
- }
- }
-}
-
-static int nsvg__cmpEdge(const void *p, const void *q)
-{
- const NSVGedge* a = (const NSVGedge*)p;
- const NSVGedge* b = (const NSVGedge*)q;
-
- if (a->y0 < b->y0) return -1;
- if (a->y0 > b->y0) return 1;
- return 0;
-}
-
-
-static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint)
-{
- NSVGactiveEdge* z;
-
- if (r->freelist != NULL) {
- // Restore from freelist.
- z = r->freelist;
- r->freelist = z->next;
- } else {
- // Alloc new edge.
- z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge));
- if (z == NULL) return NULL;
- }
-
- float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
-// STBTT_assert(e->y0 <= start_point);
- // round dx down to avoid going too far
- if (dxdy < 0)
- z->dx = (int)(-floorf(NSVG__FIX * -dxdy));
- else
- z->dx = (int)floorf(NSVG__FIX * dxdy);
- z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0)));
-// z->x -= off_x * FIX;
- z->ey = e->y1;
- z->next = 0;
- z->dir = e->dir;
-
- return z;
-}
-
-static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z)
-{
- z->next = r->freelist;
- r->freelist = z;
-}
-
-static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax)
-{
- int i = x0 >> NSVG__FIXSHIFT;
- int j = x1 >> NSVG__FIXSHIFT;
- if (i < *xmin) *xmin = i;
- if (j > *xmax) *xmax = j;
- if (i < len && j >= 0) {
- if (i == j) {
- // x0,x1 are the same pixel, so compute combined coverage
- scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT));
- } else {
- if (i >= 0) // add antialiasing for x0
- scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT));
- else
- i = -1; // clip
-
- if (j < len) // add antialiasing for x1
- scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT));
- else
- j = len; // clip
-
- for (++i; i < j; ++i) // fill pixels between x0 and x1
- scanline[i] = (unsigned char)(scanline[i] + maxWeight);
- }
- }
-}
-
-// note: this routine clips fills that extend off the edges... ideally this
-// wouldn't happen, but it could happen if the truetype glyph bounding boxes
-// are wrong, or if the user supplies a too-small bitmap
-static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule)
-{
- // non-zero winding fill
- int x0 = 0, w = 0;
-
- if (fillRule == NSVG_FILLRULE_NONZERO) {
- // Non-zero
- while (e != NULL) {
- if (w == 0) {
- // if we're currently at zero, we need to record the edge start point
- x0 = e->x; w += e->dir;
- } else {
- int x1 = e->x; w += e->dir;
- // if we went to zero, we need to draw
- if (w == 0)
- nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
- }
- e = e->next;
- }
- } else if (fillRule == NSVG_FILLRULE_EVENODD) {
- // Even-odd
- while (e != NULL) {
- if (w == 0) {
- // if we're currently at zero, we need to record the edge start point
- x0 = e->x; w = 1;
- } else {
- int x1 = e->x; w = 0;
- nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax);
- }
- e = e->next;
- }
- }
-}
-
-static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); }
-
-static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
-{
- return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24);
-}
-
-static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u)
-{
- int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
- int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8;
- int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8;
- int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8;
- int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8;
- return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
-}
-
-static unsigned int nsvg__applyOpacity(unsigned int c, float u)
-{
- int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f);
- int r = (c) & 0xff;
- int g = (c>>8) & 0xff;
- int b = (c>>16) & 0xff;
- int a = (((c>>24) & 0xff)*iu) >> 8;
- return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a);
-}
-
-static inline int nsvg__div255(int x)
-{
- return ((x+1) * 257) >> 16;
-}
-
-static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y,
- float tx, float ty, float scale, NSVGcachedPaint* cache)
-{
-
- if (cache->type == NSVG_PAINT_COLOR) {
- int i, cr, cg, cb, ca;
- cr = cache->colors[0] & 0xff;
- cg = (cache->colors[0] >> 8) & 0xff;
- cb = (cache->colors[0] >> 16) & 0xff;
- ca = (cache->colors[0] >> 24) & 0xff;
-
- for (i = 0; i < count; i++) {
- int r,g,b;
- int a = nsvg__div255((int)cover[0] * ca);
- int ia = 255 - a;
- // Premultiply
- r = nsvg__div255(cr * a);
- g = nsvg__div255(cg * a);
- b = nsvg__div255(cb * a);
-
- // Blend over
- r += nsvg__div255(ia * (int)dst[0]);
- g += nsvg__div255(ia * (int)dst[1]);
- b += nsvg__div255(ia * (int)dst[2]);
- a += nsvg__div255(ia * (int)dst[3]);
-
- dst[0] = (unsigned char)r;
- dst[1] = (unsigned char)g;
- dst[2] = (unsigned char)b;
- dst[3] = (unsigned char)a;
-
- cover++;
- dst += 4;
- }
- } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) {
- // TODO: spread modes.
- // TODO: plenty of opportunities to optimize.
- float fx, fy, dx, gy;
- float* t = cache->xform;
- int i, cr, cg, cb, ca;
- unsigned int c;
-
- fx = ((float)x - tx) / scale;
- fy = ((float)y - ty) / scale;
- dx = 1.0f / scale;
-
- for (i = 0; i < count; i++) {
- int r,g,b,a,ia;
- gy = fx*t[1] + fy*t[3] + t[5];
- c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)];
- cr = (c) & 0xff;
- cg = (c >> 8) & 0xff;
- cb = (c >> 16) & 0xff;
- ca = (c >> 24) & 0xff;
-
- a = nsvg__div255((int)cover[0] * ca);
- ia = 255 - a;
-
- // Premultiply
- r = nsvg__div255(cr * a);
- g = nsvg__div255(cg * a);
- b = nsvg__div255(cb * a);
-
- // Blend over
- r += nsvg__div255(ia * (int)dst[0]);
- g += nsvg__div255(ia * (int)dst[1]);
- b += nsvg__div255(ia * (int)dst[2]);
- a += nsvg__div255(ia * (int)dst[3]);
-
- dst[0] = (unsigned char)r;
- dst[1] = (unsigned char)g;
- dst[2] = (unsigned char)b;
- dst[3] = (unsigned char)a;
-
- cover++;
- dst += 4;
- fx += dx;
- }
- } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) {
- // TODO: spread modes.
- // TODO: plenty of opportunities to optimize.
- // TODO: focus (fx,fy)
- float fx, fy, dx, gx, gy, gd;
- float* t = cache->xform;
- int i, cr, cg, cb, ca;
- unsigned int c;
-
- fx = ((float)x - tx) / scale;
- fy = ((float)y - ty) / scale;
- dx = 1.0f / scale;
-
- for (i = 0; i < count; i++) {
- int r,g,b,a,ia;
- gx = fx*t[0] + fy*t[2] + t[4];
- gy = fx*t[1] + fy*t[3] + t[5];
- gd = sqrtf(gx*gx + gy*gy);
- c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)];
- cr = (c) & 0xff;
- cg = (c >> 8) & 0xff;
- cb = (c >> 16) & 0xff;
- ca = (c >> 24) & 0xff;
-
- a = nsvg__div255((int)cover[0] * ca);
- ia = 255 - a;
-
- // Premultiply
- r = nsvg__div255(cr * a);
- g = nsvg__div255(cg * a);
- b = nsvg__div255(cb * a);
-
- // Blend over
- r += nsvg__div255(ia * (int)dst[0]);
- g += nsvg__div255(ia * (int)dst[1]);
- b += nsvg__div255(ia * (int)dst[2]);
- a += nsvg__div255(ia * (int)dst[3]);
-
- dst[0] = (unsigned char)r;
- dst[1] = (unsigned char)g;
- dst[2] = (unsigned char)b;
- dst[3] = (unsigned char)a;
-
- cover++;
- dst += 4;
- fx += dx;
- }
- }
-}
-
-static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule)
-{
- NSVGactiveEdge *active = NULL;
- int y, s;
- int e = 0;
- int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline
- int xmin, xmax;
-
- for (y = 0; y < r->height; y++) {
- memset(r->scanline, 0, r->width);
- xmin = r->width;
- xmax = 0;
- for (s = 0; s < NSVG__SUBSAMPLES; ++s) {
- // find center of pixel for this scanline
- float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f;
- NSVGactiveEdge **step = &active;
-
- // update all active edges;
- // remove all active edges that terminate before the center of this scanline
- while (*step) {
- NSVGactiveEdge *z = *step;
- if (z->ey <= scany) {
- *step = z->next; // delete from list
-// NSVG__assert(z->valid);
- nsvg__freeActive(r, z);
- } else {
- z->x += z->dx; // advance to position for current scanline
- step = &((*step)->next); // advance through list
- }
- }
-
- // resort the list if needed
- for (;;) {
- int changed = 0;
- step = &active;
- while (*step && (*step)->next) {
- if ((*step)->x > (*step)->next->x) {
- NSVGactiveEdge* t = *step;
- NSVGactiveEdge* q = t->next;
- t->next = q->next;
- q->next = t;
- *step = q;
- changed = 1;
- }
- step = &(*step)->next;
- }
- if (!changed) break;
- }
-
- // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
- while (e < r->nedges && r->edges[e].y0 <= scany) {
- if (r->edges[e].y1 > scany) {
- NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany);
- if (z == NULL) break;
- // find insertion point
- if (active == NULL) {
- active = z;
- } else if (z->x < active->x) {
- // insert at front
- z->next = active;
- active = z;
- } else {
- // find thing to insert AFTER
- NSVGactiveEdge* p = active;
- while (p->next && p->next->x < z->x)
- p = p->next;
- // at this point, p->next->x is NOT < z->x
- z->next = p->next;
- p->next = z;
- }
- }
- e++;
- }
-
- // now process all active edges in non-zero fashion
- if (active != NULL)
- nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule);
- }
- // Blit
- if (xmin < 0) xmin = 0;
- if (xmax > r->width-1) xmax = r->width-1;
- if (xmin <= xmax) {
- nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache);
- }
- }
-
-}
-
-static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride)
-{
- int x,y;
-
- // Unpremultiply
- for (y = 0; y < h; y++) {
- unsigned char *row = &image[y*stride];
- for (x = 0; x < w; x++) {
- int r = row[0], g = row[1], b = row[2], a = row[3];
- if (a != 0) {
- row[0] = (unsigned char)(r*255/a);
- row[1] = (unsigned char)(g*255/a);
- row[2] = (unsigned char)(b*255/a);
- }
- row += 4;
- }
- }
-
- // Defringe
- for (y = 0; y < h; y++) {
- unsigned char *row = &image[y*stride];
- for (x = 0; x < w; x++) {
- int r = 0, g = 0, b = 0, a = row[3], n = 0;
- if (a == 0) {
- if (x-1 > 0 && row[-1] != 0) {
- r += row[-4];
- g += row[-3];
- b += row[-2];
- n++;
- }
- if (x+1 < w && row[7] != 0) {
- r += row[4];
- g += row[5];
- b += row[6];
- n++;
- }
- if (y-1 > 0 && row[-stride+3] != 0) {
- r += row[-stride];
- g += row[-stride+1];
- b += row[-stride+2];
- n++;
- }
- if (y+1 < h && row[stride+3] != 0) {
- r += row[stride];
- g += row[stride+1];
- b += row[stride+2];
- n++;
- }
- if (n > 0) {
- row[0] = (unsigned char)(r/n);
- row[1] = (unsigned char)(g/n);
- row[2] = (unsigned char)(b/n);
- }
- }
- row += 4;
- }
- }
-}
-
-
-static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity)
-{
- int i, j;
- NSVGgradient* grad;
-
- cache->type = paint->type;
-
- if (paint->type == NSVG_PAINT_COLOR) {
- cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
- return;
- }
-
- grad = paint->gradient;
-
- cache->spread = grad->spread;
- memcpy(cache->xform, grad->xform, sizeof(float)*6);
-
- if (grad->nstops == 0) {
- for (i = 0; i < 256; i++)
- cache->colors[i] = 0;
- } if (grad->nstops == 1) {
- for (i = 0; i < 256; i++)
- cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity);
- } else {
- unsigned int ca, cb = 0;
- float ua, ub, du, u;
- int ia, ib, count;
-
- ca = nsvg__applyOpacity(grad->stops[0].color, opacity);
- ua = nsvg__clampf(grad->stops[0].offset, 0, 1);
- ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1);
- ia = (int)(ua * 255.0f);
- ib = (int)(ub * 255.0f);
- for (i = 0; i < ia; i++) {
- cache->colors[i] = ca;
- }
-
- for (i = 0; i < grad->nstops-1; i++) {
- ca = nsvg__applyOpacity(grad->stops[i].color, opacity);
- cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity);
- ua = nsvg__clampf(grad->stops[i].offset, 0, 1);
- ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1);
- ia = (int)(ua * 255.0f);
- ib = (int)(ub * 255.0f);
- count = ib - ia;
- if (count <= 0) continue;
- u = 0;
- du = 1.0f / (float)count;
- for (j = 0; j < count; j++) {
- cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
- u += du;
- }
- }
-
- for (i = ib; i < 256; i++)
- cache->colors[i] = cb;
- }
-
-}
-
-/*
-static void dumpEdges(NSVGrasterizer* r, const char* name)
-{
- float xmin = 0, xmax = 0, ymin = 0, ymax = 0;
- NSVGedge *e = NULL;
- int i;
- if (r->nedges == 0) return;
- FILE* fp = fopen(name, "w");
- if (fp == NULL) return;
-
- xmin = xmax = r->edges[0].x0;
- ymin = ymax = r->edges[0].y0;
- for (i = 0; i < r->nedges; i++) {
- e = &r->edges[i];
- xmin = nsvg__minf(xmin, e->x0);
- xmin = nsvg__minf(xmin, e->x1);
- xmax = nsvg__maxf(xmax, e->x0);
- xmax = nsvg__maxf(xmax, e->x1);
- ymin = nsvg__minf(ymin, e->y0);
- ymin = nsvg__minf(ymin, e->y1);
- ymax = nsvg__maxf(ymax, e->y0);
- ymax = nsvg__maxf(ymax, e->y1);
- }
-
- fprintf(fp, "");
- fclose(fp);
-}
-*/
-
-void nsvgRasterize(NSVGrasterizer* r,
- NSVGimage* image, float tx, float ty, float scale,
- unsigned char* dst, int w, int h, int stride)
-{
- NSVGshape *shape = NULL;
- NSVGedge *e = NULL;
- NSVGcachedPaint cache;
- int i;
-
- r->bitmap = dst;
- r->width = w;
- r->height = h;
- r->stride = stride;
-
- if (w > r->cscanline) {
- r->cscanline = w;
- r->scanline = (unsigned char*)realloc(r->scanline, w);
- if (r->scanline == NULL) return;
- }
-
- for (i = 0; i < h; i++)
- memset(&dst[i*stride], 0, w*4);
-
- for (shape = image->shapes; shape != NULL; shape = shape->next) {
- if (!(shape->flags & NSVG_FLAGS_VISIBLE))
- continue;
-
- if (shape->fill.type != NSVG_PAINT_NONE) {
- nsvg__resetPool(r);
- r->freelist = NULL;
- r->nedges = 0;
-
- nsvg__flattenShape(r, shape, scale);
-
- // Scale and translate edges
- for (i = 0; i < r->nedges; i++) {
- e = &r->edges[i];
- e->x0 = tx + e->x0;
- e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
- e->x1 = tx + e->x1;
- e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
- }
-
- // Rasterize edges
- if (r->nedges != 0)
- qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
-
- // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
- nsvg__initPaint(&cache, &shape->fill, shape->opacity);
-
- nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule);
- }
- if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
- nsvg__resetPool(r);
- r->freelist = NULL;
- r->nedges = 0;
-
- nsvg__flattenShapeStroke(r, shape, scale);
-
-// dumpEdges(r, "edge.svg");
-
- // Scale and translate edges
- for (i = 0; i < r->nedges; i++) {
- e = &r->edges[i];
- e->x0 = tx + e->x0;
- e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
- e->x1 = tx + e->x1;
- e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
- }
-
- // Rasterize edges
- if (r->nedges != 0)
- qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
-
- // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
- nsvg__initPaint(&cache, &shape->stroke, shape->opacity);
-
- nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
- }
- }
-
- nsvg__unpremultiplyAlpha(dst, w, h, stride);
-
- r->bitmap = NULL;
- r->width = 0;
- r->height = 0;
- r->stride = 0;
-}
-
-#endif // NANOSVGRAST_IMPLEMENTATION
-
-#endif // NANOSVGRAST_H
diff --git a/src/external/par_shapes.h b/src/external/par_shapes.h
index 994a605a9..d5309137b 100644
--- a/src/external/par_shapes.h
+++ b/src/external/par_shapes.h
@@ -1130,7 +1130,7 @@ static par_shapes__rule* par_shapes__pick_rule(const char* name,
total += rule->weight;
}
}
- float r = (float) rand() / RAND_MAX;
+ float r = (float) rand() / (float) RAND_MAX;
float t = 0;
for (int i = 0; i < nrules; i++) {
rule = rules + i;
diff --git a/src/external/rl_gputex.h b/src/external/rl_gputex.h
index 6b26d1c8d..4043a9239 100644
--- a/src/external/rl_gputex.h
+++ b/src/external/rl_gputex.h
@@ -185,6 +185,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
if (header->ddspf.flags == 0x40) // No alpha channel
{
int data_size = image_pixel_size*sizeof(unsigned short);
+ if (header->mipmap_count > 1) data_size = data_size + data_size / 3;
image_data = RL_MALLOC(data_size);
memcpy(image_data, file_data_ptr, data_size);
@@ -196,6 +197,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
if (header->ddspf.a_bit_mask == 0x8000) // 1bit alpha
{
int data_size = image_pixel_size*sizeof(unsigned short);
+ if (header->mipmap_count > 1) data_size = data_size + data_size / 3;
image_data = RL_MALLOC(data_size);
memcpy(image_data, file_data_ptr, data_size);
@@ -215,6 +217,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
else if (header->ddspf.a_bit_mask == 0xf000) // 4bit alpha
{
int data_size = image_pixel_size*sizeof(unsigned short);
+ if (header->mipmap_count > 1) data_size = data_size + data_size / 3;
image_data = RL_MALLOC(data_size);
memcpy(image_data, file_data_ptr, data_size);
@@ -236,6 +239,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
else if ((header->ddspf.flags == 0x40) && (header->ddspf.rgb_bit_count == 24)) // DDS_RGB, no compressed
{
int data_size = image_pixel_size*3*sizeof(unsigned char);
+ if (header->mipmap_count > 1) data_size = data_size + data_size / 3;
image_data = RL_MALLOC(data_size);
memcpy(image_data, file_data_ptr, data_size);
@@ -245,6 +249,7 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
else if ((header->ddspf.flags == 0x41) && (header->ddspf.rgb_bit_count == 32)) // DDS_RGBA, no compressed
{
int data_size = image_pixel_size*4*sizeof(unsigned char);
+ if (header->mipmap_count > 1) data_size = data_size + data_size / 3;
image_data = RL_MALLOC(data_size);
memcpy(image_data, file_data_ptr, data_size);
@@ -265,9 +270,11 @@ void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_
}
else if (((header->ddspf.flags == 0x04) || (header->ddspf.flags == 0x05)) && (header->ddspf.fourcc > 0)) // Compressed
{
- // NOTE: This forces only 1 mipmap to be loaded which is not really correct but it works
- int data_size = (header->pitch_or_linear_size < file_size - 0x80) ? header->pitch_or_linear_size : file_size - 0x80;
- *mips = 1;
+ int data_size = 0;
+
+ // Calculate data size, including all mipmaps
+ if (header->mipmap_count > 1) data_size = header->pitch_or_linear_size + header->pitch_or_linear_size / 3;
+ else data_size = header->pitch_or_linear_size;
image_data = RL_MALLOC(data_size*sizeof(unsigned char));
diff --git a/src/external/stb_image_resize2.h b/src/external/stb_image_resize2.h
index e0c428246..ae8d730bf 100644
--- a/src/external/stb_image_resize2.h
+++ b/src/external/stb_image_resize2.h
@@ -1,9 +1,9 @@
-/* stb_image_resize2 - v2.01 - public domain image resizing
-
- by Jeff Roberts (v2) and Jorge L Rodriguez
+/* stb_image_resize2 - v2.10 - public domain image resizing
+
+ by Jeff Roberts (v2) and Jorge L Rodriguez
http://github.com/nothings/stb
- Can be threaded with the extended API. SSE2, AVX, Neon and WASM SIMD support. Only
+ Can be threaded with the extended API. SSE2, AVX, Neon and WASM SIMD support. Only
scaling and translation is supported, no rotations or shears.
COMPILING & LINKING
@@ -67,60 +67,60 @@
ADDITIONAL DOCUMENTATION
MEMORY ALLOCATION
- By default, we use malloc and free for memory allocation. To override the
+ By default, we use malloc and free for memory allocation. To override the
memory allocation, before the implementation #include, add a:
#define STBIR_MALLOC(size,user_data) ...
#define STBIR_FREE(ptr,user_data) ...
- Each resize makes exactly one call to malloc/free (unless you use the
+ Each resize makes exactly one call to malloc/free (unless you use the
extended API where you can do one allocation for many resizes). Under
address sanitizer, we do separate allocations to find overread/writes.
PERFORMANCE
This library was written with an emphasis on performance. When testing
- stb_image_resize with RGBA, the fastest mode is STBIR_4CHANNEL with
+ stb_image_resize with RGBA, the fastest mode is STBIR_4CHANNEL with
STBIR_TYPE_UINT8 pixels and CLAMPed edges (which is what many other resize
- libs do by default). Also, make sure SIMD is turned on of course (default
+ libs do by default). Also, make sure SIMD is turned on of course (default
for 64-bit targets). Avoid WRAP edge mode if you want the fastest speed.
This library also comes with profiling built-in. If you define STBIR_PROFILE,
- you can use the advanced API and get low-level profiling information by
+ you can use the advanced API and get low-level profiling information by
calling stbir_resize_extended_profile_info() or stbir_resize_split_profile_info()
after a resize.
SIMD
- Most of the routines have optimized SSE2, AVX, NEON and WASM versions.
+ Most of the routines have optimized SSE2, AVX, NEON and WASM versions.
- On Microsoft compilers, we automatically turn on SIMD for 64-bit x64 and
- ARM; for 32-bit x86 and ARM, you select SIMD mode by defining STBIR_SSE2 or
+ On Microsoft compilers, we automatically turn on SIMD for 64-bit x64 and
+ ARM; for 32-bit x86 and ARM, you select SIMD mode by defining STBIR_SSE2 or
STBIR_NEON. For AVX and AVX2, we auto-select it by detecting the /arch:AVX
- or /arch:AVX2 switches. You can also always manually turn SSE2, AVX or AVX2
+ or /arch:AVX2 switches. You can also always manually turn SSE2, AVX or AVX2
support on by defining STBIR_SSE2, STBIR_AVX or STBIR_AVX2.
On Linux, SSE2 and Neon is on by default for 64-bit x64 or ARM64. For 32-bit,
we select x86 SIMD mode by whether you have -msse2, -mavx or -mavx2 enabled
on the command line. For 32-bit ARM, you must pass -mfpu=neon-vfpv4 for both
- clang and GCC, but GCC also requires an additional -mfp16-format=ieee to
+ clang and GCC, but GCC also requires an additional -mfp16-format=ieee to
automatically enable NEON.
On x86 platforms, you can also define STBIR_FP16C to turn on FP16C instructions
for converting back and forth to half-floats. This is autoselected when we
- are using AVX2. Clang and GCC also require the -mf16c switch. ARM always uses
- the built-in half float hardware NEON instructions.
+ are using AVX2. Clang and GCC also require the -mf16c switch. ARM always uses
+ the built-in half float hardware NEON instructions.
- You can also tell us to use multiply-add instructions with STBIR_USE_FMA.
+ You can also tell us to use multiply-add instructions with STBIR_USE_FMA.
Because x86 doesn't always have fma, we turn it off by default to maintain
determinism across all platforms. If you don't care about non-FMA determinism
- and are willing to restrict yourself to more recent x86 CPUs (around the AVX
+ and are willing to restrict yourself to more recent x86 CPUs (around the AVX
timeframe), then fma will give you around a 15% speedup.
You can force off SIMD in all cases by defining STBIR_NO_SIMD. You can turn
off AVX or AVX2 specifically with STBIR_NO_AVX or STBIR_NO_AVX2. AVX is 10%
to 40% faster, and AVX2 is generally another 12%.
-
+
ALPHA CHANNEL
- Most of the resizing functions provide the ability to control how the alpha
+ Most of the resizing functions provide the ability to control how the alpha
channel of an image is processed.
When alpha represents transparency, it is important that when combining
@@ -167,33 +167,33 @@
stb_image_resize expects case #1 by default, applying alpha weighting to
images, expecting the input images to be unpremultiplied. This is what the
- COLOR+ALPHA buffer types tell the resizer to do.
+ COLOR+ALPHA buffer types tell the resizer to do.
- When you use the pixel layouts STBIR_RGBA, STBIR_BGRA, STBIR_ARGB,
- STBIR_ABGR, STBIR_RX, or STBIR_XR you are telling us that the pixels are
- non-premultiplied. In these cases, the resizer will alpha weight the colors
- (effectively creating the premultiplied image), do the filtering, and then
+ When you use the pixel layouts STBIR_RGBA, STBIR_BGRA, STBIR_ARGB,
+ STBIR_ABGR, STBIR_RX, or STBIR_XR you are telling us that the pixels are
+ non-premultiplied. In these cases, the resizer will alpha weight the colors
+ (effectively creating the premultiplied image), do the filtering, and then
convert back to non-premult on exit.
When you use the pixel layouts STBIR_RGBA_PM, STBIR_RGBA_PM, STBIR_RGBA_PM,
- STBIR_RGBA_PM, STBIR_RX_PM or STBIR_XR_PM, you are telling that the pixels
- ARE premultiplied. In this case, the resizer doesn't have to do the
- premultipling - it can filter directly on the input. This about twice as
- fast as the non-premultiplied case, so it's the right option if your data is
+ STBIR_RGBA_PM, STBIR_RX_PM or STBIR_XR_PM, you are telling that the pixels
+ ARE premultiplied. In this case, the resizer doesn't have to do the
+ premultipling - it can filter directly on the input. This about twice as
+ fast as the non-premultiplied case, so it's the right option if your data is
already setup correctly.
- When you use the pixel layout STBIR_4CHANNEL or STBIR_2CHANNEL, you are
- telling us that there is no channel that represents transparency; it may be
- RGB and some unrelated fourth channel that has been stored in the alpha
- channel, but it is actually not alpha. No special processing will be
- performed.
+ When you use the pixel layout STBIR_4CHANNEL or STBIR_2CHANNEL, you are
+ telling us that there is no channel that represents transparency; it may be
+ RGB and some unrelated fourth channel that has been stored in the alpha
+ channel, but it is actually not alpha. No special processing will be
+ performed.
- The difference between the generic 4 or 2 channel layouts, and the
+ The difference between the generic 4 or 2 channel layouts, and the
specialized _PM versions is with the _PM versions you are telling us that
the data *is* alpha, just don't premultiply it. That's important when
using SRGB pixel formats, we need to know where the alpha is, because
it is converted linearly (rather than with the SRGB converters).
-
+
Because alpha weighting produces the same effect as premultiplying, you
even have the option with non-premultiplied inputs to let the resizer
produce a premultiplied output. Because the intially computed alpha-weighted
@@ -201,10 +201,10 @@
than the normal path which un-premultiplies the output image as a final step.
Finally, when converting both in and out of non-premulitplied space (for
- example, when using STBIR_RGBA), we go to somewhat heroic measures to
- ensure that areas with zero alpha value pixels get something reasonable
- in the RGB values. If you don't care about the RGB values of zero alpha
- pixels, you can call the stbir_set_non_pm_alpha_speed_over_quality()
+ example, when using STBIR_RGBA), we go to somewhat heroic measures to
+ ensure that areas with zero alpha value pixels get something reasonable
+ in the RGB values. If you don't care about the RGB values of zero alpha
+ pixels, you can call the stbir_set_non_pm_alpha_speed_over_quality()
function - this runs a premultiplied resize about 25% faster. That said,
when you really care about speed, using premultiplied pixels for both in
and out (STBIR_RGBA_PM, etc) much faster than both of these premultiplied
@@ -218,38 +218,38 @@
layouts with the same number of channels.
DETERMINISM
- We commit to being deterministic (from x64 to ARM to scalar to SIMD, etc).
- This requires compiling with fast-math off (using at least /fp:precise).
+ We commit to being deterministic (from x64 to ARM to scalar to SIMD, etc).
+ This requires compiling with fast-math off (using at least /fp:precise).
Also, you must turn off fp-contracting (which turns mult+adds into fmas)!
- We attempt to do this with pragmas, but with Clang, you usually want to add
+ We attempt to do this with pragmas, but with Clang, you usually want to add
-ffp-contract=off to the command line as well.
- For 32-bit x86, you must use SSE and SSE2 codegen for determinism. That is,
- if the scalar x87 unit gets used at all, we immediately lose determinism.
+ For 32-bit x86, you must use SSE and SSE2 codegen for determinism. That is,
+ if the scalar x87 unit gets used at all, we immediately lose determinism.
On Microsoft Visual Studio 2008 and earlier, from what we can tell there is
- no way to be deterministic in 32-bit x86 (some x87 always leaks in, even
- with fp:strict). On 32-bit x86 GCC, determinism requires both -msse2 and
+ no way to be deterministic in 32-bit x86 (some x87 always leaks in, even
+ with fp:strict). On 32-bit x86 GCC, determinism requires both -msse2 and
-fpmath=sse.
Note that we will not be deterministic with float data containing NaNs -
- the NaNs will propagate differently on different SIMD and platforms.
+ the NaNs will propagate differently on different SIMD and platforms.
- If you turn on STBIR_USE_FMA, then we will be deterministic with other
- fma targets, but we will differ from non-fma targets (this is unavoidable,
- because a fma isn't simply an add with a mult - it also introduces a
- rounding difference compared to non-fma instruction sequences.
+ If you turn on STBIR_USE_FMA, then we will be deterministic with other
+ fma targets, but we will differ from non-fma targets (this is unavoidable,
+ because a fma isn't simply an add with a mult - it also introduces a
+ rounding difference compared to non-fma instruction sequences.
FLOAT PIXEL FORMAT RANGE
- Any range of values can be used for the non-alpha float data that you pass
- in (0 to 1, -1 to 1, whatever). However, if you are inputting float values
- but *outputting* bytes or shorts, you must use a range of 0 to 1 so that we
- scale back properly. The alpha channel must also be 0 to 1 for any format
- that does premultiplication prior to resizing.
+ Any range of values can be used for the non-alpha float data that you pass
+ in (0 to 1, -1 to 1, whatever). However, if you are inputting float values
+ but *outputting* bytes or shorts, you must use a range of 0 to 1 so that we
+ scale back properly. The alpha channel must also be 0 to 1 for any format
+ that does premultiplication prior to resizing.
- Note also that with float output, using filters with negative lobes, the
- output filtered values might go slightly out of range. You can define
- STBIR_FLOAT_LOW_CLAMP and/or STBIR_FLOAT_HIGH_CLAMP to specify the range
- to clamp to on output, if that's important.
+ Note also that with float output, using filters with negative lobes, the
+ output filtered values might go slightly out of range. You can define
+ STBIR_FLOAT_LOW_CLAMP and/or STBIR_FLOAT_HIGH_CLAMP to specify the range
+ to clamp to on output, if that's important.
MAX/MIN SCALE FACTORS
The input pixel resolutions are in integers, and we do the internal pointer
@@ -263,13 +263,13 @@
buffers).
FLIPPED IMAGES
- Stride is just the delta from one scanline to the next. This means you can
- use a negative stride to handle inverted images (point to the final
+ Stride is just the delta from one scanline to the next. This means you can
+ use a negative stride to handle inverted images (point to the final
scanline and use a negative stride). You can invert the input or output,
using negative strides.
DEFAULT FILTERS
- For functions which don't provide explicit control over what filters to
+ For functions which don't provide explicit control over what filters to
use, you can change the compile-time defaults with:
#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something
@@ -278,18 +278,18 @@
See stbir_filter in the header-file section for the list of filters.
NEW FILTERS
- A number of 1D filter kernels are supplied. For a list of supported
- filters, see the stbir_filter enum. You can install your own filters by
+ A number of 1D filter kernels are supplied. For a list of supported
+ filters, see the stbir_filter enum. You can install your own filters by
using the stbir_set_filter_callbacks function.
PROGRESS
- For interactive use with slow resize operations, you can use the the
- scanline callbacks in the extended API. It would have to be a *very* large
+ For interactive use with slow resize operations, you can use the the
+ scanline callbacks in the extended API. It would have to be a *very* large
image resample to need progress though - we're very fast.
CEIL and FLOOR
- In scalar mode, the only functions we use from math.h are ceilf and floorf,
- but if you have your own versions, you can define the STBIR_CEILF(v) and
+ In scalar mode, the only functions we use from math.h are ceilf and floorf,
+ but if you have your own versions, you can define the STBIR_CEILF(v) and
STBIR_FLOORF(v) macros and we'll use them instead. In SIMD, we just use
our own versions.
@@ -304,7 +304,7 @@
* For SIMD encode and decode scanline routines, do any pre-aligning
for bad input/output buffer alignments and pitch?
* For very wide scanlines, we should we do vertical strips to stay within
- L2 cache. Maybe do chunks of 1K pixels at a time. There would be
+ L2 cache. Maybe do chunks of 1K pixels at a time. There would be
some pixel reconversion, but probably dwarfed by things falling out
of cache. Probably also something possible with alternating between
scattering and gathering at high resize scales?
@@ -316,21 +316,38 @@
the pivot cost and the extra memory touches). Need to buffer the whole
image so have to balance memory use.
* Most of our code is internally function pointers, should we compile
- all the SIMD stuff always and dynamically dispatch?
+ all the SIMD stuff always and dynamically dispatch?
CONTRIBUTORS
Jeff Roberts: 2.0 implementation, optimizations, SIMD
- Martins Mozeiko: NEON simd, WASM simd, clang and GCC whisperer.
+ Martins Mozeiko: NEON simd, WASM simd, clang and GCC whisperer
Fabian Giesen: half float and srgb converters
Sean Barrett: API design, optimizations
Jorge L Rodriguez: Original 1.0 implementation
- Aras Pranckevicius: bugfixes for 1.0
+ Aras Pranckevicius: bugfixes
Nathan Reed: warning fixes for 1.0
REVISIONS
- 2.00 (2022-02-20) mostly new source: new api, optimizations, simd, vertical-first, etc
- (2x-5x faster without simd, 4x-12x faster with simd)
- (in some cases, 20x to 40x faster - resizing to very small for example)
+ 2.10 (2024-07-27) fix the defines GCC and mingw for loop unroll control,
+ fix MSVC 32-bit arm half float routines.
+ 2.09 (2024-06-19) fix the defines for 32-bit ARM GCC builds (was selecting
+ hardware half floats).
+ 2.08 (2024-06-10) fix for RGB->BGR three channel flips and add SIMD (thanks
+ to Ryan Salsbury), fix for sub-rect resizes, use the
+ pragmas to control unrolling when they are available.
+ 2.07 (2024-05-24) fix for slow final split during threaded conversions of very
+ wide scanlines when downsampling (caused by extra input
+ converting), fix for wide scanline resamples with many
+ splits (int overflow), fix GCC warning.
+ 2.06 (2024-02-10) fix for identical width/height 3x or more down-scaling
+ undersampling a single row on rare resize ratios (about 1%).
+ 2.05 (2024-02-07) fix for 2 pixel to 1 pixel resizes with wrap (thanks Aras),
+ fix for output callback (thanks Julien Koenen).
+ 2.04 (2023-11-17) fix for rare AVX bug, shadowed symbol (thanks Nikola Smiljanic).
+ 2.03 (2023-11-01) ASAN and TSAN warnings fixed, minor tweaks.
+ 2.00 (2023-10-10) mostly new source: new api, optimizations, simd, vertical-first, etc
+ 2x-5x faster without simd, 4x-12x faster with simd,
+ in some cases, 20x to 40x faster esp resizing large to very small.
0.96 (2019-03-04) fixed warnings
0.95 (2017-07-23) fixed warnings
0.94 (2017-03-18) fixed warnings
@@ -368,7 +385,7 @@ typedef uint64_t stbir_uint64;
#define STBIR_SSE
#endif
#endif
-#endif
+#endif
#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(_M_AMD64) || defined(__SSE2__) || defined(STBIR_SSE) || defined(STBIR_SSE2)
#ifndef STBIR_SSE2
@@ -383,7 +400,7 @@ typedef uint64_t stbir_uint64;
#endif
#if defined(__AVX2__) || defined(STBIR_AVX2)
#ifndef STBIR_NO_AVX2
- #ifndef STBIR_AVX2
+ #ifndef STBIR_AVX2
#define STBIR_AVX2
#endif
#if defined( _MSC_VER ) && !defined(__clang__)
@@ -400,15 +417,15 @@ typedef uint64_t stbir_uint64;
#endif
#endif
-#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(_M_ARM) || (__ARM_NEON_FP & 4) != 0 && __ARM_FP16_FORMAT_IEEE != 0
+#if defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || ((__ARM_NEON_FP & 4) != 0) || defined(__ARM_NEON__)
#ifndef STBIR_NEON
#define STBIR_NEON
#endif
#endif
-#if defined(_M_ARM)
+#if defined(_M_ARM) || defined(__arm__)
#ifdef STBIR_USE_FMA
-#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC
+#undef STBIR_USE_FMA // no FMA for 32-bit arm on MSVC
#endif
#endif
@@ -435,7 +452,7 @@ typedef uint64_t stbir_uint64;
//
// Easy-to-use API:
//
-// * stride is the offset between successive rows of image data
+// * stride is the offset between successive rows of image data
// in memory, in bytes. specify 0 for packed continuously in memory
// * colorspace is linear or sRGB as specified by function name
// * Uses the default filters
@@ -448,27 +465,35 @@ typedef uint64_t stbir_uint64;
// order of channels
// whether color is premultiplied by alpha
// for back compatibility, you can cast the old channel count to an stbir_pixel_layout
-typedef enum
+typedef enum
{
- STBIR_BGR = 0, // 3-chan, with order specified (for channel flipping)
- STBIR_1CHANNEL = 1,
+ STBIR_1CHANNEL = 1,
STBIR_2CHANNEL = 2,
- STBIR_RGB = 3, // 3-chan, with order specified (for channel flipping)
- STBIR_RGBA = 4, // alpha formats, alpha is NOT premultiplied into color channels
-
+ STBIR_RGB = 3, // 3-chan, with order specified (for channel flipping)
+ STBIR_BGR = 0, // 3-chan, with order specified (for channel flipping)
STBIR_4CHANNEL = 5,
+
+ STBIR_RGBA = 4, // alpha formats, where alpha is NOT premultiplied into color channels
STBIR_BGRA = 6,
STBIR_ARGB = 7,
STBIR_ABGR = 8,
STBIR_RA = 9,
STBIR_AR = 10,
- STBIR_RGBA_PM = 11, // alpha formats, alpha is premultiplied into color channels
+ STBIR_RGBA_PM = 11, // alpha formats, where alpha is premultiplied into color channels
STBIR_BGRA_PM = 12,
STBIR_ARGB_PM = 13,
STBIR_ABGR_PM = 14,
STBIR_RA_PM = 15,
STBIR_AR_PM = 16,
+
+ STBIR_RGBA_NO_AW = 11, // alpha formats, where NO alpha weighting is applied at all!
+ STBIR_BGRA_NO_AW = 12, // these are just synonyms for the _PM flags (which also do
+ STBIR_ARGB_NO_AW = 13, // no alpha weighting). These names just make it more clear
+ STBIR_ABGR_NO_AW = 14, // for some folks).
+ STBIR_RA_NO_AW = 15,
+ STBIR_AR_NO_AW = 16,
+
} stbir_pixel_layout;
//===============================================================
@@ -549,8 +574,8 @@ STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int inpu
// * Separate input and output data types
// * Can specify regions with subpixel correctness
// * Can specify alpha flags
-// * Can specify a memory callback
-// * Can specify a callback data type for pixel input and output
+// * Can specify a memory callback
+// * Can specify a callback data type for pixel input and output
// * Can be threaded for a single resize
// * Can be used to resize many frames without recalculating the sampler info
//
@@ -577,7 +602,7 @@ typedef float stbir__kernel_callback( float x, float scale, void * user_data );
typedef float stbir__support_callback( float scale, void * user_data );
// internal structure with precomputed scaling
-typedef struct stbir__info stbir__info;
+typedef struct stbir__info stbir__info;
typedef struct STBIR_RESIZE // use the stbir_resize_init and stbir_override functions to set these values for future compatibility
{
@@ -604,7 +629,7 @@ typedef struct STBIR_RESIZE // use the stbir_resize_init and stbir_override fun
stbir_edge horizontal_edge, vertical_edge;
stbir__kernel_callback * horizontal_filter_kernel; stbir__support_callback * horizontal_filter_support;
stbir__kernel_callback * vertical_filter_kernel; stbir__support_callback * vertical_filter_support;
- stbir__info * samplers;
+ stbir__info * samplers;
} STBIR_RESIZE;
// extended complexity api
@@ -620,7 +645,7 @@ STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize,
// You can update these parameters any time after resize_init and there is no cost
//--------------------------------
-STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type );
+STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_type, stbir_datatype output_type );
STBIRDEF void stbir_set_pixel_callbacks( STBIR_RESIZE * resize, stbir_input_callback * input_cb, stbir_output_callback * output_cb ); // no callbacks by default
STBIRDEF void stbir_set_user_data( STBIR_RESIZE * resize, void * user_data ); // pass back STBIR_RESIZE* by default
STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_pixels, int input_stride_in_bytes, void * output_pixels, int output_stride_in_bytes );
@@ -636,7 +661,7 @@ STBIRDEF int stbir_set_pixel_layouts( STBIR_RESIZE * resize, stbir_pixel_layout
STBIRDEF int stbir_set_edgemodes( STBIR_RESIZE * resize, stbir_edge horizontal_edge, stbir_edge vertical_edge ); // CLAMP by default
STBIRDEF int stbir_set_filters( STBIR_RESIZE * resize, stbir_filter horizontal_filter, stbir_filter vertical_filter ); // STBIR_DEFAULT_FILTER_UPSAMPLE/DOWNSAMPLE by default
-STBIRDEF int stbir_set_filter_callbacks( STBIR_RESIZE * resize, stbir__kernel_callback * horizontal_filter, stbir__support_callback * horizontal_support, stbir__kernel_callback * vertical_filter, stbir__support_callback * vertical_support );
+STBIRDEF int stbir_set_filter_callbacks( STBIR_RESIZE * resize, stbir__kernel_callback * horizontal_filter, stbir__support_callback * horizontal_support, stbir__kernel_callback * vertical_filter, stbir__support_callback * vertical_support );
STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby, int subw, int subh ); // sets both sub-regions (full regions by default)
STBIRDEF int stbir_set_input_subrect( STBIR_RESIZE * resize, double s0, double t0, double s1, double t1 ); // sets input sub-region (full region by default)
@@ -658,7 +683,7 @@ STBIRDEF int stbir_set_non_pm_alpha_speed_over_quality( STBIR_RESIZE * resize, i
//--------------------------------
// This builds the samplers and does one allocation
-STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize );
+STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize );
// You MUST call this, if you call stbir_build_samplers or stbir_build_samplers_with_splits
STBIRDEF void stbir_free_samplers( STBIR_RESIZE * resize );
@@ -681,7 +706,7 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize );
// It returns the number of splits (threads) that you can call it with.
/// It might be less if the image resize can't be split up that many ways.
-STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_splits );
+STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_splits );
// This function does a split of the resizing (you call this fuction for each
// split, on multiple threads). A split is a piece of the output resize pixel space.
@@ -691,10 +716,10 @@ STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int try_sp
// Usually, you will always call stbir_resize_split with split_start as the thread_index
// and "1" for the split_count.
// But, if you have a weird situation where you MIGHT want 8 threads, but sometimes
-// only 4 threads, you can use 0,2,4,6 for the split_start's and use "2" for the
+// only 4 threads, you can use 0,2,4,6 for the split_start's and use "2" for the
// split_count each time to turn in into a 4 thread resize. (This is unusual).
-STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count );
+STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start, int split_count );
//===============================================================
@@ -705,10 +730,10 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start
// The input callback is super flexible - it calls you with the input address
// (based on the stride and base pointer), it gives you an optional_output
// pointer that you can fill, or you can just return your own pointer into
-// your own data.
+// your own data.
//
-// You can also do conversion from non-supported data types if necessary - in
-// this case, you ignore the input_ptr and just use the x and y parameters to
+// You can also do conversion from non-supported data types if necessary - in
+// this case, you ignore the input_ptr and just use the x and y parameters to
// calculate your own input_ptr based on the size of each non-supported pixel.
// (Something like the third example below.)
//
@@ -722,14 +747,14 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start
// return input_ptr; // use buffer from call
// }
//
-// Next example, copying: (copy from some other buffer or stream):
+// Next example, copying: (copy from some other buffer or stream):
// void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context )
// {
// CopyOrStreamData( optional_output, other_data_src, num_pixels * pixel_width_in_bytes );
// return optional_output; // return the optional buffer that we filled
// }
//
-// Third example, input another buffer without copying: (zero-copy from other buffer):
+// Third example, input another buffer without copying: (zero-copy from other buffer):
// void const * my_callback( void * optional_output, void const * input_ptr, int num_pixels, int x, int y, void * context )
// {
// void * pixels = ( (char*) other_image_base ) + ( y * other_image_stride ) + ( x * other_pixel_width_in_bytes );
@@ -758,7 +783,7 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start
#ifdef STBIR_PROFILE
-typedef struct STBIR_PROFILE_INFO
+typedef struct STBIR_PROFILE_INFO
{
stbir_uint64 total_clocks;
@@ -766,7 +791,7 @@ typedef struct STBIR_PROFILE_INFO
// there are "resize_count" number of zones
stbir_uint64 clocks[ 8 ];
char const ** descriptions;
-
+
// count of clocks and descriptions
stbir_uint32 count;
} STBIR_PROFILE_INFO;
@@ -865,15 +890,15 @@ STBIRDEF void stbir_resize_split_profile_info( STBIR_PROFILE_INFO * out_info, ST
#endif
// the internal pixel layout enums are in a different order, so we can easily do range comparisons of types
-// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible
-typedef enum
+// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible
+typedef enum
{
STBIRI_1CHANNEL = 0,
STBIRI_2CHANNEL = 1,
STBIRI_RGB = 2,
STBIRI_BGR = 3,
STBIRI_4CHANNEL = 4,
-
+
STBIRI_RGBA = 5,
STBIRI_BGRA = 6,
STBIRI_ARGB = 7,
@@ -979,7 +1004,7 @@ typedef struct
stbir__span spans[2]; // can be two spans, if doing input subrect with clamp mode WRAP
} stbir__extents;
-typedef struct
+typedef struct
{
#ifdef STBIR_PROFILE
union
@@ -1010,7 +1035,7 @@ typedef struct
typedef void stbir__decode_pixels_func( float * decode, int width_times_channels, void const * input );
typedef void stbir__alpha_weight_func( float * decode_buffer, int width_times_channels );
-typedef void stbir__horizontal_gather_channels_func( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer,
+typedef void stbir__horizontal_gather_channels_func( float * output_buffer, unsigned int output_sub_size, float const * decode_buffer,
stbir__contributors const * horizontal_contributors, float const * horizontal_coefficients, int coefficient_width );
typedef void stbir__alpha_unweight_func(float * encode_buffer, int width_times_channels );
typedef void stbir__encode_pixels_func( void * output, int width_times_channels, float const * encode );
@@ -1053,10 +1078,10 @@ struct stbir__info
stbir__horizontal_gather_channels_func * horizontal_gather_channels;
stbir__alpha_unweight_func * alpha_unweight;
stbir__encode_pixels_func * encode_pixels;
-
- int alloced_total;
+
+ int alloc_ring_buffer_num_entries; // Number of entries in the ring buffer that will be allocated
int splits; // count of splits
-
+
stbir_internal_pixel_layout input_pixel_layout_internal;
stbir_internal_pixel_layout output_pixel_layout_internal;
@@ -1065,7 +1090,7 @@ struct stbir__info
int vertical_first;
int channels;
int effective_channels; // same as channels, except on RGBA/ARGB (7), or XA/AX (3)
- int alloc_ring_buffer_num_entries; // Number of entries in the ring buffer that will be allocated
+ size_t alloced_total;
};
@@ -1076,10 +1101,11 @@ struct stbir__info
#define stbir__small_float ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
// min/max friendly
-#define STBIR_CLAMP(x, xmin, xmax) do { \
+#define STBIR_CLAMP(x, xmin, xmax) for(;;) { \
if ( (x) < (xmin) ) (x) = (xmin); \
if ( (x) > (xmax) ) (x) = (xmax); \
-} while (0)
+ break; \
+}
static stbir__inline int stbir__min(int a, int b)
{
@@ -1141,7 +1167,7 @@ static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
};
-
+
static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
{
static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
@@ -1172,19 +1198,44 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#define STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT 32 // when downsampling and <= 32 scanlines of buffering, use gather. gather used down to 1/8th scaling for 25% win.
#endif
-// restrict pointers for the output pointers
+#ifndef STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS
+#define STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS 4 // when threading, what is the minimum number of scanlines for a split?
+#endif
+
+// restrict pointers for the output pointers, other loop and unroll control
#if defined( _MSC_VER ) && !defined(__clang__)
#define STBIR_STREAMOUT_PTR( star ) star __restrict
#define STBIR_NO_UNROLL( ptr ) __assume(ptr) // this oddly keeps msvc from unrolling a loop
-#elif defined( __clang__ )
- #define STBIR_STREAMOUT_PTR( star ) star __restrict__
- #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr))
-#elif defined( __GNUC__ )
+ #if _MSC_VER >= 1900
+ #define STBIR_NO_UNROLL_LOOP_START __pragma(loop( no_vector ))
+ #else
+ #define STBIR_NO_UNROLL_LOOP_START
+ #endif
+#elif defined( __clang__ )
+ #define STBIR_STREAMOUT_PTR( star ) star __restrict__
+ #define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr))
+ #if ( __clang_major__ >= 4 ) || ( ( __clang_major__ >= 3 ) && ( __clang_minor__ >= 5 ) )
+ #define STBIR_NO_UNROLL_LOOP_START _Pragma("clang loop unroll(disable)") _Pragma("clang loop vectorize(disable)")
+ #else
+ #define STBIR_NO_UNROLL_LOOP_START
+ #endif
+#elif defined( __GNUC__ )
#define STBIR_STREAMOUT_PTR( star ) star __restrict__
#define STBIR_NO_UNROLL( ptr ) __asm__ (""::"r"(ptr))
+ #if __GNUC__ >= 14
+ #define STBIR_NO_UNROLL_LOOP_START _Pragma("GCC unroll 0") _Pragma("GCC novector")
+ #else
+ #define STBIR_NO_UNROLL_LOOP_START
+ #endif
+ #define STBIR_NO_UNROLL_LOOP_START_INF_FOR
#else
#define STBIR_STREAMOUT_PTR( star ) star
#define STBIR_NO_UNROLL( ptr )
+ #define STBIR_NO_UNROLL_LOOP_START
+#endif
+
+#ifndef STBIR_NO_UNROLL_LOOP_START_INF_FOR
+#define STBIR_NO_UNROLL_LOOP_START_INF_FOR STBIR_NO_UNROLL_LOOP_START
#endif
#ifdef STBIR_NO_SIMD // force simd off for whatever reason
@@ -1223,7 +1274,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#ifdef STBIR_SSE2
#include
-
+
#define stbir__simdf __m128
#define stbir__simdi __m128i
@@ -1254,7 +1305,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#define stbir__simdi_store2( ptr, reg ) _mm_storel_epi64( (__m128i*)(ptr), (reg) )
#define stbir__prefetch( ptr ) _mm_prefetch((char*)(ptr), _MM_HINT_T0 )
-
+
#define stbir__simdi_expand_u8_to_u32(out0,out1,out2,out3,ireg) \
{ \
stbir__simdi zero = _mm_setzero_si128(); \
@@ -1285,7 +1336,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),_mm_setzero_ps()))))
#define stbir__simdf_convert_float_to_short( f ) ((unsigned short)_mm_cvtsi128_si32(_mm_cvttps_epi32(_mm_max_ps(_mm_min_ps(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),_mm_setzero_ps()))))
- #define stbir__simdi_to_int( i ) _mm_cvtsi128_si32(i)
+ #define stbir__simdi_to_int( i ) _mm_cvtsi128_si32(i)
#define stbir__simdi_convert_i32_to_float(out, ireg) (out) = _mm_cvtepi32_ps( ireg )
#define stbir__simdf_add( out, reg0, reg1 ) (out) = _mm_add_ps( reg0, reg1 )
#define stbir__simdf_mult( out, reg0, reg1 ) (out) = _mm_mul_ps( reg0, reg1 )
@@ -1440,10 +1491,10 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#define stbir__simdi8_convert_i32_to_float(out, ireg) (out) = _mm256_cvtepi32_ps( ireg )
#define stbir__simdf8_convert_float_to_i32( i, f ) (i) = _mm256_cvttps_epi32(f)
-
+
#define stbir__simdf8_bot4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (0<<0)+(2<<4) )
#define stbir__simdf8_top4s( out, a, b ) (out) = _mm256_permute2f128_ps(a,b, (1<<0)+(3<<4) )
-
+
#define stbir__simdf8_gettop4( reg ) _mm256_extractf128_ps(reg,1)
#ifdef STBIR_AVX2
@@ -1471,8 +1522,8 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
out = _mm256_castsi256_si128( _mm256_permute4x64_epi64( _mm256_packus_epi16( t, t ), (0<<0)+(2<<2)+(1<<4)+(3<<6) ) ); \
}
- #define stbir__simdi8_expand_u16_to_u32(out,ireg) out = _mm256_unpacklo_epi16( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), _mm256_setzero_si256() );
-
+ #define stbir__simdi8_expand_u16_to_u32(out,ireg) out = _mm256_unpacklo_epi16( _mm256_permute4x64_epi64(_mm256_castsi128_si256(ireg),(0<<0)+(2<<2)+(1<<4)+(3<<6)), _mm256_setzero_si256() );
+
#define stbir__simdf8_pack_to_16words(out,aa,bb) \
{ \
stbir__simdf8 af,bf; \
@@ -1496,7 +1547,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
a = _mm_unpackhi_epi8( ireg, zero ); \
out1 = _mm256_setr_m128i( _mm_unpacklo_epi16( a, zero ), _mm_unpackhi_epi16( a, zero ) ); \
}
-
+
#define stbir__simdf8_pack_to_16bytes(out,aa,bb) \
{ \
stbir__simdi t; \
@@ -1514,7 +1565,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
t = _mm_packus_epi16( t, t ); \
out = _mm_castps_si128( _mm_shuffle_ps( _mm_castsi128_ps(out), _mm_castsi128_ps(t), (0<<0)+(1<<2)+(0<<4)+(1<<6) ) ); \
}
-
+
#define stbir__simdi8_expand_u16_to_u32(out,ireg) \
{ \
stbir__simdi a,b,zero = _mm_setzero_si128(); \
@@ -1549,7 +1600,6 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#define stbir__simdf8_0123to2222( out, in ) (out) = stbir__simdf_swiz(_mm256_castps256_ps128(in), 2,2,2,2 )
- #define stbir__simdf8_load2( out, ptr ) (out) = _mm256_castsi256_ps(_mm256_castsi128_si256( _mm_loadl_epi64( (__m128i*)(ptr)) )) // top values can be random (not denormal or nan for perf)
#define stbir__simdf8_load4b( out, ptr ) (out) = _mm256_broadcast_ps( (__m128 const *)(ptr) )
static __m256i stbir_00112233 = { STBIR__CONST_4d_32i( 0, 0, 1, 1 ), STBIR__CONST_4d_32i( 2, 2, 3, 3 ) };
@@ -1582,11 +1632,11 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#ifdef STBIR_USE_FMA // not on by default to maintain bit identical simd to non-simd
#define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_fmadd_ps( mul1, mul2, add )
#define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_fmadd_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ), add )
- #define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_fmadd_ps( _mm256_castps128_ps256( mul ), _mm256_castps128_ps256( _mm_loadu_ps( (float const*)(ptr) ) ), add )
+ #define stbir__simdf8_madd_mem4( out, add, mul, ptr )(out) = _mm256_fmadd_ps( _mm256_setr_m128( mul, _mm_setzero_ps() ), _mm256_setr_m128( _mm_loadu_ps( (float const*)(ptr) ), _mm_setzero_ps() ), add )
#else
#define stbir__simdf8_madd( out, add, mul1, mul2 ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul1, mul2 ) )
#define stbir__simdf8_madd_mem( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_mul_ps( mul, _mm256_loadu_ps( (float const*)(ptr) ) ) )
- #define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_castps128_ps256( _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ) ) )
+ #define stbir__simdf8_madd_mem4( out, add, mul, ptr ) (out) = _mm256_add_ps( add, _mm256_setr_m128( _mm_mul_ps( mul, _mm_loadu_ps( (float const*)(ptr) ) ), _mm_setzero_ps() ) )
#endif
#define stbir__if_simdf8_cast_to_simdf4( val ) _mm256_castps256_ps128( val )
@@ -1627,7 +1677,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
}
#elif defined(STBIR_NEON)
-
+
#include
#define stbir__simdf float32x4_t
@@ -1686,7 +1736,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#define stbir__simdf_convert_float_to_i32( i, f ) (i) = vreinterpretq_u32_s32( vcvtq_s32_f32(f) )
#define stbir__simdf_convert_float_to_int( f ) vgetq_lane_s32(vcvtq_s32_f32(f), 0)
- #define stbir__simdi_to_int( i ) (int)vgetq_lane_u32(i, 0)
+ #define stbir__simdi_to_int( i ) (int)vgetq_lane_u32(i, 0)
#define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint8_as_float)),vdupq_n_f32(0))), 0))
#define stbir__simdf_convert_float_to_short( f ) ((unsigned short)vgetq_lane_s32(vcvtq_s32_f32(vmaxq_f32(vminq_f32(f,STBIR__CONSTF(STBIR_max_uint16_as_float)),vdupq_n_f32(0))), 0))
#define stbir__simdi_convert_i32_to_float(out, ireg) (out) = vcvtq_f32_s32( vreinterpretq_s32_u32(ireg) )
@@ -1737,12 +1787,20 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
((stbir_uint64)(4*b+0)<<32) | ((stbir_uint64)(4*b+1)<<40) | ((stbir_uint64)(4*b+2)<<48) | ((stbir_uint64)(4*b+3)<<56)), \
vcreate_u8( (4*c+0) | ((4*c+1)<<8) | ((4*c+2)<<16) | ((4*c+3)<<24) | \
((stbir_uint64)(4*d+0)<<32) | ((stbir_uint64)(4*d+1)<<40) | ((stbir_uint64)(4*d+2)<<48) | ((stbir_uint64)(4*d+3)<<56) ) )
+
+ static stbir__inline uint8x16x2_t stbir_make16x2(float32x4_t rega,float32x4_t regb)
+ {
+ uint8x16x2_t r = { vreinterpretq_u8_f32(rega), vreinterpretq_u8_f32(regb) };
+ return r;
+ }
#else
#define stbir_make16(a,b,c,d) (uint8x16_t){4*a+0,4*a+1,4*a+2,4*a+3,4*b+0,4*b+1,4*b+2,4*b+3,4*c+0,4*c+1,4*c+2,4*c+3,4*d+0,4*d+1,4*d+2,4*d+3}
+ #define stbir_make16x2(a,b) (uint8x16x2_t){{vreinterpretq_u8_f32(a),vreinterpretq_u8_f32(b)}}
#endif
#define stbir__simdf_swiz( reg, one, two, three, four ) vreinterpretq_f32_u8( vqtbl1q_u8( vreinterpretq_u8_f32(reg), stbir_make16(one, two, three, four) ) )
-
+ #define stbir__simdf_swiz2( rega, regb, one, two, three, four ) vreinterpretq_f32_u8( vqtbl2q_u8( stbir_make16x2(rega,regb), stbir_make16(one, two, three, four) ) )
+
#define stbir__simdi_16madd( out, reg0, reg1 ) \
{ \
int16x8_t r0 = vreinterpretq_s16_u32(reg0); \
@@ -1942,7 +2000,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#define stbir__simdf_convert_float_to_i32( i, f ) (i) = wasm_i32x4_trunc_sat_f32x4(f)
#define stbir__simdf_convert_float_to_int( f ) wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(f), 0)
- #define stbir__simdi_to_int( i ) wasm_i32x4_extract_lane(i, 0)
+ #define stbir__simdi_to_int( i ) wasm_i32x4_extract_lane(i, 0)
#define stbir__simdf_convert_float_to_uint8( f ) ((unsigned char)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint8_as_float),wasm_f32x4_const_splat(0))), 0))
#define stbir__simdf_convert_float_to_short( f ) ((unsigned short)wasm_i32x4_extract_lane(wasm_i32x4_trunc_sat_f32x4(wasm_f32x4_max(wasm_f32x4_min(f,STBIR_max_uint16_as_float),wasm_f32x4_const_splat(0))), 0))
#define stbir__simdi_convert_i32_to_float(out, ireg) (out) = wasm_f32x4_convert_i32x4(ireg)
@@ -2125,7 +2183,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#endif
-#if defined(STBIR_NEON) && !defined(_M_ARM)
+#if defined(STBIR_NEON) && !defined(_M_ARM) && !defined(__arm__)
#if defined( _MSC_VER ) && !defined(__clang__)
typedef __int16 stbir__FP16;
@@ -2142,7 +2200,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#endif
-#if !defined(STBIR_NEON) && !defined(STBIR_FP16C) || defined(STBIR_NEON) && defined(_M_ARM)
+#if (!defined(STBIR_NEON) && !defined(STBIR_FP16C)) || (defined(STBIR_NEON) && defined(_M_ARM)) || (defined(STBIR_NEON) && defined(__arm__))
// Fabian's half float routines, see: https://gist.github.com/rygorous/2156668
@@ -2168,7 +2226,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
unsigned int sign_mask = 0x80000000u;
stbir__FP16 o = { 0 };
stbir__FP32 f;
- unsigned int sign;
+ unsigned int sign;
f.f = val;
sign = f.u & sign_mask;
@@ -2369,24 +2427,6 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
stbir__simdi_store( output,final );
}
-#elif defined(STBIR_WASM) || (defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM)) // WASM or 32-bit ARM on MSVC/clang
-
- static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)
- {
- for (int i=0; i<8; i++)
- {
- output[i] = stbir__half_to_float(input[i]);
- }
- }
-
- static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)
- {
- for (int i=0; i<8; i++)
- {
- output[i] = stbir__float_to_half(input[i]);
- }
- }
-
#elif defined(STBIR_NEON) && defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__) // 64-bit ARM on MSVC (not clang)
static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)
@@ -2415,7 +2455,7 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0).n16_u16[0];
}
-#elif defined(STBIR_NEON) // 64-bit ARM
+#elif defined(STBIR_NEON) && ( defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) ) // 64-bit ARM
static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)
{
@@ -2441,6 +2481,23 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
return vget_lane_f16(vcvt_f16_f32(vdupq_n_f32(f)), 0);
}
+#elif defined(STBIR_WASM) || (defined(STBIR_NEON) && (defined(_MSC_VER) || defined(_M_ARM) || defined(__arm__))) // WASM or 32-bit ARM on MSVC/clang
+
+ static stbir__inline void stbir__half_to_float_SIMD(float * output, stbir__FP16 const * input)
+ {
+ for (int i=0; i<8; i++)
+ {
+ output[i] = stbir__half_to_float(input[i]);
+ }
+ }
+ static stbir__inline void stbir__float_to_half_SIMD(stbir__FP16 * output, float const * input)
+ {
+ for (int i=0; i<8; i++)
+ {
+ output[i] = stbir__float_to_half(input[i]);
+ }
+ }
+
#endif
@@ -2462,10 +2519,10 @@ static stbir__inline stbir_uint8 stbir__linear_to_srgb_uchar(float in)
#define stbir__simdf_0123to3012( out, reg ) (out) = stbir__simdf_swiz( reg, 3,0,1,2 )
#define stbir__simdf_0123to0011( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,1,1 )
#define stbir__simdf_0123to1100( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,0,0 )
-#define stbir__simdf_0123to2233( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,3,3 )
-#define stbir__simdf_0123to1133( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,3,3 )
-#define stbir__simdf_0123to0022( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,2 )
-#define stbir__simdf_0123to1032( out, reg ) (out) = stbir__simdf_swiz( reg, 1,0,3,2 )
+#define stbir__simdf_0123to2233( out, reg ) (out) = stbir__simdf_swiz( reg, 2,2,3,3 )
+#define stbir__simdf_0123to1133( out, reg ) (out) = stbir__simdf_swiz( reg, 1,1,3,3 )
+#define stbir__simdf_0123to0022( out, reg ) (out) = stbir__simdf_swiz( reg, 0,0,2,2 )
+#define stbir__simdf_0123to1032( out, reg ) (out) = stbir__simdf_swiz( reg, 1,0,3,2 )
typedef union stbir__simdi_u32
{
@@ -2493,14 +2550,16 @@ static const STBIR__SIMDI_CONST(STBIR_topscale, 0x02000000);
// Adding this switch saves about 5K on clang which is Captain Unroll the 3rd.
#define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star )
#define STBIR_SIMD_NO_UNROLL(ptr) STBIR_NO_UNROLL(ptr)
+#define STBIR_SIMD_NO_UNROLL_LOOP_START STBIR_NO_UNROLL_LOOP_START
+#define STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR STBIR_NO_UNROLL_LOOP_START_INF_FOR
#ifdef STBIR_MEMCPY
#undef STBIR_MEMCPY
-#define STBIR_MEMCPY stbir_simd_memcpy
#endif
+#define STBIR_MEMCPY stbir_simd_memcpy
// override normal use of memcpy with much simpler copy (faster and smaller with our sized copies)
-static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes )
+static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes )
{
char STBIR_SIMD_STREAMOUT_PTR (*) d = (char*) dest;
char STBIR_SIMD_STREAMOUT_PTR( * ) d_end = ((char*) dest) + bytes;
@@ -2513,8 +2572,9 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes )
{
if ( bytes < 16 )
{
- if ( bytes )
+ if ( bytes )
{
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do
{
STBIR_SIMD_NO_UNROLL(d);
@@ -2529,8 +2589,9 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes )
// do one unaligned to get us aligned for the stream out below
stbir__simdf_load( x, ( d + ofs_to_src ) );
stbir__simdf_store( d, x );
- d = (char*)( ( ( (ptrdiff_t)d ) + 16 ) & ~15 );
+ d = (char*)( ( ( (size_t)d ) + 16 ) & ~15 );
+ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
STBIR_SIMD_NO_UNROLL(d);
@@ -2561,12 +2622,13 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes )
stbir__simdfX_store( d + 4*stbir__simdfX_float_count, x1 );
stbir__simdfX_store( d + 8*stbir__simdfX_float_count, x2 );
stbir__simdfX_store( d + 12*stbir__simdfX_float_count, x3 );
- d = (char*)( ( ( (ptrdiff_t)d ) + (16*stbir__simdfX_float_count) ) & ~((16*stbir__simdfX_float_count)-1) );
+ d = (char*)( ( ( (size_t)d ) + (16*stbir__simdfX_float_count) ) & ~((16*stbir__simdfX_float_count)-1) );
+ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
STBIR_SIMD_NO_UNROLL(d);
-
+
if ( d > ( d_end - (16*stbir__simdfX_float_count) ) )
{
if ( d == d_end )
@@ -2590,7 +2652,7 @@ static void stbir_simd_memcpy( void * dest, void const * src, size_t bytes )
// memcpy that is specically intentionally overlapping (src is smaller then dest, so can be
// a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to
// the diff between dest and src)
-static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes )
+static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes )
{
char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src;
char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes;
@@ -2599,6 +2661,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
if ( ofs_to_dest >= 16 ) // is the overlap more than 16 away?
{
char STBIR_SIMD_STREAMOUT_PTR( * ) s_end16 = ((char*) src) + (bytes&~15);
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do
{
stbir__simdf x;
@@ -2615,7 +2678,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
do
{
STBIR_SIMD_NO_UNROLL(sd);
- *(int*)( sd + ofs_to_dest ) = *(int*) sd;
+ *(int*)( sd + ofs_to_dest ) = *(int*) sd;
sd += 4;
} while ( sd < s_end );
}
@@ -2624,13 +2687,17 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
// when in scalar mode, we let unrolling happen, so this macro just does the __restrict
#define STBIR_SIMD_STREAMOUT_PTR( star ) STBIR_STREAMOUT_PTR( star )
-#define STBIR_SIMD_NO_UNROLL(ptr)
+#define STBIR_SIMD_NO_UNROLL(ptr)
+#define STBIR_SIMD_NO_UNROLL_LOOP_START
+#define STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
#endif // SSE2
#ifdef STBIR_PROFILE
+#ifndef STBIR_PROFILE_FUNC
+
#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined(STBIR_SSE) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ )
#ifdef _MSC_VER
@@ -2640,7 +2707,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
#else // non msvc
- static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC()
+ static stbir__inline stbir_uint64 STBIR_PROFILE_FUNC()
{
stbir_uint32 lo, hi;
asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) );
@@ -2649,7 +2716,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
#endif // msvc
-#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__)
+#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__)
#if defined( _MSC_VER ) && !defined(__clang__)
@@ -2670,8 +2737,9 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
#error Unknown platform for profiling.
-#endif //x64 and
+#endif // x64, arm
+#endif // STBIR_PROFILE_FUNC
#define STBIR_ONLY_PROFILE_GET_SPLIT_INFO ,stbir__per_split_info * split_info
#define STBIR_ONLY_PROFILE_SET_SPLIT_INFO ,split_info
@@ -2680,7 +2748,7 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
#define STBIR_ONLY_PROFILE_BUILD_SET_INFO ,profile_info
// super light-weight micro profiler
-#define STBIR_PROFILE_START_ll( info, wh ) { stbir_uint64 wh##thiszonetime = STBIR_PROFILE_FUNC(); stbir_uint64 * wh##save_parent_excluded_ptr = info->current_zone_excluded_ptr; stbir_uint64 wh##current_zone_excluded = 0; info->current_zone_excluded_ptr = &wh##current_zone_excluded;
+#define STBIR_PROFILE_START_ll( info, wh ) { stbir_uint64 wh##thiszonetime = STBIR_PROFILE_FUNC(); stbir_uint64 * wh##save_parent_excluded_ptr = info->current_zone_excluded_ptr; stbir_uint64 wh##current_zone_excluded = 0; info->current_zone_excluded_ptr = &wh##current_zone_excluded;
#define STBIR_PROFILE_END_ll( info, wh ) wh##thiszonetime = STBIR_PROFILE_FUNC() - wh##thiszonetime; info->profile.named.wh += wh##thiszonetime - wh##current_zone_excluded; *wh##save_parent_excluded_ptr += wh##thiszonetime; info->current_zone_excluded_ptr = wh##save_parent_excluded_ptr; }
#define STBIR_PROFILE_FIRST_START_ll( info, wh ) { int i; info->current_zone_excluded_ptr = &info->profile.named.total; for(i=0;iprofile.array);i++) info->profile.array[i]=0; } STBIR_PROFILE_START_ll( info, wh );
#define STBIR_PROFILE_CLEAR_EXTRAS_ll( info, num ) { int extra; for(extra=1;extra<(num);extra++) { int i; for(i=0;iprofile.array);i++) (info)[extra].profile.array[i]=0; } }
@@ -2710,8 +2778,8 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
#define STBIR_PROFILE_FIRST_START( wh )
#define STBIR_PROFILE_CLEAR_EXTRAS( )
-#define STBIR_PROFILE_BUILD_START( wh )
-#define STBIR_PROFILE_BUILD_END( wh )
+#define STBIR_PROFILE_BUILD_START( wh )
+#define STBIR_PROFILE_BUILD_END( wh )
#define STBIR_PROFILE_BUILD_FIRST_START( wh )
#define STBIR_PROFILE_BUILD_CLEAR( info )
@@ -2736,10 +2804,10 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
#ifndef STBIR_SIMD
-// memcpy that is specically intentionally overlapping (src is smaller then dest, so can be
+// memcpy that is specifically intentionally overlapping (src is smaller then dest, so can be
// a normal forward copy, bytes is divisible by 4 and bytes is greater than or equal to
// the diff between dest and src)
-static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes )
+static void stbir_overlapping_memcpy( void * dest, void const * src, size_t bytes )
{
char STBIR_SIMD_STREAMOUT_PTR (*) sd = (char*) src;
char STBIR_SIMD_STREAMOUT_PTR( * ) s_end = ((char*) src) + bytes;
@@ -2748,10 +2816,11 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
if ( ofs_to_dest >= 8 ) // is the overlap more than 8 away?
{
char STBIR_SIMD_STREAMOUT_PTR( * ) s_end8 = ((char*) src) + (bytes&~7);
+ STBIR_NO_UNROLL_LOOP_START
do
{
STBIR_NO_UNROLL(sd);
- *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd;
+ *(stbir_uint64*)( sd + ofs_to_dest ) = *(stbir_uint64*) sd;
sd += 8;
} while ( sd < s_end8 );
@@ -2759,10 +2828,11 @@ static void stbir_overlapping_memcpy( void * dest, void const * src, size_t byte
return;
}
+ STBIR_NO_UNROLL_LOOP_START
do
{
STBIR_NO_UNROLL(sd);
- *(int*)( sd + ofs_to_dest ) = *(int*) sd;
+ *(int*)( sd + ofs_to_dest ) = *(int*) sd;
sd += 4;
} while ( sd < s_end );
}
@@ -2863,13 +2933,6 @@ static float stbir__filter_mitchell(float x, float s, void * user_data)
return (0.0f);
}
-static float stbir__support_zero(float s, void * user_data)
-{
- STBIR__UNUSED(s);
- STBIR__UNUSED(user_data);
- return 0;
-}
-
static float stbir__support_zeropoint5(float s, void * user_data)
{
STBIR__UNUSED(s);
@@ -2884,7 +2947,7 @@ static float stbir__support_one(float s, void * user_data)
return 1;
}
-static float stbir__support_two(float s, void * user_data)
+static float stbir__support_two(float s, void * user_data)
{
STBIR__UNUSED(s);
STBIR__UNUSED(user_data);
@@ -2903,7 +2966,7 @@ static int stbir__get_filter_pixel_width(stbir__support_callback * support, floa
return (int)STBIR_CEILF(support(scale,user_data) * 2.0f / scale);
}
-// this is how many coefficents per run of the filter (which is different
+// this is how many coefficents per run of the filter (which is different
// from the filter_pixel_width depending on if we are scattering or gathering)
static int stbir__get_coefficient_width(stbir__sampler * samp, int is_gather, void * user_data)
{
@@ -2924,7 +2987,7 @@ static int stbir__get_coefficient_width(stbir__sampler * samp, int is_gather, vo
}
}
-static int stbir__get_contributors(stbir__sampler * samp, int is_gather)
+static int stbir__get_contributors(stbir__sampler * samp, int is_gather)
{
if (is_gather)
return samp->scale_info.output_sub_size;
@@ -2954,7 +3017,7 @@ static int stbir__edge_reflect_full( int n, int max )
{
if (n < 0)
{
- if (n > -max)
+ if (n > -max)
return -n;
else
return max - 1;
@@ -3056,7 +3119,7 @@ static void stbir__get_extents( stbir__sampler * samp, stbir__extents * scanline
left_margin = -min_n;
min_n = 0;
}
-
+
right_margin = 0;
if ( max_n >= input_full_size )
{
@@ -3081,7 +3144,7 @@ static void stbir__get_extents( stbir__sampler * samp, stbir__extents * scanline
// don't have to do edge calc for zero clamp
if ( edge == STBIR_EDGE_ZERO )
return;
-
+
// convert margin pixels to the pixels within the input (min and max)
for( j = -left_margin ; j < 0 ; j++ )
{
@@ -3179,20 +3242,20 @@ static void stbir__calculate_in_pixel_range( int * first_pixel, int * last_pixel
float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
- float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) * inv_scale;
- float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) * inv_scale;
+ float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) * inv_scale;
+ float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) * inv_scale;
first = (int)(STBIR_FLOORF(in_pixel_influence_lowerbound + 0.5f));
last = (int)(STBIR_FLOORF(in_pixel_influence_upperbound - 0.5f));
if ( edge == STBIR_EDGE_WRAP )
{
- if ( first <= -input_size )
- first = -(input_size-1);
+ if ( first < -input_size )
+ first = -input_size;
if ( last >= (input_size*2))
last = (input_size*2) - 1;
}
-
+
*first_pixel = first;
*last_pixel = last;
}
@@ -3213,10 +3276,10 @@ static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_
int i;
int last_non_zero;
float out_pixel_center = (float)n + 0.5f;
- float in_center_of_out = (out_pixel_center + out_shift) * inv_scale;
+ float in_center_of_out = (out_pixel_center + out_shift) * inv_scale;
int in_first_pixel, in_last_pixel;
-
+
stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, out_pixel_center, out_filter_radius, inv_scale, out_shift, input_size, edge );
last_non_zero = -1;
@@ -3229,7 +3292,7 @@ static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_
if ( ( ( coeff < stbir__small_float ) && ( coeff > -stbir__small_float ) ) )
{
if ( i == 0 ) // if we're at the front, just eat zero contributors
- {
+ {
STBIR_ASSERT ( ( in_last_pixel - in_first_pixel ) != 0 ); // there should be at least one contrib
++in_first_pixel;
i--;
@@ -3239,10 +3302,10 @@ static void stbir__calculate_coefficients_for_gather_upsample( float out_filter_
}
else
last_non_zero = i;
-
+
coefficient_group[i] = coeff;
}
-
+
in_last_pixel = last_non_zero+in_first_pixel; // kills trailing zeros
contributors->n0 = in_first_pixel;
contributors->n1 = in_last_pixel;
@@ -3354,7 +3417,7 @@ static void stbir__calculate_coefficients_for_gather_downsample( int start, int
stbir__contributors * contribs = contributors + out;
// is this the first time this output pixel has been seen? Init it.
- if ( out > first_out_inited )
+ if ( out > first_out_inited )
{
STBIR_ASSERT( out == ( first_out_inited + 1 ) ); // ensure we have only advanced one at time
first_out_inited = out;
@@ -3362,7 +3425,7 @@ static void stbir__calculate_coefficients_for_gather_downsample( int start, int
contribs->n1 = in_pixel;
coeffs[0] = coeff;
}
- else
+ else
{
// insert on end (always in order)
if ( coeffs[0] == 0.0f ) // if the first coefficent is zero, then zap it for this coeffs
@@ -3379,10 +3442,16 @@ static void stbir__calculate_coefficients_for_gather_downsample( int start, int
}
}
+#ifdef STBIR_RENORMALIZE_IN_FLOAT
+#define STBIR_RENORM_TYPE float
+#else
+#define STBIR_RENORM_TYPE double
+#endif
+
static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter_extent_info* filter_info, stbir__scale_info * scale_info, int num_contributors, stbir__contributors* contributors, float * coefficient_group, int coefficient_width )
{
int input_size = scale_info->input_full_size;
- int input_last_n1 = input_size - 1;
+ int input_last_n1 = input_size - 1;
int n, end;
int lowest = 0x7fffffff;
int highest = -0x7fffffff;
@@ -3400,14 +3469,14 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter
for (n = 0; n < end; n++)
{
int i;
- float filter_scale, total_filter = 0;
+ STBIR_RENORM_TYPE filter_scale, total_filter = 0;
int e;
// add all contribs
e = contribs->n1 - contribs->n0;
for( i = 0 ; i <= e ; i++ )
{
- total_filter += coeffs[i];
+ total_filter += (STBIR_RENORM_TYPE) coeffs[i];
STBIR_ASSERT( ( coeffs[i] >= -2.0f ) && ( coeffs[i] <= 2.0f ) ); // check for wonky weights
}
@@ -3423,10 +3492,11 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter
// if the total isn't 1.0, rescale everything
if ( ( total_filter < (1.0f-stbir__small_float) ) || ( total_filter > (1.0f+stbir__small_float) ) )
{
- filter_scale = 1.0f / total_filter;
+ filter_scale = ((STBIR_RENORM_TYPE)1.0) / total_filter;
+
// scale them all
for (i = 0; i <= e; i++)
- coeffs[i] *= filter_scale;
+ coeffs[i] = (float) ( coeffs[i] * filter_scale );
}
}
++contribs;
@@ -3483,13 +3553,13 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter
else if ( ( edge == STBIR_EDGE_CLAMP ) || ( edge == STBIR_EDGE_REFLECT ) )
{
// for clamp and reflect, calculate the true inbounds position (based on edge type) and just add that to the existing weight
-
+
// right hand side first
if ( contribs->n1 > input_last_n1 )
{
int start = contribs->n0;
int endi = contribs->n1;
- contribs->n1 = input_last_n1;
+ contribs->n1 = input_last_n1;
for( i = input_size; i <= endi; i++ )
stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), coeffs[i-start] );
}
@@ -3500,18 +3570,18 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter
int save_n0;
float save_n0_coeff;
float * c = coeffs - ( contribs->n0 + 1 );
-
+
// reinsert the coeffs with it reflected or clamped (insert accumulates, if the coeffs exist)
- for( i = -1 ; i > contribs->n0 ; i-- )
+ for( i = -1 ; i > contribs->n0 ; i-- )
stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( i, input_size ), *c-- );
save_n0 = contribs->n0;
save_n0_coeff = c[0]; // save it, since we didn't do the final one (i==n0), because there might be too many coeffs to hold (before we resize)!
// now slide all the coeffs down (since we have accumulated them in the positive contribs) and reset the first contrib
- contribs->n0 = 0;
+ contribs->n0 = 0;
for(i = 0 ; i <= contribs->n1 ; i++ )
coeffs[i] = coeffs[i-save_n0];
-
+
// now that we have shrunk down the contribs, we insert the first one safely
stbir__insert_coeff( contribs, coeffs, stbir__edge_wrap_slow[edge]( save_n0, input_size ), save_n0_coeff );
}
@@ -3547,7 +3617,9 @@ static void stbir__cleanup_gathered_coefficients( stbir_edge edge, stbir__filter
filter_info->widest = widest;
}
-static int stbir__pack_coefficients( int num_contributors, stbir__contributors* contributors, float * coefficents, int coefficient_width, int widest, int row_width )
+#undef STBIR_RENORM_TYPE
+
+static int stbir__pack_coefficients( int num_contributors, stbir__contributors* contributors, float * coefficents, int coefficient_width, int widest, int row0, int row1 )
{
#define STBIR_MOVE_1( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint32*)(dest))[0] = ((stbir_uint32*)(src))[0]; }
#define STBIR_MOVE_2( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; }
@@ -3556,6 +3628,10 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
#else
#define STBIR_MOVE_4( dest, src ) { STBIR_NO_UNROLL(dest); ((stbir_uint64*)(dest))[0] = ((stbir_uint64*)(src))[0]; ((stbir_uint64*)(dest))[1] = ((stbir_uint64*)(src))[1]; }
#endif
+
+ int row_end = row1 + 1;
+ STBIR__UNUSED( row0 ); // only used in an assert
+
if ( coefficient_width != widest )
{
float * pc = coefficents;
@@ -3564,6 +3640,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
switch( widest )
{
case 1:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_1( pc, coeffs );
++pc;
@@ -3571,6 +3648,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 2:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_2( pc, coeffs );
pc += 2;
@@ -3578,6 +3656,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 3:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_2( pc, coeffs );
STBIR_MOVE_1( pc+2, coeffs+2 );
@@ -3586,6 +3665,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 4:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_4( pc, coeffs );
pc += 4;
@@ -3593,6 +3673,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 5:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_4( pc, coeffs );
STBIR_MOVE_1( pc+4, coeffs+4 );
@@ -3601,6 +3682,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 6:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_4( pc, coeffs );
STBIR_MOVE_2( pc+4, coeffs+4 );
@@ -3609,6 +3691,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 7:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_4( pc, coeffs );
STBIR_MOVE_2( pc+4, coeffs+4 );
@@ -3618,6 +3701,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 8:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_4( pc, coeffs );
STBIR_MOVE_4( pc+4, coeffs+4 );
@@ -3626,6 +3710,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 9:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_4( pc, coeffs );
STBIR_MOVE_4( pc+4, coeffs+4 );
@@ -3635,6 +3720,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 10:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_4( pc, coeffs );
STBIR_MOVE_4( pc+4, coeffs+4 );
@@ -3644,6 +3730,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 11:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_4( pc, coeffs );
STBIR_MOVE_4( pc+4, coeffs+4 );
@@ -3654,6 +3741,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
case 12:
+ STBIR_NO_UNROLL_LOOP_START
do {
STBIR_MOVE_4( pc, coeffs );
STBIR_MOVE_4( pc+4, coeffs+4 );
@@ -3663,6 +3751,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
} while ( pc < pc_end );
break;
default:
+ STBIR_NO_UNROLL_LOOP_START
do {
float * copy_end = pc + widest - 4;
float * c = coeffs;
@@ -3673,6 +3762,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
c += 4;
} while ( pc <= copy_end );
copy_end += 4;
+ STBIR_NO_UNROLL_LOOP_START
while ( pc < copy_end )
{
STBIR_MOVE_1( pc, c );
@@ -3688,7 +3778,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
coefficents[ widest * num_contributors ] = 8888.0f;
// the minimum we might read for unrolled filters widths is 12. So, we need to
- // make sure we never read outside the decode buffer, by possibly moving
+ // make sure we never read outside the decode buffer, by possibly moving
// the sample area back into the scanline, and putting zeros weights first.
// we start on the right edge and check until we're well past the possible
// clip area (2*widest).
@@ -3697,13 +3787,13 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
float * coeffs = coefficents + widest * ( num_contributors - 1 );
// go until no chance of clipping (this is usually less than 8 lops)
- while ( ( ( contribs->n0 + widest*2 ) >= row_width ) && ( contribs >= contributors ) )
+ while ( ( contribs >= contributors ) && ( ( contribs->n0 + widest*2 ) >= row_end ) )
{
// might we clip??
- if ( ( contribs->n0 + widest ) > row_width )
+ if ( ( contribs->n0 + widest ) > row_end )
{
int stop_range = widest;
-
+
// if range is larger than 12, it will be handled by generic loops that can terminate on the exact length
// of this contrib n1, instead of a fixed widest amount - so calculate this
if ( widest > 12 )
@@ -3712,22 +3802,22 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
// how far will be read in the n_coeff loop (which depends on the widest count mod4);
mod = widest & 3;
- stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod;
+ stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod;
// the n_coeff loops do a minimum amount of coeffs, so factor that in!
if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod;
}
// now see if we still clip with the refined range
- if ( ( contribs->n0 + stop_range ) > row_width )
+ if ( ( contribs->n0 + stop_range ) > row_end )
{
- int new_n0 = row_width - stop_range;
+ int new_n0 = row_end - stop_range;
int num = contribs->n1 - contribs->n0 + 1;
int backup = contribs->n0 - new_n0;
float * from_co = coeffs + num - 1;
float * to_co = from_co + backup;
- STBIR_ASSERT( ( new_n0 >= 0 ) && ( new_n0 < contribs->n0 ) );
+ STBIR_ASSERT( ( new_n0 >= row0 ) && ( new_n0 < contribs->n0 ) );
// move the coeffs over
while( num )
@@ -3746,7 +3836,7 @@ static int stbir__pack_coefficients( int num_contributors, stbir__contributors*
// how far will be read in the n_coeff loop (which depends on the widest count mod4);
mod = widest & 3;
- stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod;
+ stop_range = ( ( ( contribs->n1 - contribs->n0 + 1 ) - mod + 3 ) & ~3 ) + mod;
// the n_coeff loops do a minimum amount of coeffs, so factor that in!
if ( stop_range < ( 8 + mod ) ) stop_range = 8 + mod;
@@ -3774,7 +3864,7 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot
int input_full_size = samp->scale_info.input_full_size;
int gather_num_contributors = samp->num_contributors;
stbir__contributors* gather_contributors = samp->contributors;
- float * gather_coeffs = samp->coefficients;
+ float * gather_coeffs = samp->coefficients;
int gather_coefficient_width = samp->coefficient_width;
switch ( samp->is_gather )
@@ -3792,16 +3882,16 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot
break;
case 0: // scatter downsample (only on vertical)
- case 2: // gather downsample
+ case 2: // gather downsample
{
float in_pixels_radius = support(scale,user_data) * inv_scale;
int filter_pixel_margin = samp->filter_pixel_margin;
int input_end = input_full_size + filter_pixel_margin;
-
+
// if this is a scatter, we do a downsample gather to get the coeffs, and then pivot after
if ( !samp->is_gather )
{
- // check if we are using the same gather downsample on the horizontal as this vertical,
+ // check if we are using the same gather downsample on the horizontal as this vertical,
// if so, then we don't have to generate them, we can just pivot from the horizontal.
if ( other_axis_for_pivot )
{
@@ -3846,30 +3936,37 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot
float * scatter_coeffs = samp->coefficients + ( gn0 + filter_pixel_margin ) * scatter_coefficient_width;
float * g_coeffs = gather_coeffs;
scatter_contributors = samp->contributors + ( gn0 + filter_pixel_margin );
-
+
for (k = gn0 ; k <= gn1 ; k++ )
{
float gc = *g_coeffs++;
- if ( ( k > highest_set ) || ( scatter_contributors->n0 > scatter_contributors->n1 ) )
+
+ // skip zero and denormals - must skip zeros to avoid adding coeffs beyond scatter_coefficient_width
+ // (which happens when pivoting from horizontal, which might have dummy zeros)
+ if ( ( ( gc >= stbir__small_float ) || ( gc <= -stbir__small_float ) ) )
{
+ if ( ( k > highest_set ) || ( scatter_contributors->n0 > scatter_contributors->n1 ) )
{
- // if we are skipping over several contributors, we need to clear the skipped ones
- stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1);
- while ( clear_contributors < scatter_contributors )
{
- clear_contributors->n0 = 0;
- clear_contributors->n1 = -1;
- ++clear_contributors;
+ // if we are skipping over several contributors, we need to clear the skipped ones
+ stbir__contributors * clear_contributors = samp->contributors + ( highest_set + filter_pixel_margin + 1);
+ while ( clear_contributors < scatter_contributors )
+ {
+ clear_contributors->n0 = 0;
+ clear_contributors->n1 = -1;
+ ++clear_contributors;
+ }
}
+ scatter_contributors->n0 = n;
+ scatter_contributors->n1 = n;
+ scatter_coeffs[0] = gc;
+ highest_set = k;
}
- scatter_contributors->n0 = n;
- scatter_contributors->n1 = n;
- scatter_coeffs[0] = gc;
- highest_set = k;
- }
- else
- {
- stbir__insert_coeff( scatter_contributors, scatter_coeffs, n, gc );
+ else
+ {
+ stbir__insert_coeff( scatter_contributors, scatter_coeffs, n, gc );
+ }
+ STBIR_ASSERT( ( scatter_contributors->n1 - scatter_contributors->n0 + 1 ) <= scatter_coefficient_width );
}
++scatter_contributors;
scatter_coeffs += scatter_coefficient_width;
@@ -3908,11 +4005,11 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot
#define stbir__decode_suffix BGRA
#define stbir__decode_swizzle
-#define stbir__decode_order0 2
+#define stbir__decode_order0 2
#define stbir__decode_order1 1
#define stbir__decode_order2 0
#define stbir__decode_order3 3
-#define stbir__encode_order0 2
+#define stbir__encode_order0 2
#define stbir__encode_order1 1
#define stbir__encode_order2 0
#define stbir__encode_order3 3
@@ -3922,11 +4019,11 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot
#define stbir__decode_suffix ARGB
#define stbir__decode_swizzle
-#define stbir__decode_order0 1
+#define stbir__decode_order0 1
#define stbir__decode_order1 2
#define stbir__decode_order2 3
#define stbir__decode_order3 0
-#define stbir__encode_order0 3
+#define stbir__encode_order0 3
#define stbir__encode_order1 0
#define stbir__encode_order2 1
#define stbir__encode_order3 2
@@ -3936,11 +4033,11 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot
#define stbir__decode_suffix ABGR
#define stbir__decode_swizzle
-#define stbir__decode_order0 3
+#define stbir__decode_order0 3
#define stbir__decode_order1 2
#define stbir__decode_order2 1
#define stbir__decode_order3 0
-#define stbir__encode_order0 3
+#define stbir__encode_order0 3
#define stbir__encode_order1 2
#define stbir__encode_order2 1
#define stbir__encode_order3 0
@@ -3950,12 +4047,12 @@ static void stbir__calculate_filters( stbir__sampler * samp, stbir__sampler * ot
#define stbir__decode_suffix AR
#define stbir__decode_swizzle
-#define stbir__decode_order0 1
-#define stbir__decode_order1 0
+#define stbir__decode_order0 1
+#define stbir__decode_order1 0
#define stbir__decode_order2 3
#define stbir__decode_order3 2
-#define stbir__encode_order0 1
-#define stbir__encode_order1 0
+#define stbir__encode_order0 1
+#define stbir__encode_order1 0
#define stbir__encode_order2 3
#define stbir__encode_order3 2
#define stbir__coder_min_num 2
@@ -3973,9 +4070,10 @@ static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_c
// fancy alpha is stored internally as R G B A Rpm Gpm Bpm
#ifdef STBIR_SIMD
-
+
#ifdef STBIR_SIMD8
decode += 16;
+ STBIR_NO_UNROLL_LOOP_START
while ( decode <= end_decode )
{
stbir__simdf8 d0,d1,a0,a1,p0,p1;
@@ -3998,8 +4096,9 @@ static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_c
out += 28;
}
decode -= 16;
- #else
+ #else
decode += 8;
+ STBIR_NO_UNROLL_LOOP_START
while ( decode <= end_decode )
{
stbir__simdf d0,a0,d1,a1,p0,p1;
@@ -4022,12 +4121,14 @@ static void stbir__fancy_alpha_weight_4ch( float * out_buffer, int width_times_c
// might be one last odd pixel
#ifdef STBIR_SIMD8
+ STBIR_NO_UNROLL_LOOP_START
while ( decode < end_decode )
#else
if ( decode < end_decode )
#endif
{
stbir__simdf d,a,p;
+ STBIR_NO_UNROLL(decode);
stbir__simdf_load( d, decode );
stbir__simdf_0123to3333( a, d );
stbir__simdf_mult( p, a, d );
@@ -4069,6 +4170,7 @@ static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_c
decode += 8;
if ( decode <= end_decode )
{
+ STBIR_NO_UNROLL_LOOP_START
do {
#ifdef STBIR_SIMD8
stbir__simdf8 d0,a0,p0;
@@ -4077,11 +4179,11 @@ static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_c
stbir__simdf8_0123to11331133( p0, d0 );
stbir__simdf8_0123to00220022( a0, d0 );
stbir__simdf8_mult( p0, p0, a0 );
-
+
stbir__simdf_store2( out, stbir__if_simdf8_cast_to_simdf4( d0 ) );
stbir__simdf_store( out+2, stbir__if_simdf8_cast_to_simdf4( p0 ) );
stbir__simdf_store2h( out+3, stbir__if_simdf8_cast_to_simdf4( d0 ) );
-
+
stbir__simdf_store2( out+6, stbir__simdf8_gettop4( d0 ) );
stbir__simdf_store( out+8, stbir__simdf8_gettop4( p0 ) );
stbir__simdf_store2h( out+9, stbir__simdf8_gettop4( d0 ) );
@@ -4112,6 +4214,7 @@ static void stbir__fancy_alpha_weight_2ch( float * out_buffer, int width_times_c
decode -= 8;
#endif
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( decode < end_decode )
{
float x = decode[0], y = decode[1];
@@ -4132,6 +4235,7 @@ static void stbir__fancy_alpha_unweight_4ch( float * encode_buffer, int width_ti
// fancy RGBA is stored internally as R G B A Rpm Gpm Bpm
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
float alpha = input[3];
#ifdef STBIR_SIMD
@@ -4199,6 +4303,7 @@ static void stbir__simple_alpha_weight_4ch( float * decode_buffer, int width_tim
#ifdef STBIR_SIMD
{
decode += 2 * stbir__simdfX_float_count;
+ STBIR_NO_UNROLL_LOOP_START
while ( decode <= end_decode )
{
stbir__simdfX d0,a0,d1,a1;
@@ -4217,6 +4322,7 @@ static void stbir__simple_alpha_weight_4ch( float * decode_buffer, int width_tim
// few last pixels remnants
#ifdef STBIR_SIMD8
+ STBIR_NO_UNROLL_LOOP_START
while ( decode < end_decode )
#else
if ( decode < end_decode )
@@ -4252,6 +4358,7 @@ static void stbir__simple_alpha_weight_2ch( float * decode_buffer, int width_tim
#ifdef STBIR_SIMD
decode += 2 * stbir__simdfX_float_count;
+ STBIR_NO_UNROLL_LOOP_START
while ( decode <= end_decode )
{
stbir__simdfX d0,a0,d1,a1;
@@ -4269,6 +4376,7 @@ static void stbir__simple_alpha_weight_2ch( float * decode_buffer, int width_tim
decode -= 2 * stbir__simdfX_float_count;
#endif
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( decode < end_decode )
{
float alpha = decode[1];
@@ -4283,6 +4391,7 @@ static void stbir__simple_alpha_unweight_4ch( float * encode_buffer, int width_t
float STBIR_SIMD_STREAMOUT_PTR(*) encode = encode_buffer;
float const * end_output = encode_buffer + width_times_channels;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
float alpha = encode[3];
@@ -4330,9 +4439,77 @@ static void stbir__simple_flip_3ch( float * decode_buffer, int width_times_chann
float STBIR_STREAMOUT_PTR(*) decode = decode_buffer;
float const * end_decode = decode_buffer + width_times_channels;
- decode += 12;
+#ifdef STBIR_SIMD
+ #ifdef stbir__simdf_swiz2 // do we have two argument swizzles?
+ end_decode -= 12;
+ STBIR_NO_UNROLL_LOOP_START
+ while( decode <= end_decode )
+ {
+ // on arm64 8 instructions, no overlapping stores
+ stbir__simdf a,b,c,na,nb;
+ STBIR_SIMD_NO_UNROLL(decode);
+ stbir__simdf_load( a, decode );
+ stbir__simdf_load( b, decode+4 );
+ stbir__simdf_load( c, decode+8 );
+
+ na = stbir__simdf_swiz2( a, b, 2, 1, 0, 5 );
+ b = stbir__simdf_swiz2( a, b, 4, 3, 6, 7 );
+ nb = stbir__simdf_swiz2( b, c, 0, 1, 4, 3 );
+ c = stbir__simdf_swiz2( b, c, 2, 7, 6, 5 );
+
+ stbir__simdf_store( decode, na );
+ stbir__simdf_store( decode+4, nb );
+ stbir__simdf_store( decode+8, c );
+ decode += 12;
+ }
+ end_decode += 12;
+ #else
+ end_decode -= 24;
+ STBIR_NO_UNROLL_LOOP_START
+ while( decode <= end_decode )
+ {
+ // 26 instructions on x64
+ stbir__simdf a,b,c,d,e,f,g;
+ float i21, i23;
+ STBIR_SIMD_NO_UNROLL(decode);
+ stbir__simdf_load( a, decode );
+ stbir__simdf_load( b, decode+3 );
+ stbir__simdf_load( c, decode+6 );
+ stbir__simdf_load( d, decode+9 );
+ stbir__simdf_load( e, decode+12 );
+ stbir__simdf_load( f, decode+15 );
+ stbir__simdf_load( g, decode+18 );
+
+ a = stbir__simdf_swiz( a, 2, 1, 0, 3 );
+ b = stbir__simdf_swiz( b, 2, 1, 0, 3 );
+ c = stbir__simdf_swiz( c, 2, 1, 0, 3 );
+ d = stbir__simdf_swiz( d, 2, 1, 0, 3 );
+ e = stbir__simdf_swiz( e, 2, 1, 0, 3 );
+ f = stbir__simdf_swiz( f, 2, 1, 0, 3 );
+ g = stbir__simdf_swiz( g, 2, 1, 0, 3 );
+
+ // stores overlap, need to be in order,
+ stbir__simdf_store( decode, a );
+ i21 = decode[21];
+ stbir__simdf_store( decode+3, b );
+ i23 = decode[23];
+ stbir__simdf_store( decode+6, c );
+ stbir__simdf_store( decode+9, d );
+ stbir__simdf_store( decode+12, e );
+ stbir__simdf_store( decode+15, f );
+ stbir__simdf_store( decode+18, g );
+ decode[21] = i23;
+ decode[23] = i21;
+ decode += 24;
+ }
+ end_decode += 24;
+ #endif
+#else
+ end_decode -= 12;
+ STBIR_NO_UNROLL_LOOP_START
while( decode <= end_decode )
{
+ // 16 instructions
float t0,t1,t2,t3;
STBIR_NO_UNROLL(decode);
t0 = decode[0]; t1 = decode[3]; t2 = decode[6]; t3 = decode[9];
@@ -4340,8 +4517,10 @@ static void stbir__simple_flip_3ch( float * decode_buffer, int width_times_chann
decode[2] = t0; decode[5] = t1; decode[8] = t2; decode[11] = t3;
decode += 12;
}
- decode -= 12;
+ end_decode += 12;
+#endif
+ STBIR_NO_UNROLL_LOOP_START
while( decode < end_decode )
{
float t = decode[0];
@@ -4362,14 +4541,14 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir_edge edge_horizontal = stbir_info->horizontal.edge;
stbir_edge edge_vertical = stbir_info->vertical.edge;
int row = stbir__edge_wrap(edge_vertical, n, stbir_info->vertical.scale_info.input_full_size);
- const void* input_plane_data = ( (char *) stbir_info->input_data ) + (ptrdiff_t)row * (ptrdiff_t) stbir_info->input_stride_bytes;
+ const void* input_plane_data = ( (char *) stbir_info->input_data ) + (size_t)row * (size_t) stbir_info->input_stride_bytes;
stbir__span const * spans = stbir_info->scanline_extents.spans;
float* full_decode_buffer = output_buffer - stbir_info->scanline_extents.conservative.n0 * effective_channels;
// if we are on edge_zero, and we get in here with an out of bounds n, then the calculate filters has failed
STBIR_ASSERT( !(edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->vertical.scale_info.input_full_size)) );
- do
+ do
{
float * decode_buffer;
void const * input_data;
@@ -4377,7 +4556,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
int width_times_channels;
int width;
- if ( spans->n1 < spans->n0 )
+ if ( spans->n1 < spans->n0 )
break;
width = spans->n1 + 1 - spans->n0;
@@ -4394,7 +4573,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
// call the callback with a temp buffer (that they can choose to use or not). the temp is just right aligned memory in the decode_buffer itself
input_data = stbir_info->in_pixels_cb( ( (char*) end_decode ) - ( width * input_sample_in_bytes ), input_plane_data, width, spans->pixel_offset_for_input, row, stbir_info->user_data );
}
-
+
STBIR_PROFILE_START( decode );
// convert the pixels info the float decode_buffer, (we index from end_decode, so that when channelsdecode_pixels( (float*)end_decode - width_times_channels, width_times_channels, input_data );
@@ -4418,7 +4597,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
// this code only runs if we're in edge_wrap, and we're doing the entire scanline
int e, start_x[2];
int input_full_size = stbir_info->horizontal.scale_info.input_full_size;
-
+
start_x[0] = -stbir_info->scanline_extents.edge_sizes[0]; // left edge start x
start_x[1] = input_full_size; // right edge
@@ -4447,7 +4626,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf tot,c; \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf_load1( c, hc ); \
- stbir__simdf_mult1_mem( tot, c, decode );
+ stbir__simdf_mult1_mem( tot, c, decode );
#define stbir__2_coeff_only() \
stbir__simdf tot,c,d; \
@@ -4456,7 +4635,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_load2( d, decode ); \
stbir__simdf_mult( tot, c, d ); \
stbir__simdf_0123to1230( c, tot ); \
- stbir__simdf_add1( tot, tot, c );
+ stbir__simdf_add1( tot, tot, c );
#define stbir__3_coeff_only() \
stbir__simdf tot,c,t; \
@@ -4466,7 +4645,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_0123to1230( c, tot ); \
stbir__simdf_0123to2301( t, tot ); \
stbir__simdf_add1( tot, tot, c ); \
- stbir__simdf_add1( tot, tot, t );
+ stbir__simdf_add1( tot, tot, t );
#define stbir__store_output_tiny() \
stbir__simdf_store1( output, tot ); \
@@ -4483,7 +4662,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
#define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf_load( c, hc + (ofs) ); \
- stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) );
+ stbir__simdf_madd_mem( tot, tot, c, decode+(ofs) );
#define stbir__1_coeff_remnant( ofs ) \
{ stbir__simdf d; \
@@ -4495,7 +4674,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
{ stbir__simdf d; \
stbir__simdf_load2z( c, hc+(ofs) ); \
stbir__simdf_load2( d, decode+(ofs) ); \
- stbir__simdf_madd( tot, tot, d, c ); }
+ stbir__simdf_madd( tot, tot, d, c ); }
#define stbir__3_coeff_setup() \
stbir__simdf mask; \
@@ -4520,18 +4699,18 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
#define stbir__1_coeff_only() \
float tot; \
- tot = decode[0]*hc[0];
+ tot = decode[0]*hc[0];
#define stbir__2_coeff_only() \
float tot; \
tot = decode[0] * hc[0]; \
- tot += decode[1] * hc[1];
+ tot += decode[1] * hc[1];
#define stbir__3_coeff_only() \
float tot; \
tot = decode[0] * hc[0]; \
tot += decode[1] * hc[1]; \
- tot += decode[2] * hc[2];
+ tot += decode[2] * hc[2];
#define stbir__store_output_tiny() \
output[0] = tot; \
@@ -4544,16 +4723,16 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
tot0 = decode[0] * hc[0]; \
tot1 = decode[1] * hc[1]; \
tot2 = decode[2] * hc[2]; \
- tot3 = decode[3] * hc[3];
+ tot3 = decode[3] * hc[3];
#define stbir__4_coeff_continue_from_4( ofs ) \
tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \
tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \
tot2 += decode[2+(ofs)] * hc[2+(ofs)]; \
- tot3 += decode[3+(ofs)] * hc[3+(ofs)];
+ tot3 += decode[3+(ofs)] * hc[3+(ofs)];
#define stbir__1_coeff_remnant( ofs ) \
- tot0 += decode[0+(ofs)] * hc[0+(ofs)];
+ tot0 += decode[0+(ofs)] * hc[0+(ofs)];
#define stbir__2_coeff_remnant( ofs ) \
tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \
@@ -4562,7 +4741,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
#define stbir__3_coeff_remnant( ofs ) \
tot0 += decode[0+(ofs)] * hc[0+(ofs)]; \
tot1 += decode[1+(ofs)] * hc[1+(ofs)]; \
- tot2 += decode[2+(ofs)] * hc[2+(ofs)];
+ tot2 += decode[2+(ofs)] * hc[2+(ofs)];
#define stbir__store_output() \
output[0] = (tot0+tot2)+(tot1+tot3); \
@@ -4570,7 +4749,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
++horizontal_contributors; \
output += 1;
-#endif
+#endif
#define STBIR__horizontal_channels 1
#define STB_IMAGE_RESIZE_DO_HORIZONTALS
@@ -4588,14 +4767,14 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_load1z( c, hc ); \
stbir__simdf_0123to0011( c, c ); \
stbir__simdf_load2( d, decode ); \
- stbir__simdf_mult( tot, d, c );
+ stbir__simdf_mult( tot, d, c );
#define stbir__2_coeff_only() \
stbir__simdf tot,c; \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf_load2( c, hc ); \
stbir__simdf_0123to0011( c, c ); \
- stbir__simdf_mult_mem( tot, c, decode );
+ stbir__simdf_mult_mem( tot, c, decode );
#define stbir__3_coeff_only() \
stbir__simdf tot,c,cs,d; \
@@ -4605,7 +4784,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_mult_mem( tot, c, decode ); \
stbir__simdf_0123to2222( c, cs ); \
stbir__simdf_load2z( d, decode+4 ); \
- stbir__simdf_madd( tot, tot, d, c );
+ stbir__simdf_madd( tot, tot, d, c );
#define stbir__store_output_tiny() \
stbir__simdf_0123to2301( c, tot ); \
@@ -4628,7 +4807,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf8_load4b( cs, hc + (ofs) ); \
stbir__simdf8_0123to00112233( c, cs ); \
- stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*2 );
+ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*2 );
#define stbir__1_coeff_remnant( ofs ) \
{ stbir__simdf t; \
@@ -4649,13 +4828,13 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf8_load4b( cs, hc + (ofs) ); \
stbir__simdf8_0123to00112233( c, cs ); \
stbir__simdf8_load6z( d, decode+(ofs)*2 ); \
- stbir__simdf8_madd( tot0, tot0, c, d ); }
+ stbir__simdf8_madd( tot0, tot0, c, d ); }
#define stbir__store_output() \
- { stbir__simdf t,c; \
+ { stbir__simdf t,d; \
stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \
- stbir__simdf_0123to2301( c, t ); \
- stbir__simdf_add( t, t, c ); \
+ stbir__simdf_0123to2301( d, t ); \
+ stbir__simdf_add( t, t, d ); \
stbir__simdf_store2( output, t ); \
horizontal_coefficients += coefficient_width; \
++horizontal_contributors; \
@@ -4670,7 +4849,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_0123to0011( c, cs ); \
stbir__simdf_mult_mem( tot0, c, decode ); \
stbir__simdf_0123to2233( c, cs ); \
- stbir__simdf_mult_mem( tot1, c, decode+4 );
+ stbir__simdf_mult_mem( tot1, c, decode+4 );
#define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -4678,7 +4857,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_0123to0011( c, cs ); \
stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); \
stbir__simdf_0123to2233( c, cs ); \
- stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*2+4 );
+ stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*2+4 );
#define stbir__1_coeff_remnant( ofs ) \
{ stbir__simdf d; \
@@ -4690,7 +4869,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
#define stbir__2_coeff_remnant( ofs ) \
stbir__simdf_load2( cs, hc + (ofs) ); \
stbir__simdf_0123to0011( c, cs ); \
- stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 );
+ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 );
#define stbir__3_coeff_remnant( ofs ) \
{ stbir__simdf d; \
@@ -4699,7 +4878,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*2 ); \
stbir__simdf_0123to2222( c, cs ); \
stbir__simdf_load2z( d, decode + (ofs) * 2 + 4 ); \
- stbir__simdf_madd( tot1, tot1, d, c ); }
+ stbir__simdf_madd( tot1, tot1, d, c ); }
#define stbir__store_output() \
stbir__simdf_add( tot0, tot0, tot1 ); \
@@ -4718,7 +4897,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
float tota,totb,c; \
c = hc[0]; \
tota = decode[0]*c; \
- totb = decode[1]*c;
+ totb = decode[1]*c;
#define stbir__2_coeff_only() \
float tota,totb,c; \
@@ -4727,7 +4906,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
totb = decode[1]*c; \
c = hc[1]; \
tota += decode[2]*c; \
- totb += decode[3]*c;
+ totb += decode[3]*c;
// this weird order of add matches the simd
#define stbir__3_coeff_only() \
@@ -4740,7 +4919,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
totb += decode[5]*c; \
c = hc[1]; \
tota += decode[2]*c; \
- totb += decode[3]*c;
+ totb += decode[3]*c;
#define stbir__store_output_tiny() \
output[0] = tota; \
@@ -4762,7 +4941,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
totb2 = decode[5]*c; \
c = hc[3]; \
tota3 = decode[6]*c; \
- totb3 = decode[7]*c;
+ totb3 = decode[7]*c;
#define stbir__4_coeff_continue_from_4( ofs ) \
c = hc[0+(ofs)]; \
@@ -4776,12 +4955,12 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
totb2 += decode[5+(ofs)*2]*c; \
c = hc[3+(ofs)]; \
tota3 += decode[6+(ofs)*2]*c; \
- totb3 += decode[7+(ofs)*2]*c;
+ totb3 += decode[7+(ofs)*2]*c;
#define stbir__1_coeff_remnant( ofs ) \
c = hc[0+(ofs)]; \
tota0 += decode[0+(ofs)*2] * c; \
- totb0 += decode[1+(ofs)*2] * c;
+ totb0 += decode[1+(ofs)*2] * c;
#define stbir__2_coeff_remnant( ofs ) \
c = hc[0+(ofs)]; \
@@ -4789,7 +4968,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
totb0 += decode[1+(ofs)*2] * c; \
c = hc[1+(ofs)]; \
tota1 += decode[2+(ofs)*2] * c; \
- totb1 += decode[3+(ofs)*2] * c;
+ totb1 += decode[3+(ofs)*2] * c;
#define stbir__3_coeff_remnant( ofs ) \
c = hc[0+(ofs)]; \
@@ -4800,7 +4979,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
totb1 += decode[3+(ofs)*2] * c; \
c = hc[2+(ofs)]; \
tota2 += decode[4+(ofs)*2] * c; \
- totb2 += decode[5+(ofs)*2] * c;
+ totb2 += decode[5+(ofs)*2] * c;
#define stbir__store_output() \
output[0] = (tota0+tota2)+(tota1+tota3); \
@@ -4809,7 +4988,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
++horizontal_contributors; \
output += 2;
-#endif
+#endif
#define STBIR__horizontal_channels 2
#define STB_IMAGE_RESIZE_DO_HORIZONTALS
@@ -4827,7 +5006,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_load1z( c, hc ); \
stbir__simdf_0123to0001( c, c ); \
stbir__simdf_load( d, decode ); \
- stbir__simdf_mult( tot, d, c );
+ stbir__simdf_mult( tot, d, c );
#define stbir__2_coeff_only() \
stbir__simdf tot,c,cs,d; \
@@ -4838,7 +5017,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_mult( tot, d, c ); \
stbir__simdf_0123to1111( c, cs ); \
stbir__simdf_load( d, decode+3 ); \
- stbir__simdf_madd( tot, tot, d, c );
+ stbir__simdf_madd( tot, tot, d, c );
#define stbir__3_coeff_only() \
stbir__simdf tot,c,d,cs; \
@@ -4852,7 +5031,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_madd( tot, tot, d, c ); \
stbir__simdf_0123to2222( c, cs ); \
stbir__simdf_load( d, decode+6 ); \
- stbir__simdf_madd( tot, tot, d, c );
+ stbir__simdf_madd( tot, tot, d, c );
#define stbir__store_output_tiny() \
stbir__simdf_store2( output, tot ); \
@@ -4872,7 +5051,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf8_0123to00001111( c, cs ); \
stbir__simdf8_mult_mem( tot0, c, decode - 1 ); \
stbir__simdf8_0123to22223333( c, cs ); \
- stbir__simdf8_mult_mem( tot1, c, decode+6 - 1 );
+ stbir__simdf8_mult_mem( tot1, c, decode+6 - 1 );
#define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -4880,26 +5059,26 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf8_0123to00001111( c, cs ); \
stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); \
stbir__simdf8_0123to22223333( c, cs ); \
- stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*3 + 6 - 1 );
+ stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*3 + 6 - 1 );
#define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf_load1rep4( t, hc + (ofs) ); \
- stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*3 - 1 );
+ stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*3 - 1 );
#define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf8_load4b( cs, hc + (ofs) - 2 ); \
stbir__simdf8_0123to22223333( c, cs ); \
- stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 );
-
+ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 );
+
#define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf8_load4b( cs, hc + (ofs) ); \
stbir__simdf8_0123to00001111( c, cs ); \
stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*3 - 1 ); \
stbir__simdf8_0123to2222( t, cs ); \
- stbir__simdf8_madd_mem4( tot1, tot1, t, decode+(ofs)*3 + 6 - 1 );
+ stbir__simdf8_madd_mem4( tot1, tot1, t, decode+(ofs)*3 + 6 - 1 );
#define stbir__store_output() \
stbir__simdf8_add( tot0, tot0, tot1 ); \
@@ -4930,7 +5109,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_0123to1122( c, cs ); \
stbir__simdf_mult_mem( tot1, c, decode+4 ); \
stbir__simdf_0123to2333( c, cs ); \
- stbir__simdf_mult_mem( tot2, c, decode+8 );
+ stbir__simdf_mult_mem( tot2, c, decode+8 );
#define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -4940,13 +5119,13 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_0123to1122( c, cs ); \
stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*3+4 ); \
stbir__simdf_0123to2333( c, cs ); \
- stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*3+8 );
+ stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*3+8 );
#define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf_load1z( c, hc + (ofs) ); \
stbir__simdf_0123to0001( c, c ); \
- stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 );
+ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 );
#define stbir__2_coeff_remnant( ofs ) \
{ stbir__simdf d; \
@@ -4956,7 +5135,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*3 ); \
stbir__simdf_0123to1122( c, cs ); \
stbir__simdf_load2z( d, decode+(ofs)*3+4 ); \
- stbir__simdf_madd( tot1, tot1, c, d ); }
+ stbir__simdf_madd( tot1, tot1, c, d ); }
#define stbir__3_coeff_remnant( ofs ) \
{ stbir__simdf d; \
@@ -4968,7 +5147,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*3+4 ); \
stbir__simdf_0123to2222( c, cs ); \
stbir__simdf_load1z( d, decode+(ofs)*3+8 ); \
- stbir__simdf_madd( tot2, tot2, c, d ); }
+ stbir__simdf_madd( tot2, tot2, c, d ); }
#define stbir__store_output() \
stbir__simdf_0123ABCDto3ABx( c, tot0, tot1 ); \
@@ -4999,7 +5178,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
c = hc[0]; \
tot0 = decode[0]*c; \
tot1 = decode[1]*c; \
- tot2 = decode[2]*c;
+ tot2 = decode[2]*c;
#define stbir__2_coeff_only() \
float tot0, tot1, tot2, c; \
@@ -5010,7 +5189,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
c = hc[1]; \
tot0 += decode[3]*c; \
tot1 += decode[4]*c; \
- tot2 += decode[5]*c;
+ tot2 += decode[5]*c;
#define stbir__3_coeff_only() \
float tot0, tot1, tot2, c; \
@@ -5025,7 +5204,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
c = hc[2]; \
tot0 += decode[6]*c; \
tot1 += decode[7]*c; \
- tot2 += decode[8]*c;
+ tot2 += decode[8]*c;
#define stbir__store_output_tiny() \
output[0] = tot0; \
@@ -5052,7 +5231,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
c = hc[3]; \
totd0 = decode[9]*c; \
totd1 = decode[10]*c; \
- totd2 = decode[11]*c;
+ totd2 = decode[11]*c;
#define stbir__4_coeff_continue_from_4( ofs ) \
c = hc[0+(ofs)]; \
@@ -5070,7 +5249,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
c = hc[3+(ofs)]; \
totd0 += decode[9+(ofs)*3]*c; \
totd1 += decode[10+(ofs)*3]*c; \
- totd2 += decode[11+(ofs)*3]*c;
+ totd2 += decode[11+(ofs)*3]*c;
#define stbir__1_coeff_remnant( ofs ) \
c = hc[0+(ofs)]; \
@@ -5100,7 +5279,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
c = hc[2+(ofs)]; \
totc0 += decode[6+(ofs)*3]*c; \
totc1 += decode[7+(ofs)*3]*c; \
- totc2 += decode[8+(ofs)*3]*c;
+ totc2 += decode[8+(ofs)*3]*c;
#define stbir__store_output() \
output[0] = (tota0+totc0)+(totb0+totd0); \
@@ -5110,7 +5289,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
++horizontal_contributors; \
output += 3;
-#endif
+#endif
#define STBIR__horizontal_channels 3
#define STB_IMAGE_RESIZE_DO_HORIZONTALS
@@ -5126,7 +5305,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf_load1( c, hc ); \
stbir__simdf_0123to0000( c, c ); \
- stbir__simdf_mult_mem( tot, c, decode );
+ stbir__simdf_mult_mem( tot, c, decode );
#define stbir__2_coeff_only() \
stbir__simdf tot,c,cs; \
@@ -5135,7 +5314,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_0123to0000( c, cs ); \
stbir__simdf_mult_mem( tot, c, decode ); \
stbir__simdf_0123to1111( c, cs ); \
- stbir__simdf_madd_mem( tot, tot, c, decode+4 );
+ stbir__simdf_madd_mem( tot, tot, c, decode+4 );
#define stbir__3_coeff_only() \
stbir__simdf tot,c,cs; \
@@ -5146,7 +5325,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_0123to1111( c, cs ); \
stbir__simdf_madd_mem( tot, tot, c, decode+4 ); \
stbir__simdf_0123to2222( c, cs ); \
- stbir__simdf_madd_mem( tot, tot, c, decode+8 );
+ stbir__simdf_madd_mem( tot, tot, c, decode+8 );
#define stbir__store_output_tiny() \
stbir__simdf_store( output, tot ); \
@@ -5163,7 +5342,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf8_0123to00001111( c, cs ); \
stbir__simdf8_mult_mem( tot0, c, decode ); \
stbir__simdf8_0123to22223333( c, cs ); \
- stbir__simdf8_madd_mem( tot0, tot0, c, decode+8 );
+ stbir__simdf8_madd_mem( tot0, tot0, c, decode+8 );
#define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -5171,26 +5350,26 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf8_0123to00001111( c, cs ); \
stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \
stbir__simdf8_0123to22223333( c, cs ); \
- stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 );
+ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 );
#define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf_load1rep4( t, hc + (ofs) ); \
- stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4 );
+ stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4 );
#define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf8_load4b( cs, hc + (ofs) - 2 ); \
stbir__simdf8_0123to22223333( c, cs ); \
- stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 );
-
+ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 );
+
#define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf8_load4b( cs, hc + (ofs) ); \
stbir__simdf8_0123to00001111( c, cs ); \
stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \
stbir__simdf8_0123to2222( t, cs ); \
- stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4+8 );
+ stbir__simdf8_madd_mem4( tot0, tot0, t, decode+(ofs)*4+8 );
#define stbir__store_output() \
stbir__simdf8_add4halves( t, stbir__if_simdf8_cast_to_simdf4(tot0), tot0 ); \
@@ -5199,7 +5378,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
++horizontal_contributors; \
output += 4;
-#else
+#else
#define stbir__4_coeff_start() \
stbir__simdf tot0,tot1,c,cs; \
@@ -5212,7 +5391,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_0123to2222( c, cs ); \
stbir__simdf_madd_mem( tot0, tot0, c, decode+8 ); \
stbir__simdf_0123to3333( c, cs ); \
- stbir__simdf_madd_mem( tot1, tot1, c, decode+12 );
+ stbir__simdf_madd_mem( tot1, tot1, c, decode+12 );
#define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -5224,13 +5403,13 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_0123to2222( c, cs ); \
stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4+8 ); \
stbir__simdf_0123to3333( c, cs ); \
- stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+12 );
+ stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+12 );
#define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf_load1( c, hc + (ofs) ); \
stbir__simdf_0123to0000( c, c ); \
- stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 );
+ stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 );
#define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -5238,8 +5417,8 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_0123to0000( c, cs ); \
stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*4 ); \
stbir__simdf_0123to1111( c, cs ); \
- stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 );
-
+ stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*4+4 );
+
#define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf_load( cs, hc + (ofs) ); \
@@ -5365,7 +5544,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
x0 += decode[0+(ofs)*4] * c; \
x1 += decode[1+(ofs)*4] * c; \
x2 += decode[2+(ofs)*4] * c; \
- x3 += decode[3+(ofs)*4] * c;
+ x3 += decode[3+(ofs)*4] * c;
#define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -5378,8 +5557,8 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
y0 += decode[4+(ofs)*4] * c; \
y1 += decode[5+(ofs)*4] * c; \
y2 += decode[6+(ofs)*4] * c; \
- y3 += decode[7+(ofs)*4] * c;
-
+ y3 += decode[7+(ofs)*4] * c;
+
#define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
c = hc[0+(ofs)]; \
@@ -5396,7 +5575,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
x0 += decode[8+(ofs)*4] * c; \
x1 += decode[9+(ofs)*4] * c; \
x2 += decode[10+(ofs)*4] * c; \
- x3 += decode[11+(ofs)*4] * c;
+ x3 += decode[11+(ofs)*4] * c;
#define stbir__store_output() \
output[0] = x0 + y0; \
@@ -5407,7 +5586,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
++horizontal_contributors; \
output += 4;
-#endif
+#endif
#define STBIR__horizontal_channels 4
#define STB_IMAGE_RESIZE_DO_HORIZONTALS
@@ -5426,7 +5605,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_load1( c, hc ); \
stbir__simdf_0123to0000( c, c ); \
stbir__simdf_mult_mem( tot0, c, decode ); \
- stbir__simdf_mult_mem( tot1, c, decode+3 );
+ stbir__simdf_mult_mem( tot1, c, decode+3 );
#define stbir__2_coeff_only() \
stbir__simdf tot0,tot1,c,cs; \
@@ -5437,7 +5616,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_mult_mem( tot1, c, decode+3 ); \
stbir__simdf_0123to1111( c, cs ); \
stbir__simdf_madd_mem( tot0, tot0, c, decode+7 ); \
- stbir__simdf_madd_mem( tot1, tot1, c,decode+10 );
+ stbir__simdf_madd_mem( tot1, tot1, c,decode+10 );
#define stbir__3_coeff_only() \
stbir__simdf tot0,tot1,c,cs; \
@@ -5451,7 +5630,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_madd_mem( tot1, tot1, c, decode+10 ); \
stbir__simdf_0123to2222( c, cs ); \
stbir__simdf_madd_mem( tot0, tot0, c, decode+14 ); \
- stbir__simdf_madd_mem( tot1, tot1, c, decode+17 );
+ stbir__simdf_madd_mem( tot1, tot1, c, decode+17 );
#define stbir__store_output_tiny() \
stbir__simdf_store( output+3, tot1 ); \
@@ -5473,7 +5652,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf8_0123to22222222( c, cs ); \
stbir__simdf8_madd_mem( tot0, tot0, c, decode+14 ); \
stbir__simdf8_0123to33333333( c, cs ); \
- stbir__simdf8_madd_mem( tot1, tot1, c, decode+21 );
+ stbir__simdf8_madd_mem( tot1, tot1, c, decode+21 );
#define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -5485,19 +5664,19 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf8_0123to22222222( c, cs ); \
stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); \
stbir__simdf8_0123to33333333( c, cs ); \
- stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+21 );
+ stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+21 );
#define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf8_load1b( c, hc + (ofs) ); \
- stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 );
+ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 );
#define stbir__2_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf8_load1b( c, hc + (ofs) ); \
stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7 ); \
stbir__simdf8_load1b( c, hc + (ofs)+1 ); \
- stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 );
+ stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 );
#define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -5507,7 +5686,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf8_0123to11111111( c, cs ); \
stbir__simdf8_madd_mem( tot1, tot1, c, decode+(ofs)*7+7 ); \
stbir__simdf8_0123to22222222( c, cs ); \
- stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 );
+ stbir__simdf8_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 );
#define stbir__store_output() \
stbir__simdf8_add( tot0, tot0, tot1 ); \
@@ -5540,7 +5719,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_madd_mem( tot1, tot1, c, decode+17 ); \
stbir__simdf_0123to3333( c, cs ); \
stbir__simdf_madd_mem( tot2, tot2, c, decode+21 ); \
- stbir__simdf_madd_mem( tot3, tot3, c, decode+24 );
+ stbir__simdf_madd_mem( tot3, tot3, c, decode+24 );
#define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -5556,7 +5735,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 ); \
stbir__simdf_0123to3333( c, cs ); \
stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+21 ); \
- stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+24 );
+ stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+24 );
#define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -5573,8 +5752,8 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+3 ); \
stbir__simdf_0123to1111( c, cs ); \
stbir__simdf_madd_mem( tot2, tot2, c, decode+(ofs)*7+7 ); \
- stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 );
-
+ stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 );
+
#define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
stbir__simdf_load( cs, hc + (ofs) ); \
@@ -5586,7 +5765,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
stbir__simdf_madd_mem( tot3, tot3, c, decode+(ofs)*7+10 ); \
stbir__simdf_0123to2222( c, cs ); \
stbir__simdf_madd_mem( tot0, tot0, c, decode+(ofs)*7+14 ); \
- stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 );
+ stbir__simdf_madd_mem( tot1, tot1, c, decode+(ofs)*7+17 );
#define stbir__store_output() \
stbir__simdf_add( tot0, tot0, tot2 ); \
@@ -5610,7 +5789,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
tot3 = decode[3]*c; \
tot4 = decode[4]*c; \
tot5 = decode[5]*c; \
- tot6 = decode[6]*c;
+ tot6 = decode[6]*c;
#define stbir__2_coeff_only() \
float tot0, tot1, tot2, tot3, tot4, tot5, tot6, c; \
@@ -5704,7 +5883,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
y3 += decode[24] * c; \
y4 += decode[25] * c; \
y5 += decode[26] * c; \
- y6 += decode[27] * c;
+ y6 += decode[27] * c;
#define stbir__4_coeff_continue_from_4( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -5739,7 +5918,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
y3 += decode[24+(ofs)*7] * c; \
y4 += decode[25+(ofs)*7] * c; \
y5 += decode[26+(ofs)*7] * c; \
- y6 += decode[27+(ofs)*7] * c;
+ y6 += decode[27+(ofs)*7] * c;
#define stbir__1_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
@@ -5770,7 +5949,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
y4 += decode[11+(ofs)*7] * c; \
y5 += decode[12+(ofs)*7] * c; \
y6 += decode[13+(ofs)*7] * c; \
-
+
#define stbir__3_coeff_remnant( ofs ) \
STBIR_SIMD_NO_UNROLL(decode); \
c = hc[0+(ofs)]; \
@@ -5810,7 +5989,7 @@ static void stbir__decode_scanline(stbir__info const * stbir_info, int n, float
++horizontal_contributors; \
output += 7;
-#endif
+#endif
#define STBIR__horizontal_channels 7
#define STB_IMAGE_RESIZE_DO_HORIZONTALS
@@ -5937,7 +6116,7 @@ static void stbir__encode_scanline( stbir__info const * stbir_info, void *output
// if we have an output callback, we first convert the decode buffer in place (and then hand that to the callback)
if ( stbir_info->out_pixels_cb )
output_buffer = encode_buffer;
-
+
STBIR_PROFILE_START( encode );
// convert into the output buffer
stbir_info->encode_pixels( output_buffer, width_times_channels, encode_buffer );
@@ -5945,7 +6124,7 @@ static void stbir__encode_scanline( stbir__info const * stbir_info, void *output
// if we have an output callback, call it to send the data
if ( stbir_info->out_pixels_cb )
- stbir_info->out_pixels_cb( output_buffer_data, num_pixels, row, stbir_info->user_data );
+ stbir_info->out_pixels_cb( output_buffer, num_pixels, row, stbir_info->user_data );
}
@@ -6015,7 +6194,7 @@ static void stbir__resample_vertical_gather(stbir__info const * stbir_info, stbi
stbir__resample_horizontal_gather(stbir_info, encode_buffer, decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
}
- stbir__encode_scanline( stbir_info, ( (char *) stbir_info->output_data ) + ((ptrdiff_t)n * (ptrdiff_t)stbir_info->output_stride_bytes),
+ stbir__encode_scanline( stbir_info, ( (char *) stbir_info->output_data ) + ((size_t)n * (size_t)stbir_info->output_stride_bytes),
encode_buffer, n STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
}
@@ -6030,7 +6209,7 @@ static void stbir__decode_and_resample_for_vertical_gather_loop(stbir__info cons
// update new end scanline
split_info->ring_buffer_last_scanline = n;
- // get ring buffer
+ // get ring buffer
ring_buffer_index = (split_info->ring_buffer_begin_index + (split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
ring_buffer = stbir__get_ring_buffer_entry(stbir_info, split_info, ring_buffer_index);
@@ -6056,7 +6235,7 @@ static void stbir__vertical_gather_loop( stbir__info const * stbir_info, stbir__
// initialize the ring buffer for gathering
split_info->ring_buffer_begin_index = 0;
- split_info->ring_buffer_first_scanline = stbir_info->vertical.extent_info.lowest;
+ split_info->ring_buffer_first_scanline = vertical_contributors->n0;
split_info->ring_buffer_last_scanline = split_info->ring_buffer_first_scanline - 1; // means "empty"
for (y = start_output_y; y < end_output_y; y++)
@@ -6080,12 +6259,12 @@ static void stbir__vertical_gather_loop( stbir__info const * stbir_info, stbir__
split_info->ring_buffer_first_scanline++;
split_info->ring_buffer_begin_index++;
}
-
+
if ( stbir_info->vertical_first )
{
float * ring_buffer = stbir__get_ring_buffer_scanline( stbir_info, split_info, ++split_info->ring_buffer_last_scanline );
// Decode the nth scanline from the source image into the decode buffer.
- stbir__decode_scanline( stbir_info, split_info->ring_buffer_last_scanline, ring_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+ stbir__decode_scanline( stbir_info, split_info->ring_buffer_last_scanline, ring_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
}
else
{
@@ -6108,10 +6287,10 @@ static void stbir__encode_first_scanline_from_scatter(stbir__info const * stbir_
{
// evict a scanline out into the output buffer
float* ring_buffer_entry = stbir__get_ring_buffer_entry(stbir_info, split_info, split_info->ring_buffer_begin_index );
-
+
// dump the scanline out
- stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (ptrdiff_t)split_info->ring_buffer_first_scanline * (ptrdiff_t)stbir_info->output_stride_bytes ), ring_buffer_entry, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
-
+ stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (size_t)split_info->ring_buffer_first_scanline * (size_t)stbir_info->output_stride_bytes ), ring_buffer_entry, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+
// mark it as empty
ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER;
@@ -6129,10 +6308,10 @@ static void stbir__horizontal_resample_and_encode_first_scanline_from_scatter(st
// Now resample it into the buffer.
stbir__resample_horizontal_gather( stbir_info, split_info->vertical_buffer, ring_buffer_entry STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
-
+
// dump the scanline out
- stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (ptrdiff_t)split_info->ring_buffer_first_scanline * (ptrdiff_t)stbir_info->output_stride_bytes ), split_info->vertical_buffer, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
-
+ stbir__encode_scanline( stbir_info, ( (char *)stbir_info->output_data ) + ( (size_t)split_info->ring_buffer_first_scanline * (size_t)stbir_info->output_stride_bytes ), split_info->vertical_buffer, split_info->ring_buffer_first_scanline STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+
// mark it as empty
ring_buffer_entry[ 0 ] = STBIR__FLOAT_EMPTY_MARKER;
@@ -6172,7 +6351,7 @@ static void stbir__resample_vertical_scatter(stbir__info const * stbir_info, stb
STBIR_PROFILE_END( vertical );
}
-typedef void stbir__handle_scanline_for_scatter_func(stbir__info const * stbir_info, stbir__per_split_info* split_info);
+typedef void stbir__handle_scanline_for_scatter_func(stbir__info const * stbir_info, stbir__per_split_info* split_info);
static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir__per_split_info* split_info, int split_count )
{
@@ -6193,7 +6372,7 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_
end_input_y = split_info[split_count-1].end_input_y;
// adjust for starting offset start_input_y
- y = start_input_y + stbir_info->vertical.filter_pixel_margin;
+ y = start_input_y + stbir_info->vertical.filter_pixel_margin;
vertical_contributors += y ;
vertical_coefficients += stbir_info->vertical.coefficient_width * y;
@@ -6240,7 +6419,7 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_
split_info->start_input_y = y;
on_first_input_y = 0;
- // clip the region
+ // clip the region
if ( out_first_scanline < start_output_y )
{
vc += start_output_y - out_first_scanline;
@@ -6253,11 +6432,11 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_
// if very first scanline, init the index
if (split_info->ring_buffer_begin_index < 0)
split_info->ring_buffer_begin_index = out_first_scanline - start_output_y;
-
+
STBIR_ASSERT( split_info->ring_buffer_begin_index <= out_first_scanline );
// Decode the nth scanline from the source image into the decode buffer.
- stbir__decode_scanline( stbir_info, y, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
+ stbir__decode_scanline( stbir_info, y, split_info->decode_buffer STBIR_ONLY_PROFILE_SET_SPLIT_INFO );
// When horizontal first, we resample horizontally into the vertical buffer before we scatter it out
if ( !stbir_info->vertical_first )
@@ -6269,7 +6448,7 @@ static void stbir__vertical_scatter_loop( stbir__info const * stbir_info, stbir_
if ( ( ( split_info->ring_buffer_last_scanline - split_info->ring_buffer_first_scanline + 1 ) == stbir_info->ring_buffer_num_entries ) &&
( out_last_scanline > split_info->ring_buffer_last_scanline ) )
handle_scanline_for_scatter( stbir_info, split_info );
-
+
// Now the horizontal buffer is ready to write to all ring buffer rows, so do it.
stbir__resample_vertical_scatter(stbir_info, split_info, out_first_scanline, out_last_scanline, vc, (float*)scanline_scatter_buffer, (float*)scanline_scatter_buffer_end );
@@ -6305,7 +6484,7 @@ static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir
if (scale_info->scale >= ( 1.0f - stbir__small_float ) )
{
if ( (scale_info->scale <= ( 1.0f + stbir__small_float ) ) && ( STBIR_CEILF(scale_info->pixel_shift) == scale_info->pixel_shift ) )
- filter = STBIR_FILTER_POINT_SAMPLE;
+ filter = STBIR_FILTER_POINT_SAMPLE;
else
filter = STBIR_DEFAULT_FILTER_UPSAMPLE;
}
@@ -6313,7 +6492,7 @@ static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir
samp->filter_enum = filter;
STBIR_ASSERT(samp->filter_enum != 0);
- STBIR_ASSERT((unsigned)samp->filter_enum < STBIR_FILTER_OTHER);
+ STBIR_ASSERT((unsigned)samp->filter_enum < STBIR_FILTER_OTHER);
samp->filter_kernel = stbir__builtin_kernels[ filter ];
samp->filter_support = stbir__builtin_supports[ filter ];
@@ -6339,15 +6518,31 @@ static void stbir__set_sampler(stbir__sampler * samp, stbir_filter filter, stbir
// pre calculate stuff based on the above
samp->coefficient_width = stbir__get_coefficient_width(samp, samp->is_gather, user_data);
+ // filter_pixel_width is the conservative size in pixels of input that affect an output pixel.
+ // In rare cases (only with 2 pix to 1 pix with the default filters), it's possible that the
+ // filter will extend before or after the scanline beyond just one extra entire copy of the
+ // scanline (we would hit the edge twice). We don't let you do that, so we clamp the total
+ // width to 3x the total of input pixel (once for the scanline, once for the left side
+ // overhang, and once for the right side). We only do this for edge mode, since the other
+ // modes can just re-edge clamp back in again.
if ( edge == STBIR_EDGE_WRAP )
- if ( samp->filter_pixel_width > ( scale_info->input_full_size * 2 ) ) // this can only happen when shrinking to a single pixel
- samp->filter_pixel_width = scale_info->input_full_size * 2;
+ if ( samp->filter_pixel_width > ( scale_info->input_full_size * 3 ) )
+ samp->filter_pixel_width = scale_info->input_full_size * 3;
// This is how much to expand buffers to account for filters seeking outside
// the image boundaries.
samp->filter_pixel_margin = samp->filter_pixel_width / 2;
+
+ // filter_pixel_margin is the amount that this filter can overhang on just one side of either
+ // end of the scanline (left or the right). Since we only allow you to overhang 1 scanline's
+ // worth of pixels, we clamp this one side of overhang to the input scanline size. Again,
+ // this clamping only happens in rare cases with the default filters (2 pix to 1 pix).
+ if ( edge == STBIR_EDGE_WRAP )
+ if ( samp->filter_pixel_margin > scale_info->input_full_size )
+ samp->filter_pixel_margin = scale_info->input_full_size;
samp->num_contributors = stbir__get_contributors(samp, samp->is_gather);
+
samp->contributors_size = samp->num_contributors * sizeof(stbir__contributors);
samp->coefficients_size = samp->num_contributors * samp->coefficient_width * sizeof(float) + sizeof(float); // extra sizeof(float) is padding
@@ -6397,8 +6592,8 @@ static void stbir__get_conservative_extents( stbir__sampler * samp, stbir__contr
range->n0 = in_first_pixel;
stbir__calculate_in_pixel_range( &in_first_pixel, &in_last_pixel, (float)output_sub_size, 0, inv_scale, out_shift, input_full_size, edge );
range->n1 = in_last_pixel;
-
- // now go through the margin to the start of area to find bottom
+
+ // now go through the margin to the start of area to find bottom
n = range->n0 + 1;
input_end = -filter_pixel_margin;
while( n >= input_end )
@@ -6413,7 +6608,7 @@ static void stbir__get_conservative_extents( stbir__sampler * samp, stbir__contr
--n;
}
- // now go through the end of the area through the margin to find top
+ // now go through the end of the area through the margin to find top
n = range->n1 - 1;
input_end = n + 1 + filter_pixel_margin;
while( n <= input_end )
@@ -6462,7 +6657,7 @@ static void stbir__get_split_info( stbir__per_split_info* split_info, int splits
cur = 0;
for( i = 0 ; i < splits ; i++ )
{
- int each;
+ int each;
split_info[i].start_output_y = cur;
each = left / ( splits - i );
split_info[i].end_output_y = cur + each;
@@ -6478,7 +6673,7 @@ static void stbir__get_split_info( stbir__per_split_info* split_info, int splits
static void stbir__free_internal_mem( stbir__info *info )
{
#define STBIR__FREE_AND_CLEAR( ptr ) { if ( ptr ) { void * p = (ptr); (ptr) = 0; STBIR_FREE( p, info->user_data); } }
-
+
if ( info )
{
#ifndef STBIR__SEPARATE_ALLOCATIONS
@@ -6496,16 +6691,16 @@ static void stbir__free_internal_mem( stbir__info *info )
for( j = 0 ; j < info->alloc_ring_buffer_num_entries ; j++ )
{
#ifdef STBIR_SIMD8
- if ( info->effective_channels == 3 )
+ if ( info->effective_channels == 3 )
--info->split_info[i].ring_buffers[j]; // avx in 3 channel mode needs one float at the start of the buffer
- #endif
+ #endif
STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers[j] );
}
#ifdef STBIR_SIMD8
- if ( info->effective_channels == 3 )
+ if ( info->effective_channels == 3 )
--info->split_info[i].decode_buffer; // avx in 3 channel mode needs one float at the start of the buffer
- #endif
+ #endif
STBIR__FREE_AND_CLEAR( info->split_info[i].decode_buffer );
STBIR__FREE_AND_CLEAR( info->split_info[i].ring_buffers );
STBIR__FREE_AND_CLEAR( info->split_info[i].vertical_buffer );
@@ -6522,7 +6717,7 @@ static void stbir__free_internal_mem( stbir__info *info )
STBIR__FREE_AND_CLEAR( info );
#endif
}
-
+
#undef STBIR__FREE_AND_CLEAR
}
@@ -6534,20 +6729,20 @@ static int stbir__get_max_split( int splits, int height )
for( i = 0 ; i < splits ; i++ )
{
int each = height / ( splits - i );
- if ( each > max )
+ if ( each > max )
max = each;
height -= each;
}
return max;
}
-static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_n_coeffs_funcs[8] =
-{
+static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_n_coeffs_funcs[8] =
+{
0, stbir__horizontal_gather_1_channels_with_n_coeffs_funcs, stbir__horizontal_gather_2_channels_with_n_coeffs_funcs, stbir__horizontal_gather_3_channels_with_n_coeffs_funcs, stbir__horizontal_gather_4_channels_with_n_coeffs_funcs, 0,0, stbir__horizontal_gather_7_channels_with_n_coeffs_funcs
};
-static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_channels_funcs[8] =
-{
+static stbir__horizontal_gather_channels_func ** stbir__horizontal_gather_channels_funcs[8] =
+{
0, stbir__horizontal_gather_1_channels_funcs, stbir__horizontal_gather_2_channels_funcs, stbir__horizontal_gather_3_channels_funcs, stbir__horizontal_gather_4_channels_funcs, 0,0, stbir__horizontal_gather_7_channels_funcs
};
@@ -6622,28 +6817,28 @@ static STBIR__V_FIRST_INFO STBIR__V_FIRST_INFO_BUFFER = {0};
#endif
// Figure out whether to scale along the horizontal or vertical first.
-// This only *super* important when you are scaling by a massively
-// different amount in the vertical vs the horizontal (for example, if
-// you are scaling by 2x in the width, and 0.5x in the height, then you
-// want to do the vertical scale first, because it's around 3x faster
+// This only *super* important when you are scaling by a massively
+// different amount in the vertical vs the horizontal (for example, if
+// you are scaling by 2x in the width, and 0.5x in the height, then you
+// want to do the vertical scale first, because it's around 3x faster
// in that order.
//
-// In more normal circumstances, this makes a 20-40% differences, so
+// In more normal circumstances, this makes a 20-40% differences, so
// it's good to get right, but not critical. The normal way that you
-// decide which direction goes first is just figuring out which
-// direction does more multiplies. But with modern CPUs with their
+// decide which direction goes first is just figuring out which
+// direction does more multiplies. But with modern CPUs with their
// fancy caches and SIMD and high IPC abilities, so there's just a lot
-// more that goes into it.
+// more that goes into it.
//
-// My handwavy sort of solution is to have an app that does a whole
+// My handwavy sort of solution is to have an app that does a whole
// bunch of timing for both vertical and horizontal first modes,
// and then another app that can read lots of these timing files
// and try to search for the best weights to use. Dotimings.c
// is the app that does a bunch of timings, and vf_train.c is the
-// app that solves for the best weights (and shows how well it
+// app that solves for the best weights (and shows how well it
// does currently).
-static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int horizontal_filter_pixel_width, float horizontal_scale, int horizontal_output_size, int vertical_filter_pixel_width, float vertical_scale, int vertical_output_size, int is_gather, STBIR__V_FIRST_INFO * info )
+static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int horizontal_filter_pixel_width, float horizontal_scale, int horizontal_output_size, int vertical_filter_pixel_width, float vertical_scale, int vertical_output_size, int is_gather, STBIR__V_FIRST_INFO * info )
{
double v_cost, h_cost;
float * weights;
@@ -6655,15 +6850,15 @@ static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLA
v_classification = ( vertical_output_size < horizontal_output_size ) ? 6 : 7;
else if ( vertical_scale <= 1.0f )
v_classification = ( is_gather ) ? 1 : 0;
- else if ( vertical_scale <= 2.0f)
+ else if ( vertical_scale <= 2.0f)
v_classification = 2;
- else if ( vertical_scale <= 3.0f)
+ else if ( vertical_scale <= 3.0f)
v_classification = 3;
- else if ( vertical_scale <= 4.0f)
+ else if ( vertical_scale <= 4.0f)
v_classification = 5;
- else
+ else
v_classification = 6;
-
+
// use the right weights
weights = weights_table[ v_classification ];
@@ -6684,10 +6879,10 @@ static int stbir__should_do_vertical_first( float weights_table[STBIR_RESIZE_CLA
info->is_gather = is_gather;
}
- // and this allows us to override everything for testing (see dotiming.c)
- if ( ( info ) && ( info->control_v_first ) )
+ // and this allows us to override everything for testing (see dotiming.c)
+ if ( ( info ) && ( info->control_v_first ) )
vertical_first = ( info->control_v_first == 2 ) ? 1 : 0;
-
+
return vertical_first;
}
@@ -6699,9 +6894,9 @@ static unsigned char stbir__pixel_channels[] = {
};
// the internal pixel layout enums are in a different order, so we can easily do range comparisons of types
-// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible
+// the public pixel layout is ordered in a way that if you cast num_channels (1-4) to the enum, you get something sensible
static stbir_internal_pixel_layout stbir__pixel_layout_convert_public_to_internal[] = {
- STBIRI_BGR, STBIRI_1CHANNEL, STBIRI_2CHANNEL, STBIRI_RGB, STBIRI_RGBA,
+ STBIRI_BGR, STBIRI_1CHANNEL, STBIRI_2CHANNEL, STBIRI_RGB, STBIRI_RGBA,
STBIRI_4CHANNEL, STBIRI_BGRA, STBIRI_ARGB, STBIRI_ABGR, STBIRI_RA, STBIRI_AR,
STBIRI_RGBA_PM, STBIRI_BGRA_PM, STBIRI_ARGB_PM, STBIRI_ABGR_PM, STBIRI_RA_PM, STBIRI_AR_PM,
};
@@ -6712,17 +6907,17 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
stbir__info * info = 0;
void * alloced = 0;
- int alloced_total = 0;
+ size_t alloced_total = 0;
int vertical_first;
int decode_buffer_size, ring_buffer_length_bytes, ring_buffer_size, vertical_buffer_size, alloc_ring_buffer_num_entries;
int alpha_weighting_type = 0; // 0=none, 1=simple, 2=fancy
- int conservative_split_output_size = stbir__get_max_split( splits, vertical->scale_info.output_sub_size );
- stbir_internal_pixel_layout input_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ input_pixel_layout_public ];
+ int conservative_split_output_size = stbir__get_max_split( splits, vertical->scale_info.output_sub_size );
+ stbir_internal_pixel_layout input_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ input_pixel_layout_public ];
stbir_internal_pixel_layout output_pixel_layout = stbir__pixel_layout_convert_public_to_internal[ output_pixel_layout_public ];
- int channels = stbir__pixel_channels[ input_pixel_layout ];
+ int channels = stbir__pixel_channels[ input_pixel_layout ];
int effective_channels = channels;
-
+
// first figure out what type of alpha weighting to use (if any)
if ( ( horizontal->filter_enum != STBIR_FILTER_POINT_SAMPLE ) || ( vertical->filter_enum != STBIR_FILTER_POINT_SAMPLE ) ) // no alpha weighting on point sampling
{
@@ -6760,11 +6955,11 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
// sometimes read one float off in some of the unrolled loops (with a weight of zero coeff, so it doesn't have an effect)
decode_buffer_size = ( conservative->n1 - conservative->n0 + 1 ) * effective_channels * sizeof(float) + sizeof(float); // extra float for padding
-
+
#if defined( STBIR__SEPARATE_ALLOCATIONS ) && defined(STBIR_SIMD8)
if ( effective_channels == 3 )
decode_buffer_size += sizeof(float); // avx in 3 channel mode needs one float at the start of the buffer (only with separate allocations)
-#endif
+#endif
ring_buffer_length_bytes = horizontal->scale_info.output_sub_size * effective_channels * sizeof(float) + sizeof(float); // extra float for padding
@@ -6803,9 +6998,9 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
#define STBIR__NEXT_PTR( ptr, size, ntype ) advance_mem = (void*) ( ( ((size_t)advance_mem) + 15 ) & ~15 ); if ( alloced ) ptr = (ntype*)advance_mem; advance_mem = ((char*)advance_mem) + (size);
#endif
- STBIR__NEXT_PTR( info, sizeof( stbir__info ), stbir__info );
+ STBIR__NEXT_PTR( info, sizeof( stbir__info ), stbir__info );
- STBIR__NEXT_PTR( info->split_info, sizeof( stbir__per_split_info ) * splits, stbir__per_split_info );
+ STBIR__NEXT_PTR( info->split_info, sizeof( stbir__per_split_info ) * splits, stbir__per_split_info );
if ( info )
{
@@ -6820,39 +7015,39 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
info->channels = channels;
info->effective_channels = effective_channels;
-
+
info->offset_x = new_x;
info->offset_y = new_y;
info->alloc_ring_buffer_num_entries = alloc_ring_buffer_num_entries;
- info->ring_buffer_num_entries = 0;
+ info->ring_buffer_num_entries = 0;
info->ring_buffer_length_bytes = ring_buffer_length_bytes;
info->splits = splits;
info->vertical_first = vertical_first;
- info->input_pixel_layout_internal = input_pixel_layout;
+ info->input_pixel_layout_internal = input_pixel_layout;
info->output_pixel_layout_internal = output_pixel_layout;
// setup alpha weight functions
info->alpha_weight = 0;
info->alpha_unweight = 0;
-
+
// handle alpha weighting functions and overrides
if ( alpha_weighting_type == 2 )
{
// high quality alpha multiplying on the way in, dividing on the way out
- info->alpha_weight = fancy_alpha_weights[ input_pixel_layout - STBIRI_RGBA ];
+ info->alpha_weight = fancy_alpha_weights[ input_pixel_layout - STBIRI_RGBA ];
info->alpha_unweight = fancy_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ];
}
else if ( alpha_weighting_type == 4 )
{
// fast alpha multiplying on the way in, dividing on the way out
- info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ];
+ info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ];
info->alpha_unweight = simple_alpha_unweights[ output_pixel_layout - STBIRI_RGBA ];
}
else if ( alpha_weighting_type == 1 )
{
// fast alpha on the way in, leave in premultiplied form on way out
- info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ];
+ info->alpha_weight = simple_alpha_weights[ input_pixel_layout - STBIRI_RGBA ];
}
else if ( alpha_weighting_type == 3 )
{
@@ -6871,7 +7066,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
info->alpha_weight = stbir__simple_flip_3ch;
}
- }
+ }
// get all the per-split buffers
for( i = 0 ; i < splits ; i++ )
@@ -6883,7 +7078,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
#ifdef STBIR_SIMD8
if ( ( info ) && ( effective_channels == 3 ) )
++info->split_info[i].decode_buffer; // avx in 3 channel mode needs one float at the start of the buffer
- #endif
+ #endif
STBIR__NEXT_PTR( info->split_info[i].ring_buffers, alloc_ring_buffer_num_entries * sizeof(float*), float* );
{
@@ -6894,7 +7089,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
#ifdef STBIR_SIMD8
if ( ( info ) && ( effective_channels == 3 ) )
++info->split_info[i].ring_buffers[j]; // avx in 3 channel mode needs one float at the start of the buffer
- #endif
+ #endif
}
}
#else
@@ -6922,10 +7117,10 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
#endif
if ( temp_mem_amt >= both )
{
- if ( info )
- {
- vertical->gather_prescatter_contributors = (stbir__contributors*)info->split_info[0].decode_buffer;
- vertical->gather_prescatter_coefficients = (float*) ( ( (char*)info->split_info[0].decode_buffer ) + vertical->gather_prescatter_contributors_size );
+ if ( info )
+ {
+ vertical->gather_prescatter_contributors = (stbir__contributors*)info->split_info[0].decode_buffer;
+ vertical->gather_prescatter_coefficients = (float*) ( ( (char*)info->split_info[0].decode_buffer ) + vertical->gather_prescatter_contributors_size );
}
}
else
@@ -6948,7 +7143,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
if ( diff_shift < 0.0f ) diff_shift = -diff_shift;
if ( ( diff_scale <= stbir__small_float ) && ( diff_shift <= stbir__small_float ) )
{
- if ( horizontal->is_gather == vertical->is_gather )
+ if ( horizontal->is_gather == vertical->is_gather )
{
copy_horizontal = 1;
goto no_vert_alloc;
@@ -6975,16 +7170,16 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
// but if the number of coeffs <= 12, use another set of special cases. <=12 coeffs is any enlarging resize, or shrinking resize down to about 1/3 size
if ( horizontal->extent_info.widest <= 12 )
info->horizontal_gather_channels = stbir__horizontal_gather_channels_funcs[ effective_channels ][ horizontal->extent_info.widest - 1 ];
-
+
info->scanline_extents.conservative.n0 = conservative->n0;
info->scanline_extents.conservative.n1 = conservative->n1;
-
+
// get exact extents
stbir__get_extents( horizontal, &info->scanline_extents );
// pack the horizontal coeffs
- horizontal->coefficient_width = stbir__pack_coefficients(horizontal->num_contributors, horizontal->contributors, horizontal->coefficients, horizontal->coefficient_width, horizontal->extent_info.widest, info->scanline_extents.conservative.n1 + 1 );
-
+ horizontal->coefficient_width = stbir__pack_coefficients(horizontal->num_contributors, horizontal->contributors, horizontal->coefficients, horizontal->coefficient_width, horizontal->extent_info.widest, info->scanline_extents.conservative.n0, info->scanline_extents.conservative.n1 );
+
STBIR_MEMCPY( &info->horizontal, horizontal, sizeof( stbir__sampler ) );
STBIR_PROFILE_BUILD_END( horizontal );
@@ -7014,36 +7209,27 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
info->ring_buffer_num_entries = conservative_split_output_size;
STBIR_ASSERT( info->ring_buffer_num_entries <= info->alloc_ring_buffer_num_entries );
- // a few of the horizontal gather functions read one dword past the end (but mask it out), so put in a normal value so no snans or denormals accidentally sneak in
+ // a few of the horizontal gather functions read past the end of the decode (but mask it out),
+ // so put in normal values so no snans or denormals accidentally sneak in (also, in the ring
+ // buffer for vertical first)
for( i = 0 ; i < splits ; i++ )
{
- int width, ofs;
-
- // find the right most span
- if ( info->scanline_extents.spans[0].n1 > info->scanline_extents.spans[1].n1 )
- width = info->scanline_extents.spans[0].n1 - info->scanline_extents.spans[0].n0;
- else
- width = info->scanline_extents.spans[1].n1 - info->scanline_extents.spans[1].n0;
-
- // this calc finds the exact end of the decoded scanline for all filter modes.
- // usually this is just the width * effective channels. But we have to account
- // for the area to the left of the scanline for wrap filtering and alignment, this
- // is stored as a negative value in info->scanline_extents.conservative.n0. Next,
- // we need to skip the exact size of the right hand size filter area (again for
- // wrap mode), this is in info->scanline_extents.edge_sizes[1]).
- ofs = ( width + 1 - info->scanline_extents.conservative.n0 + info->scanline_extents.edge_sizes[1] ) * effective_channels;
-
- // place a known, but numerically valid value in the decode buffer
- info->split_info[i].decode_buffer[ ofs ] = 9999.0f;
+ int t, ofs, start;
+
+ ofs = decode_buffer_size / 4;
+ start = ofs - 4;
+ if ( start < 0 ) start = 0;
+
+ for( t = start ; t < ofs; t++ )
+ info->split_info[i].decode_buffer[ t ] = 9999.0f;
- // if vertical filtering first, place a known, but numerically valid value in the all
- // of the ring buffer accumulators
if ( vertical_first )
{
- int j;
+ int j;
for( j = 0; j < info->ring_buffer_num_entries ; j++ )
{
- stbir__get_ring_buffer_entry( info, info->split_info + i, j )[ ofs ] = 9999.0f;
+ for( t = start ; t < ofs; t++ )
+ stbir__get_ring_buffer_entry( info, info->split_info + i, j )[ t ] = 9999.0f;
}
}
}
@@ -7055,7 +7241,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
// is this the first time through loop?
if ( info == 0 )
{
- alloced_total = (int) ( 15 + (size_t)advance_mem );
+ alloced_total = ( 15 + (size_t)advance_mem );
alloced = STBIR_MALLOC( alloced_total, user_data );
if ( alloced == 0 )
return 0;
@@ -7065,7 +7251,7 @@ static stbir__info * stbir__alloc_internal_mem_and_build_samplers( stbir__sample
}
}
-static int stbir__perform_resize( stbir__info const * info, int split_start, int split_count )
+static int stbir__perform_resize( stbir__info const * info, int split_start, int split_count )
{
stbir__per_split_info * split_info = info->split_info + split_start;
@@ -7085,7 +7271,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r
{
static stbir__decode_pixels_func * decode_simple[STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=
{
- /* 1ch-4ch */ stbir__decode_uint8_srgb, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear,
+ /* 1ch-4ch */ stbir__decode_uint8_srgb, stbir__decode_uint8_srgb, 0, stbir__decode_float_linear, stbir__decode_half_float_linear,
};
static stbir__decode_pixels_func * decode_alphas[STBIRI_AR-STBIRI_RGBA+1][STBIR_TYPE_HALF_FLOAT-STBIR_TYPE_UINT8_SRGB+1]=
@@ -7148,7 +7334,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r
stbir_datatype input_type, output_type;
input_type = resize->input_data_type;
- output_type = resize->output_data_type;
+ output_type = resize->output_data_type;
info->input_data = resize->input_pixels;
info->input_stride_bytes = resize->input_stride_in_bytes;
info->output_stride_bytes = resize->output_stride_in_bytes;
@@ -7156,7 +7342,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r
// if we're completely point sampling, then we can turn off SRGB
if ( ( info->horizontal.filter_enum == STBIR_FILTER_POINT_SAMPLE ) && ( info->vertical.filter_enum == STBIR_FILTER_POINT_SAMPLE ) )
{
- if ( ( ( input_type == STBIR_TYPE_UINT8_SRGB ) || ( input_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) &&
+ if ( ( ( input_type == STBIR_TYPE_UINT8_SRGB ) || ( input_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) &&
( ( output_type == STBIR_TYPE_UINT8_SRGB ) || ( output_type == STBIR_TYPE_UINT8_SRGB_ALPHA ) ) )
{
input_type = STBIR_TYPE_UINT8;
@@ -7164,7 +7350,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r
}
}
- // recalc the output and input strides
+ // recalc the output and input strides
if ( info->input_stride_bytes == 0 )
info->input_stride_bytes = info->channels * info->horizontal.scale_info.input_full_size * stbir__type_size[input_type];
@@ -7172,7 +7358,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r
info->output_stride_bytes = info->channels * info->horizontal.scale_info.output_sub_size * stbir__type_size[output_type];
// calc offset
- info->output_data = ( (char*) resize->output_pixels ) + ( (ptrdiff_t) info->offset_y * (ptrdiff_t) resize->output_stride_in_bytes ) + ( info->offset_x * info->channels * stbir__type_size[output_type] );
+ info->output_data = ( (char*) resize->output_pixels ) + ( (size_t) info->offset_y * (size_t) resize->output_stride_in_bytes ) + ( info->offset_x * info->channels * stbir__type_size[output_type] );
info->in_pixels_cb = resize->input_cb;
info->user_data = resize->user_data;
@@ -7205,7 +7391,7 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r
if ( ( output_type == STBIR_TYPE_UINT8 ) || ( output_type == STBIR_TYPE_UINT16 ) )
{
int non_scaled = 0;
-
+
// check if we can run unscaled - 0-255.0/0-65535.0 instead of 0-1.0 (which is a tiny bit faster when doing linear 8->8 or 16->16)
if ( ( !info->alpha_weight ) && ( !info->alpha_unweight ) ) // don't short circuit when alpha weighting (get everything to 0-1.0 as usual)
if ( ( ( input_type == STBIR_TYPE_UINT8 ) && ( output_type == STBIR_TYPE_UINT8 ) ) || ( ( input_type == STBIR_TYPE_UINT16 ) && ( output_type == STBIR_TYPE_UINT16 ) ) )
@@ -7225,16 +7411,16 @@ static void stbir__update_info_from_resize( stbir__info * info, STBIR_RESIZE * r
}
info->input_type = input_type;
- info->output_type = output_type;
+ info->output_type = output_type;
info->decode_pixels = decode_pixels;
- info->encode_pixels = encode_pixels;
+ info->encode_pixels = encode_pixels;
}
static void stbir__clip( int * outx, int * outsubw, int outw, double * u0, double * u1 )
{
double per, adj;
int over;
-
+
// do left/top edge
if ( *outx < 0 )
{
@@ -7253,7 +7439,7 @@ static void stbir__clip( int * outx, int * outsubw, int outw, double * u0, doubl
*u1 += adj; // decrease u1
*outsubw = outw - *outx;
}
-}
+}
// converts a double to a rational that has less than one float bit of error (returns 0 if unable to do so)
static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32 *numer, stbir_uint32 *denom, int limit_denom ) // limit_denom (1) or limit numer (0)
@@ -7270,7 +7456,7 @@ static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32
bot = 1 << 25;
// keep refining, but usually stops in a few loops - usually 5 for bad cases
- for(;;)
+ for(;;)
{
stbir_uint64 est, temp;
@@ -7303,13 +7489,13 @@ static int stbir__double_to_rational(double f, stbir_uint32 limit, stbir_uint32
bot = temp;
// move remainders
- temp = est * denom_estimate + denom_last;
- denom_last = denom_estimate;
+ temp = est * denom_estimate + denom_last;
+ denom_last = denom_estimate;
denom_estimate = temp;
// move remainders
- temp = est * numer_estimate + numer_last;
- numer_last = numer_estimate;
+ temp = est * numer_estimate + numer_last;
+ numer_last = numer_estimate;
numer_estimate = temp;
}
@@ -7353,11 +7539,11 @@ static int stbir__calculate_region_transform( stbir__scale_info * scale_info, in
output_s = ( (double)output_sub_range) / output_range;
- // figure out the scaling to use
- ratio = output_s / input_s;
+ // figure out the scaling to use
+ ratio = output_s / input_s;
// save scale before clipping
- scale = ( output_range / input_range ) * ratio;
+ scale = ( output_range / input_range ) * ratio;
scale_info->scale = (float)scale;
scale_info->inv_scale = (float)( 1.0 / scale );
@@ -7368,11 +7554,11 @@ static int stbir__calculate_region_transform( stbir__scale_info * scale_info, in
input_s = input_s1 - input_s0;
// after clipping do we have zero input area?
- if ( input_s <= stbir__small_float )
+ if ( input_s <= stbir__small_float )
return 0;
- // calculate and store the starting source offsets in output pixel space
- scale_info->pixel_shift = (float) ( input_s0 * ratio * output_range );
+ // calculate and store the starting source offsets in output pixel space
+ scale_info->pixel_shift = (float) ( input_s0 * ratio * output_range );
scale_info->scale_is_rational = stbir__double_to_rational( scale, ( scale <= 1.0 ) ? output_full_range : input_full_range, &scale_info->scale_numerator, &scale_info->scale_denominator, ( scale >= 1.0 ) );
@@ -7389,7 +7575,6 @@ static void stbir__init_and_set_layout( STBIR_RESIZE * resize, stbir_pixel_layou
resize->output_cb = 0;
resize->user_data = resize;
resize->samplers = 0;
- resize->needs_rebuild = 1;
resize->called_alloc = 0;
resize->horizontal_filter = STBIR_FILTER_DEFAULT;
resize->horizontal_filter_kernel = 0; resize->horizontal_filter_support = 0;
@@ -7403,9 +7588,10 @@ static void stbir__init_and_set_layout( STBIR_RESIZE * resize, stbir_pixel_layou
resize->output_data_type = data_type;
resize->input_pixel_layout_public = pixel_layout;
resize->output_pixel_layout_public = pixel_layout;
+ resize->needs_rebuild = 1;
}
-STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize,
+STBIRDEF void stbir_resize_init( STBIR_RESIZE * resize,
const void *input_pixels, int input_w, int input_h, int input_stride_in_bytes, // stride can be zero
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, // stride can be zero
stbir_pixel_layout pixel_layout, stbir_datatype data_type )
@@ -7428,17 +7614,27 @@ STBIRDEF void stbir_set_datatypes( STBIR_RESIZE * resize, stbir_datatype input_t
{
resize->input_data_type = input_type;
resize->output_data_type = output_type;
+ if ( ( resize->samplers ) && ( !resize->needs_rebuild ) )
+ stbir__update_info_from_resize( resize->samplers, resize );
}
STBIRDEF void stbir_set_pixel_callbacks( STBIR_RESIZE * resize, stbir_input_callback * input_cb, stbir_output_callback * output_cb ) // no callbacks by default
{
resize->input_cb = input_cb;
resize->output_cb = output_cb;
+
+ if ( ( resize->samplers ) && ( !resize->needs_rebuild ) )
+ {
+ resize->samplers->in_pixels_cb = input_cb;
+ resize->samplers->out_pixels_cb = output_cb;
+ }
}
STBIRDEF void stbir_set_user_data( STBIR_RESIZE * resize, void * user_data ) // pass back STBIR_RESIZE* by default
{
resize->user_data = user_data;
+ if ( ( resize->samplers ) && ( !resize->needs_rebuild ) )
+ resize->samplers->user_data = user_data;
}
STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_pixels, int input_stride_in_bytes, void * output_pixels, int output_stride_in_bytes )
@@ -7447,6 +7643,8 @@ STBIRDEF void stbir_set_buffer_ptrs( STBIR_RESIZE * resize, const void * input_p
resize->input_stride_in_bytes = input_stride_in_bytes;
resize->output_pixels = output_pixels;
resize->output_stride_in_bytes = output_stride_in_bytes;
+ if ( ( resize->samplers ) && ( !resize->needs_rebuild ) )
+ stbir__update_info_from_resize( resize->samplers, resize );
}
@@ -7549,7 +7747,7 @@ STBIRDEF int stbir_set_pixel_subrect( STBIR_RESIZE * resize, int subx, int suby,
return 1;
}
-static int stbir__perform_build( STBIR_RESIZE * resize, int splits )
+static int stbir__perform_build( STBIR_RESIZE * resize, int splits )
{
stbir__contributors conservative = { 0, 0 };
stbir__sampler horizontal, vertical;
@@ -7563,13 +7761,13 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits )
// have we already built the samplers?
if ( resize->samplers )
return 0;
-
+
#define STBIR_RETURN_ERROR_AND_ASSERT( exp ) STBIR_ASSERT( !(exp) ); if (exp) return 0;
STBIR_RETURN_ERROR_AND_ASSERT( (unsigned)resize->horizontal_filter >= STBIR_FILTER_OTHER)
STBIR_RETURN_ERROR_AND_ASSERT( (unsigned)resize->vertical_filter >= STBIR_FILTER_OTHER)
#undef STBIR_RETURN_ERROR_AND_ASSERT
- if ( splits <= 0 )
+ if ( splits <= 0 )
return 0;
STBIR_PROFILE_BUILD_FIRST_START( build );
@@ -7593,9 +7791,9 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits )
stbir__get_conservative_extents( &horizontal, &conservative, resize->user_data );
stbir__set_sampler(&vertical, resize->vertical_filter, resize->horizontal_filter_kernel, resize->vertical_filter_support, resize->vertical_edge, &vertical.scale_info, 0, resize->user_data );
- if ( ( vertical.scale_info.output_sub_size / splits ) < 4 ) // each split should be a minimum of 4 scanlines (handwavey choice)
+ if ( ( vertical.scale_info.output_sub_size / splits ) < STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS ) // each split should be a minimum of 4 scanlines (handwavey choice)
{
- splits = vertical.scale_info.output_sub_size / 4;
+ splits = vertical.scale_info.output_sub_size / STBIR_FORCE_MINIMUM_SCANLINES_FOR_SPLITS;
if ( splits == 0 ) splits = 1;
}
@@ -7603,7 +7801,7 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits )
out_info = stbir__alloc_internal_mem_and_build_samplers( &horizontal, &vertical, &conservative, resize->input_pixel_layout_public, resize->output_pixel_layout_public, splits, new_output_subx, new_output_suby, resize->fast_alpha, resize->user_data STBIR_ONLY_PROFILE_BUILD_SET_INFO );
STBIR_PROFILE_BUILD_END( alloc );
STBIR_PROFILE_BUILD_END( build );
-
+
if ( out_info )
{
resize->splits = splits;
@@ -7612,6 +7810,10 @@ static int stbir__perform_build( STBIR_RESIZE * resize, int splits )
#ifdef STBIR_PROFILE
STBIR_MEMCPY( &out_info->profile, &profile_infod.profile, sizeof( out_info->profile ) );
#endif
+
+ // update anything that can be changed without recalcing samplers
+ stbir__update_info_from_resize( out_info, resize );
+
return splits;
}
@@ -7640,7 +7842,7 @@ STBIRDEF int stbir_build_samplers_with_splits( STBIR_RESIZE * resize, int splits
}
STBIR_PROFILE_BUILD_CLEAR( resize->samplers );
-
+
return 1;
}
@@ -7652,7 +7854,7 @@ STBIRDEF int stbir_build_samplers( STBIR_RESIZE * resize )
STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize )
{
int result;
-
+
if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) )
{
int alloc_state = resize->called_alloc; // remember allocated state
@@ -7665,10 +7867,10 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize )
if ( !stbir_build_samplers( resize ) )
return 0;
-
+
resize->called_alloc = alloc_state;
- // if build_samplers succeeded (above), but there are no samplers set, then
+ // if build_samplers succeeded (above), but there are no samplers set, then
// the area to stretch into was zero pixels, so don't do anything and return
// success
if ( resize->samplers == 0 )
@@ -7680,10 +7882,6 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize )
STBIR_PROFILE_BUILD_CLEAR( resize->samplers );
}
-
- // update anything that can be changed without recalcing samplers
- stbir__update_info_from_resize( resize->samplers, resize );
-
// do resize
result = stbir__perform_resize( resize->samplers, 0, resize->splits );
@@ -7692,7 +7890,7 @@ STBIRDEF int stbir_resize_extended( STBIR_RESIZE * resize )
{
stbir_free_samplers( resize );
resize->samplers = 0;
- }
+ }
return result;
}
@@ -7707,14 +7905,11 @@ STBIRDEF int stbir_resize_extended_split( STBIR_RESIZE * resize, int split_start
// you **must** build samplers first when using split resize
if ( ( resize->samplers == 0 ) || ( resize->needs_rebuild ) )
- return 0;
-
+ return 0;
+
if ( ( split_start >= resize->splits ) || ( split_start < 0 ) || ( ( split_start + split_count ) > resize->splits ) || ( split_count <= 0 ) )
return 0;
-
- // update anything that can be changed without recalcing samplers
- stbir__update_info_from_resize( resize->samplers, resize );
-
+
// do resize
return stbir__perform_resize( resize->samplers, split_start, split_count );
}
@@ -7735,7 +7930,7 @@ static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * o
if ( output_stride_in_bytes < pitch )
return 0;
- size = output_stride_in_bytes * output_h;
+ size = (size_t)output_stride_in_bytes * (size_t)output_h;
if ( size == 0 )
return 0;
@@ -7752,7 +7947,7 @@ static int stbir__check_output_stuff( void ** ret_ptr, int * ret_pitch, void * o
*ret_pitch = pitch;
}
- return 1;
+ return 1;
}
@@ -7767,9 +7962,9 @@ STBIRDEF unsigned char * stbir_resize_uint8_linear( const unsigned char *input_p
if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
return 0;
- stbir_resize_init( &resize,
- input_pixels, input_w, input_h, input_stride_in_bytes,
- (optr) ? optr : output_pixels, output_w, output_h, opitch,
+ stbir_resize_init( &resize,
+ input_pixels, input_w, input_h, input_stride_in_bytes,
+ (optr) ? optr : output_pixels, output_w, output_h, opitch,
pixel_layout, STBIR_TYPE_UINT8 );
if ( !stbir_resize_extended( &resize ) )
@@ -7793,9 +7988,9 @@ STBIRDEF unsigned char * stbir_resize_uint8_srgb( const unsigned char *input_pix
if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( unsigned char ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
return 0;
- stbir_resize_init( &resize,
- input_pixels, input_w, input_h, input_stride_in_bytes,
- (optr) ? optr : output_pixels, output_w, output_h, opitch,
+ stbir_resize_init( &resize,
+ input_pixels, input_w, input_h, input_stride_in_bytes,
+ (optr) ? optr : output_pixels, output_w, output_h, opitch,
pixel_layout, STBIR_TYPE_UINT8_SRGB );
if ( !stbir_resize_extended( &resize ) )
@@ -7820,9 +8015,9 @@ STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int inpu
if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, sizeof( float ), output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
return 0;
- stbir_resize_init( &resize,
- input_pixels, input_w, input_h, input_stride_in_bytes,
- (optr) ? optr : output_pixels, output_w, output_h, opitch,
+ stbir_resize_init( &resize,
+ input_pixels, input_w, input_h, input_stride_in_bytes,
+ (optr) ? optr : output_pixels, output_w, output_h, opitch,
pixel_layout, STBIR_TYPE_FLOAT );
if ( !stbir_resize_extended( &resize ) )
@@ -7838,7 +8033,7 @@ STBIRDEF float * stbir_resize_float_linear( const float *input_pixels , int inpu
STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int input_h, int input_stride_in_bytes,
void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
- stbir_pixel_layout pixel_layout, stbir_datatype data_type,
+ stbir_pixel_layout pixel_layout, stbir_datatype data_type,
stbir_edge edge, stbir_filter filter )
{
STBIR_RESIZE resize;
@@ -7848,9 +8043,9 @@ STBIRDEF void * stbir_resize( const void *input_pixels , int input_w , int input
if ( !stbir__check_output_stuff( (void**)&optr, &opitch, output_pixels, stbir__type_size[data_type], output_w, output_h, output_stride_in_bytes, stbir__pixel_layout_convert_public_to_internal[ pixel_layout ] ) )
return 0;
- stbir_resize_init( &resize,
- input_pixels, input_w, input_h, input_stride_in_bytes,
- (optr) ? optr : output_pixels, output_w, output_h, output_stride_in_bytes,
+ stbir_resize_init( &resize,
+ input_pixels, input_w, input_h, input_stride_in_bytes,
+ (optr) ? optr : output_pixels, output_w, output_h, output_stride_in_bytes,
pixel_layout, data_type );
resize.horizontal_edge = edge;
@@ -7958,7 +8153,7 @@ STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * info, STB
#else // STB_IMAGE_RESIZE_HORIZONTALS&STB_IMAGE_RESIZE_DO_VERTICALS
// we reinclude the header file to define all the horizontal functions
-// specializing each function for the number of coeffs is 20-40% faster *OVERALL*
+// specializing each function for the number of coeffs is 20-40% faster *OVERALL*
// by including the header file again this way, we can still debug the functions
@@ -7991,16 +8186,16 @@ STBIRDEF void stbir_resize_extended_profile_info( STBIR_PROFILE_INFO * info, STB
#define stbir__encode_order2 2
#define stbir__encode_order3 3
#define stbir__decode_simdf8_flip(reg)
-#define stbir__decode_simdf4_flip(reg)
+#define stbir__decode_simdf4_flip(reg)
#define stbir__encode_simdf8_unflip(reg)
-#define stbir__encode_simdf4_unflip(reg)
+#define stbir__encode_simdf4_unflip(reg)
#endif
#ifdef STBIR_SIMD8
#define stbir__encode_simdfX_unflip stbir__encode_simdf8_unflip
#else
#define stbir__encode_simdfX_unflip stbir__encode_simdf4_unflip
-#endif
+#endif
static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * decodep, int width_times_channels, void const * inputp )
{
@@ -8013,6 +8208,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco
if ( width_times_channels >= 16 )
{
decode_end -= 16;
+ STBIR_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
#ifdef STBIR_SIMD8
@@ -8054,7 +8250,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco
#endif
decode += 16;
input += 16;
- if ( decode <= decode_end )
+ if ( decode <= decode_end )
continue;
if ( decode == ( decode_end + 16 ) )
break;
@@ -8068,6 +8264,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( decode <= decode_end )
{
STBIR_SIMD_NO_UNROLL(decode);
@@ -8083,6 +8280,7 @@ static void STBIR__CODER_NAME( stbir__decode_uint8_linear_scaled )( float * deco
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( decode < decode_end )
{
STBIR_NO_UNROLL(decode);
@@ -8109,6 +8307,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu
{
float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;
end_output -= stbir__simdfX_float_count*2;
+ STBIR_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
stbir__simdfX e0, e1;
@@ -8119,15 +8318,15 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu
stbir__encode_simdfX_unflip( e0 );
stbir__encode_simdfX_unflip( e1 );
#ifdef STBIR_SIMD8
- stbir__simdf8_pack_to_16bytes( i, e0, e1 );
+ stbir__simdf8_pack_to_16bytes( i, e0, e1 );
stbir__simdi_store( output, i );
#else
- stbir__simdf_pack_to_8bytes( i, e0, e1 );
+ stbir__simdf_pack_to_8bytes( i, e0, e1 );
stbir__simdi_store2( output, i );
#endif
encode += stbir__simdfX_float_count*2;
output += stbir__simdfX_float_count*2;
- if ( output <= end_output )
+ if ( output <= end_output )
continue;
if ( output == ( end_output + stbir__simdfX_float_count*2 ) )
break;
@@ -8140,6 +8339,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output += 4;
+ STBIR_NO_UNROLL_LOOP_START
while( output <= end_output )
{
stbir__simdf e0;
@@ -8158,9 +8358,10 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( output < end_output )
{
- stbir__simdf e0;
+ stbir__simdf e0;
STBIR_NO_UNROLL(encode);
stbir__simdf_madd1_mem( e0, STBIR__CONSTF(STBIR_simd_point5), STBIR__CONSTF(STBIR_max_uint8_as_float), encode+stbir__encode_order0 ); output[0] = stbir__simdf_convert_float_to_uint8( e0 );
#if stbir__coder_min_num >= 2
@@ -8173,7 +8374,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu
encode += stbir__coder_min_num;
}
#endif
-
+
#else
// try to do blocks of 4 when you can
@@ -8194,6 +8395,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear_scaled )( void * outpu
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( output < end_output )
{
float f;
@@ -8223,6 +8425,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int
if ( width_times_channels >= 16 )
{
decode_end -= 16;
+ STBIR_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
#ifdef STBIR_SIMD8
@@ -8258,7 +8461,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int
#endif
decode += 16;
input += 16;
- if ( decode <= decode_end )
+ if ( decode <= decode_end )
continue;
if ( decode == ( decode_end + 16 ) )
break;
@@ -8272,6 +8475,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( decode <= decode_end )
{
STBIR_SIMD_NO_UNROLL(decode);
@@ -8287,6 +8491,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_linear)( float * decodep, int
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( decode < decode_end )
{
STBIR_NO_UNROLL(decode);
@@ -8313,6 +8518,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int
{
float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;
end_output -= stbir__simdfX_float_count*2;
+ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
stbir__simdfX e0, e1;
@@ -8323,15 +8529,15 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int
stbir__encode_simdfX_unflip( e0 );
stbir__encode_simdfX_unflip( e1 );
#ifdef STBIR_SIMD8
- stbir__simdf8_pack_to_16bytes( i, e0, e1 );
+ stbir__simdf8_pack_to_16bytes( i, e0, e1 );
stbir__simdi_store( output, i );
#else
- stbir__simdf_pack_to_8bytes( i, e0, e1 );
+ stbir__simdf_pack_to_8bytes( i, e0, e1 );
stbir__simdi_store2( output, i );
#endif
encode += stbir__simdfX_float_count*2;
output += stbir__simdfX_float_count*2;
- if ( output <= end_output )
+ if ( output <= end_output )
continue;
if ( output == ( end_output + stbir__simdfX_float_count*2 ) )
break;
@@ -8344,6 +8550,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output += 4;
+ STBIR_NO_UNROLL_LOOP_START
while( output <= end_output )
{
stbir__simdf e0;
@@ -8382,6 +8589,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_linear )( void * outputp, int
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( output < end_output )
{
float f;
@@ -8422,6 +8630,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( decode < decode_end )
{
STBIR_NO_UNROLL(decode);
@@ -8441,7 +8650,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi
#define stbir__min_max_shift20( i, f ) \
stbir__simdf_max( f, f, stbir_simdf_casti(STBIR__CONSTI( STBIR_almost_zero )) ); \
stbir__simdf_min( f, f, stbir_simdf_casti(STBIR__CONSTI( STBIR_almost_one )) ); \
- stbir__simdi_32shr( i, stbir_simdi_castf( f ), 20 );
+ stbir__simdi_32shr( i, stbir_simdi_castf( f ), 20 );
#define stbir__scale_and_convert( i, f ) \
stbir__simdf_madd( f, STBIR__CONSTF( STBIR_simd_point5 ), STBIR__CONSTF( STBIR_max_uint8_as_float ), f ); \
@@ -8468,7 +8677,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi
temp1.m128i_u32[0] = table[temp1.m128i_i32[0]]; temp1.m128i_u32[1] = table[temp1.m128i_i32[1]]; temp1.m128i_u32[2] = table[temp1.m128i_i32[2]]; temp1.m128i_u32[3] = table[temp1.m128i_i32[3]]; \
v0 = temp0.m128i_i128; \
v1 = temp1.m128i_i128; \
-}
+}
#define stbir__simdi_table_lookup3( v0,v1,v2, table ) \
{ \
@@ -8499,7 +8708,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb)( float * decodep, int wi
v1 = temp1.m128i_i128; \
v2 = temp2.m128i_i128; \
v3 = temp3.m128i_i128; \
-}
+}
static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int width_times_channels, float const * encode )
{
@@ -8507,16 +8716,16 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w
unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels;
#ifdef STBIR_SIMD
- stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8;
if ( width_times_channels >= 16 )
{
float const * end_encode_m16 = encode + width_times_channels - 16;
end_output -= 16;
+ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
stbir__simdf f0, f1, f2, f3;
- stbir__simdi i0, i1, i2, i3;
+ stbir__simdi i0, i1, i2, i3;
STBIR_SIMD_NO_UNROLL(encode);
stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );
@@ -8525,9 +8734,9 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w
stbir__min_max_shift20( i1, f1 );
stbir__min_max_shift20( i2, f2 );
stbir__min_max_shift20( i3, f3 );
-
- stbir__simdi_table_lookup4( i0, i1, i2, i3, to_srgb );
-
+
+ stbir__simdi_table_lookup4( i0, i1, i2, i3, ( fp32_to_srgb8_tab4 - (127-13)*8 ) );
+
stbir__linear_to_srgb_finish( i0, f0 );
stbir__linear_to_srgb_finish( i1, f1 );
stbir__linear_to_srgb_finish( i2, f2 );
@@ -8537,7 +8746,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w
encode += 16;
output += 16;
- if ( output <= end_output )
+ if ( output <= end_output )
continue;
if ( output == ( end_output + 16 ) )
break;
@@ -8551,6 +8760,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while ( output <= end_output )
{
STBIR_SIMD_NO_UNROLL(encode);
@@ -8568,7 +8778,8 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb )( void * outputp, int w
// do the remnants
#if stbir__coder_min_num < 4
- while( output < end_output )
+ STBIR_NO_UNROLL_LOOP_START
+ while( output < end_output )
{
STBIR_NO_UNROLL(encode);
output[0] = stbir__linear_to_srgb_uchar( encode[stbir__encode_order0] );
@@ -8608,12 +8819,12 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o
unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels;
#ifdef STBIR_SIMD
- stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8;
if ( width_times_channels >= 16 )
{
float const * end_encode_m16 = encode + width_times_channels - 16;
end_output -= 16;
+ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
stbir__simdf f0, f1, f2, f3;
@@ -8625,10 +8836,10 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o
stbir__min_max_shift20( i0, f0 );
stbir__min_max_shift20( i1, f1 );
stbir__min_max_shift20( i2, f2 );
- stbir__scale_and_convert( i3, f3 );
-
- stbir__simdi_table_lookup3( i0, i1, i2, to_srgb );
-
+ stbir__scale_and_convert( i3, f3 );
+
+ stbir__simdi_table_lookup3( i0, i1, i2, ( fp32_to_srgb8_tab4 - (127-13)*8 ) );
+
stbir__linear_to_srgb_finish( i0, f0 );
stbir__linear_to_srgb_finish( i1, f1 );
stbir__linear_to_srgb_finish( i2, f2 );
@@ -8638,7 +8849,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o
output += 16;
encode += 16;
- if ( output <= end_output )
+ if ( output <= end_output )
continue;
if ( output == ( end_output + 16 ) )
break;
@@ -8649,9 +8860,10 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb4_linearalpha )( void * o
}
#endif
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
float f;
- STBIR_SIMD_NO_UNROLL(encode);
+ STBIR_SIMD_NO_UNROLL(encode);
output[stbir__decode_order0] = stbir__linear_to_srgb_uchar( encode[0] );
output[stbir__decode_order1] = stbir__linear_to_srgb_uchar( encode[1] );
@@ -8686,7 +8898,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint8_srgb2_linearalpha)( float * de
decode += 4;
}
decode -= 4;
- if( decode < decode_end )
+ if( decode < decode_end )
{
decode[0] = stbir__srgb_uchar_to_linear_float[ stbir__decode_order0 ];
decode[1] = ( (float) input[stbir__decode_order1] ) * stbir__max_uint8_as_float_inverted;
@@ -8699,16 +8911,16 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o
unsigned char * end_output = ( (unsigned char*) output ) + width_times_channels;
#ifdef STBIR_SIMD
- stbir_uint32 const * to_srgb = fp32_to_srgb8_tab4 - (127-13)*8;
if ( width_times_channels >= 16 )
{
float const * end_encode_m16 = encode + width_times_channels - 16;
end_output -= 16;
+ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
stbir__simdf f0, f1, f2, f3;
- stbir__simdi i0, i1, i2, i3;
+ stbir__simdi i0, i1, i2, i3;
STBIR_SIMD_NO_UNROLL(encode);
stbir__simdf_load4_transposed( f0, f1, f2, f3, encode );
@@ -8717,9 +8929,9 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o
stbir__scale_and_convert( i1, f1 );
stbir__min_max_shift20( i2, f2 );
stbir__scale_and_convert( i3, f3 );
-
- stbir__simdi_table_lookup2( i0, i2, to_srgb );
-
+
+ stbir__simdi_table_lookup2( i0, i2, ( fp32_to_srgb8_tab4 - (127-13)*8 ) );
+
stbir__linear_to_srgb_finish( i0, f0 );
stbir__linear_to_srgb_finish( i2, f2 );
@@ -8727,7 +8939,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o
output += 16;
encode += 16;
- if ( output <= end_output )
+ if ( output <= end_output )
continue;
if ( output == ( end_output + 16 ) )
break;
@@ -8738,6 +8950,7 @@ static void STBIR__CODER_NAME( stbir__encode_uint8_srgb2_linearalpha )( void * o
}
#endif
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
float f;
STBIR_SIMD_NO_UNROLL(encode);
@@ -8766,6 +8979,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod
if ( width_times_channels >= 8 )
{
decode_end -= 8;
+ STBIR_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
#ifdef STBIR_SIMD8
@@ -8793,9 +9007,9 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod
stbir__simdf_store( decode + 0, of0 );
stbir__simdf_store( decode + 4, of1 );
#endif
- decode += 8;
+ decode += 8;
input += 8;
- if ( decode <= decode_end )
+ if ( decode <= decode_end )
continue;
if ( decode == ( decode_end + 8 ) )
break;
@@ -8809,6 +9023,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( decode <= decode_end )
{
STBIR_SIMD_NO_UNROLL(decode);
@@ -8824,6 +9039,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear_scaled)( float * decod
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( decode < decode_end )
{
STBIR_NO_UNROLL(decode);
@@ -8852,6 +9068,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output
{
float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;
end_output -= stbir__simdfX_float_count*2;
+ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
stbir__simdfX e0, e1;
@@ -8865,7 +9082,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output
stbir__simdiX_store( output, i );
encode += stbir__simdfX_float_count*2;
output += stbir__simdfX_float_count*2;
- if ( output <= end_output )
+ if ( output <= end_output )
continue;
if ( output == ( end_output + stbir__simdfX_float_count*2 ) )
break;
@@ -8879,6 +9096,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output += 4;
+ STBIR_NO_UNROLL_LOOP_START
while( output <= end_output )
{
stbir__simdf e;
@@ -8897,6 +9115,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( output < end_output )
{
stbir__simdf e;
@@ -8912,12 +9131,13 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output
encode += stbir__coder_min_num;
}
#endif
-
+
#else
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( output <= end_output )
{
float f;
@@ -8934,6 +9154,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear_scaled)( void * output
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( output < end_output )
{
float f;
@@ -8963,6 +9184,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int
if ( width_times_channels >= 8 )
{
decode_end -= 8;
+ STBIR_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
#ifdef STBIR_SIMD8
@@ -8989,7 +9211,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int
#endif
decode += 8;
input += 8;
- if ( decode <= decode_end )
+ if ( decode <= decode_end )
continue;
if ( decode == ( decode_end + 8 ) )
break;
@@ -9003,6 +9225,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( decode <= decode_end )
{
STBIR_SIMD_NO_UNROLL(decode);
@@ -9018,6 +9241,7 @@ static void STBIR__CODER_NAME(stbir__decode_uint16_linear)( float * decodep, int
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( decode < decode_end )
{
STBIR_NO_UNROLL(decode);
@@ -9045,6 +9269,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int
{
float const * end_encode_m8 = encode + width_times_channels - stbir__simdfX_float_count*2;
end_output -= stbir__simdfX_float_count*2;
+ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
stbir__simdfX e0, e1;
@@ -9058,7 +9283,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int
stbir__simdiX_store( output, i );
encode += stbir__simdfX_float_count*2;
output += stbir__simdfX_float_count*2;
- if ( output <= end_output )
+ if ( output <= end_output )
continue;
if ( output == ( end_output + stbir__simdfX_float_count*2 ) )
break;
@@ -9072,6 +9297,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output += 4;
+ STBIR_NO_UNROLL_LOOP_START
while( output <= end_output )
{
stbir__simdf e;
@@ -9093,6 +9319,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( output <= end_output )
{
float f;
@@ -9111,6 +9338,7 @@ static void STBIR__CODER_NAME(stbir__encode_uint16_linear)( void * outputp, int
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( output < end_output )
{
float f;
@@ -9139,6 +9367,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep,
{
stbir__FP16 const * end_input_m8 = input + width_times_channels - 8;
decode_end -= 8;
+ STBIR_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
STBIR_NO_UNROLL(decode);
@@ -9166,7 +9395,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep,
#endif
decode += 8;
input += 8;
- if ( decode <= decode_end )
+ if ( decode <= decode_end )
continue;
if ( decode == ( decode_end + 8 ) )
break;
@@ -9180,6 +9409,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep,
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( decode <= decode_end )
{
STBIR_SIMD_NO_UNROLL(decode);
@@ -9195,6 +9425,7 @@ static void STBIR__CODER_NAME(stbir__decode_half_float_linear)( float * decodep,
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( decode < decode_end )
{
STBIR_NO_UNROLL(decode);
@@ -9221,6 +9452,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp
{
float const * end_encode_m8 = encode + width_times_channels - 8;
end_output -= 8;
+ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
STBIR_SIMD_NO_UNROLL(encode);
@@ -9247,7 +9479,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp
#endif
encode += 8;
output += 8;
- if ( output <= end_output )
+ if ( output <= end_output )
continue;
if ( output == ( end_output + 8 ) )
break;
@@ -9261,6 +9493,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( output <= end_output )
{
STBIR_SIMD_NO_UNROLL(output);
@@ -9276,6 +9509,7 @@ static void STBIR__CODER_NAME( stbir__encode_half_float_linear )( void * outputp
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( output < end_output )
{
STBIR_NO_UNROLL(output);
@@ -9304,6 +9538,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int
{
float const * end_input_m16 = input + width_times_channels - 16;
decode_end -= 16;
+ STBIR_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
STBIR_NO_UNROLL(decode);
@@ -9338,7 +9573,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int
#endif
decode += 16;
input += 16;
- if ( decode <= decode_end )
+ if ( decode <= decode_end )
continue;
if ( decode == ( decode_end + 16 ) )
break;
@@ -9352,6 +9587,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
decode += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( decode <= decode_end )
{
STBIR_SIMD_NO_UNROLL(decode);
@@ -9367,6 +9603,7 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( decode < decode_end )
{
STBIR_NO_UNROLL(decode);
@@ -9383,10 +9620,10 @@ static void STBIR__CODER_NAME(stbir__decode_float_linear)( float * decodep, int
#endif
#else
-
+
if ( (void*)decodep != inputp )
STBIR_MEMCPY( decodep, inputp, width_times_channels * sizeof( float ) );
-
+
#endif
}
@@ -9426,6 +9663,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int
{
float const * end_encode_m8 = encode + width_times_channels - ( stbir__simdfX_float_count * 2 );
end_output -= ( stbir__simdfX_float_count * 2 );
+ STBIR_SIMD_NO_UNROLL_LOOP_START_INF_FOR
for(;;)
{
stbir__simdfX e0, e1;
@@ -9435,18 +9673,18 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int
#ifdef STBIR_FLOAT_HIGH_CLAMP
stbir__simdfX_min( e0, e0, high_clamp );
stbir__simdfX_min( e1, e1, high_clamp );
-#endif
+#endif
#ifdef STBIR_FLOAT_LOW_CLAMP
stbir__simdfX_max( e0, e0, low_clamp );
stbir__simdfX_max( e1, e1, low_clamp );
-#endif
+#endif
stbir__encode_simdfX_unflip( e0 );
stbir__encode_simdfX_unflip( e1 );
stbir__simdfX_store( output, e0 );
stbir__simdfX_store( output+stbir__simdfX_float_count, e1 );
encode += stbir__simdfX_float_count * 2;
output += stbir__simdfX_float_count * 2;
- if ( output < end_output )
+ if ( output < end_output )
continue;
if ( output == ( end_output + ( stbir__simdfX_float_count * 2 ) ) )
break;
@@ -9459,6 +9697,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output += 4;
+ STBIR_NO_UNROLL_LOOP_START
while( output <= end_output )
{
stbir__simdf e0;
@@ -9466,10 +9705,10 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int
stbir__simdf_load( e0, encode );
#ifdef STBIR_FLOAT_HIGH_CLAMP
stbir__simdf_min( e0, e0, high_clamp );
-#endif
+#endif
#ifdef STBIR_FLOAT_LOW_CLAMP
stbir__simdf_max( e0, e0, low_clamp );
-#endif
+#endif
stbir__encode_simdf4_unflip( e0 );
stbir__simdf_store( output-4, e0 );
output += 4;
@@ -9483,6 +9722,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int
// try to do blocks of 4 when you can
#if stbir__coder_min_num != 3 // doesn't divide cleanly by four
output += 4;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
while( output <= end_output )
{
float e;
@@ -9502,6 +9742,7 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int
// do the remnants
#if stbir__coder_min_num < 4
+ STBIR_NO_UNROLL_LOOP_START
while( output < end_output )
{
float e;
@@ -9517,18 +9758,18 @@ static void STBIR__CODER_NAME( stbir__encode_float_linear )( void * outputp, int
encode += stbir__coder_min_num;
}
#endif
-
+
#endif
}
-#undef stbir__decode_suffix
+#undef stbir__decode_suffix
#undef stbir__decode_simdf8_flip
#undef stbir__decode_simdf4_flip
-#undef stbir__decode_order0
+#undef stbir__decode_order0
#undef stbir__decode_order1
#undef stbir__decode_order2
#undef stbir__decode_order3
-#undef stbir__encode_order0
+#undef stbir__encode_order0
#undef stbir__encode_order1
#undef stbir__encode_order2
#undef stbir__encode_order3
@@ -9612,7 +9853,8 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output
stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); )
stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); )
stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); )
- while ( ( (char*)input_end - (char*) input ) >= (16*stbir__simdfX_float_count) )
+ STBIR_SIMD_NO_UNROLL_LOOP_START
+ while ( ( (char*)input_end - (char*) input ) >= (16*stbir__simdfX_float_count) )
{
stbir__simdfX o0, o1, o2, o3, r0, r1, r2, r3;
STBIR_SIMD_NO_UNROLL(output0);
@@ -9621,52 +9863,53 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output
#ifdef STB_IMAGE_RESIZE_VERTICAL_CONTINUE
stbIF0( stbir__simdfX_load( o0, output0 ); stbir__simdfX_load( o1, output0+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output0+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output0+(3*stbir__simdfX_float_count) );
- stbir__simdfX_madd( o0, o0, r0, c0 ); stbir__simdfX_madd( o1, o1, r1, c0 ); stbir__simdfX_madd( o2, o2, r2, c0 ); stbir__simdfX_madd( o3, o3, r3, c0 );
+ stbir__simdfX_madd( o0, o0, r0, c0 ); stbir__simdfX_madd( o1, o1, r1, c0 ); stbir__simdfX_madd( o2, o2, r2, c0 ); stbir__simdfX_madd( o3, o3, r3, c0 );
stbir__simdfX_store( output0, o0 ); stbir__simdfX_store( output0+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output0+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output0+(3*stbir__simdfX_float_count), o3 ); )
stbIF1( stbir__simdfX_load( o0, output1 ); stbir__simdfX_load( o1, output1+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output1+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output1+(3*stbir__simdfX_float_count) );
- stbir__simdfX_madd( o0, o0, r0, c1 ); stbir__simdfX_madd( o1, o1, r1, c1 ); stbir__simdfX_madd( o2, o2, r2, c1 ); stbir__simdfX_madd( o3, o3, r3, c1 );
+ stbir__simdfX_madd( o0, o0, r0, c1 ); stbir__simdfX_madd( o1, o1, r1, c1 ); stbir__simdfX_madd( o2, o2, r2, c1 ); stbir__simdfX_madd( o3, o3, r3, c1 );
stbir__simdfX_store( output1, o0 ); stbir__simdfX_store( output1+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output1+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output1+(3*stbir__simdfX_float_count), o3 ); )
stbIF2( stbir__simdfX_load( o0, output2 ); stbir__simdfX_load( o1, output2+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output2+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output2+(3*stbir__simdfX_float_count) );
- stbir__simdfX_madd( o0, o0, r0, c2 ); stbir__simdfX_madd( o1, o1, r1, c2 ); stbir__simdfX_madd( o2, o2, r2, c2 ); stbir__simdfX_madd( o3, o3, r3, c2 );
+ stbir__simdfX_madd( o0, o0, r0, c2 ); stbir__simdfX_madd( o1, o1, r1, c2 ); stbir__simdfX_madd( o2, o2, r2, c2 ); stbir__simdfX_madd( o3, o3, r3, c2 );
stbir__simdfX_store( output2, o0 ); stbir__simdfX_store( output2+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output2+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output2+(3*stbir__simdfX_float_count), o3 ); )
stbIF3( stbir__simdfX_load( o0, output3 ); stbir__simdfX_load( o1, output3+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output3+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output3+(3*stbir__simdfX_float_count) );
- stbir__simdfX_madd( o0, o0, r0, c3 ); stbir__simdfX_madd( o1, o1, r1, c3 ); stbir__simdfX_madd( o2, o2, r2, c3 ); stbir__simdfX_madd( o3, o3, r3, c3 );
+ stbir__simdfX_madd( o0, o0, r0, c3 ); stbir__simdfX_madd( o1, o1, r1, c3 ); stbir__simdfX_madd( o2, o2, r2, c3 ); stbir__simdfX_madd( o3, o3, r3, c3 );
stbir__simdfX_store( output3, o0 ); stbir__simdfX_store( output3+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output3+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output3+(3*stbir__simdfX_float_count), o3 ); )
stbIF4( stbir__simdfX_load( o0, output4 ); stbir__simdfX_load( o1, output4+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output4+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output4+(3*stbir__simdfX_float_count) );
- stbir__simdfX_madd( o0, o0, r0, c4 ); stbir__simdfX_madd( o1, o1, r1, c4 ); stbir__simdfX_madd( o2, o2, r2, c4 ); stbir__simdfX_madd( o3, o3, r3, c4 );
+ stbir__simdfX_madd( o0, o0, r0, c4 ); stbir__simdfX_madd( o1, o1, r1, c4 ); stbir__simdfX_madd( o2, o2, r2, c4 ); stbir__simdfX_madd( o3, o3, r3, c4 );
stbir__simdfX_store( output4, o0 ); stbir__simdfX_store( output4+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output4+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output4+(3*stbir__simdfX_float_count), o3 ); )
stbIF5( stbir__simdfX_load( o0, output5 ); stbir__simdfX_load( o1, output5+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output5+(2*stbir__simdfX_float_count)); stbir__simdfX_load( o3, output5+(3*stbir__simdfX_float_count) );
- stbir__simdfX_madd( o0, o0, r0, c5 ); stbir__simdfX_madd( o1, o1, r1, c5 ); stbir__simdfX_madd( o2, o2, r2, c5 ); stbir__simdfX_madd( o3, o3, r3, c5 );
+ stbir__simdfX_madd( o0, o0, r0, c5 ); stbir__simdfX_madd( o1, o1, r1, c5 ); stbir__simdfX_madd( o2, o2, r2, c5 ); stbir__simdfX_madd( o3, o3, r3, c5 );
stbir__simdfX_store( output5, o0 ); stbir__simdfX_store( output5+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output5+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output5+(3*stbir__simdfX_float_count), o3 ); )
stbIF6( stbir__simdfX_load( o0, output6 ); stbir__simdfX_load( o1, output6+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output6+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output6+(3*stbir__simdfX_float_count) );
- stbir__simdfX_madd( o0, o0, r0, c6 ); stbir__simdfX_madd( o1, o1, r1, c6 ); stbir__simdfX_madd( o2, o2, r2, c6 ); stbir__simdfX_madd( o3, o3, r3, c6 );
+ stbir__simdfX_madd( o0, o0, r0, c6 ); stbir__simdfX_madd( o1, o1, r1, c6 ); stbir__simdfX_madd( o2, o2, r2, c6 ); stbir__simdfX_madd( o3, o3, r3, c6 );
stbir__simdfX_store( output6, o0 ); stbir__simdfX_store( output6+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output6+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output6+(3*stbir__simdfX_float_count), o3 ); )
stbIF7( stbir__simdfX_load( o0, output7 ); stbir__simdfX_load( o1, output7+stbir__simdfX_float_count ); stbir__simdfX_load( o2, output7+(2*stbir__simdfX_float_count) ); stbir__simdfX_load( o3, output7+(3*stbir__simdfX_float_count) );
- stbir__simdfX_madd( o0, o0, r0, c7 ); stbir__simdfX_madd( o1, o1, r1, c7 ); stbir__simdfX_madd( o2, o2, r2, c7 ); stbir__simdfX_madd( o3, o3, r3, c7 );
+ stbir__simdfX_madd( o0, o0, r0, c7 ); stbir__simdfX_madd( o1, o1, r1, c7 ); stbir__simdfX_madd( o2, o2, r2, c7 ); stbir__simdfX_madd( o3, o3, r3, c7 );
stbir__simdfX_store( output7, o0 ); stbir__simdfX_store( output7+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output7+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output7+(3*stbir__simdfX_float_count), o3 ); )
#else
- stbIF0( stbir__simdfX_mult( o0, r0, c0 ); stbir__simdfX_mult( o1, r1, c0 ); stbir__simdfX_mult( o2, r2, c0 ); stbir__simdfX_mult( o3, r3, c0 );
+ stbIF0( stbir__simdfX_mult( o0, r0, c0 ); stbir__simdfX_mult( o1, r1, c0 ); stbir__simdfX_mult( o2, r2, c0 ); stbir__simdfX_mult( o3, r3, c0 );
stbir__simdfX_store( output0, o0 ); stbir__simdfX_store( output0+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output0+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output0+(3*stbir__simdfX_float_count), o3 ); )
- stbIF1( stbir__simdfX_mult( o0, r0, c1 ); stbir__simdfX_mult( o1, r1, c1 ); stbir__simdfX_mult( o2, r2, c1 ); stbir__simdfX_mult( o3, r3, c1 );
+ stbIF1( stbir__simdfX_mult( o0, r0, c1 ); stbir__simdfX_mult( o1, r1, c1 ); stbir__simdfX_mult( o2, r2, c1 ); stbir__simdfX_mult( o3, r3, c1 );
stbir__simdfX_store( output1, o0 ); stbir__simdfX_store( output1+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output1+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output1+(3*stbir__simdfX_float_count), o3 ); )
- stbIF2( stbir__simdfX_mult( o0, r0, c2 ); stbir__simdfX_mult( o1, r1, c2 ); stbir__simdfX_mult( o2, r2, c2 ); stbir__simdfX_mult( o3, r3, c2 );
+ stbIF2( stbir__simdfX_mult( o0, r0, c2 ); stbir__simdfX_mult( o1, r1, c2 ); stbir__simdfX_mult( o2, r2, c2 ); stbir__simdfX_mult( o3, r3, c2 );
stbir__simdfX_store( output2, o0 ); stbir__simdfX_store( output2+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output2+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output2+(3*stbir__simdfX_float_count), o3 ); )
- stbIF3( stbir__simdfX_mult( o0, r0, c3 ); stbir__simdfX_mult( o1, r1, c3 ); stbir__simdfX_mult( o2, r2, c3 ); stbir__simdfX_mult( o3, r3, c3 );
+ stbIF3( stbir__simdfX_mult( o0, r0, c3 ); stbir__simdfX_mult( o1, r1, c3 ); stbir__simdfX_mult( o2, r2, c3 ); stbir__simdfX_mult( o3, r3, c3 );
stbir__simdfX_store( output3, o0 ); stbir__simdfX_store( output3+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output3+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output3+(3*stbir__simdfX_float_count), o3 ); )
- stbIF4( stbir__simdfX_mult( o0, r0, c4 ); stbir__simdfX_mult( o1, r1, c4 ); stbir__simdfX_mult( o2, r2, c4 ); stbir__simdfX_mult( o3, r3, c4 );
+ stbIF4( stbir__simdfX_mult( o0, r0, c4 ); stbir__simdfX_mult( o1, r1, c4 ); stbir__simdfX_mult( o2, r2, c4 ); stbir__simdfX_mult( o3, r3, c4 );
stbir__simdfX_store( output4, o0 ); stbir__simdfX_store( output4+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output4+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output4+(3*stbir__simdfX_float_count), o3 ); )
- stbIF5( stbir__simdfX_mult( o0, r0, c5 ); stbir__simdfX_mult( o1, r1, c5 ); stbir__simdfX_mult( o2, r2, c5 ); stbir__simdfX_mult( o3, r3, c5 );
+ stbIF5( stbir__simdfX_mult( o0, r0, c5 ); stbir__simdfX_mult( o1, r1, c5 ); stbir__simdfX_mult( o2, r2, c5 ); stbir__simdfX_mult( o3, r3, c5 );
stbir__simdfX_store( output5, o0 ); stbir__simdfX_store( output5+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output5+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output5+(3*stbir__simdfX_float_count), o3 ); )
- stbIF6( stbir__simdfX_mult( o0, r0, c6 ); stbir__simdfX_mult( o1, r1, c6 ); stbir__simdfX_mult( o2, r2, c6 ); stbir__simdfX_mult( o3, r3, c6 );
+ stbIF6( stbir__simdfX_mult( o0, r0, c6 ); stbir__simdfX_mult( o1, r1, c6 ); stbir__simdfX_mult( o2, r2, c6 ); stbir__simdfX_mult( o3, r3, c6 );
stbir__simdfX_store( output6, o0 ); stbir__simdfX_store( output6+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output6+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output6+(3*stbir__simdfX_float_count), o3 ); )
- stbIF7( stbir__simdfX_mult( o0, r0, c7 ); stbir__simdfX_mult( o1, r1, c7 ); stbir__simdfX_mult( o2, r2, c7 ); stbir__simdfX_mult( o3, r3, c7 );
+ stbIF7( stbir__simdfX_mult( o0, r0, c7 ); stbir__simdfX_mult( o1, r1, c7 ); stbir__simdfX_mult( o2, r2, c7 ); stbir__simdfX_mult( o3, r3, c7 );
stbir__simdfX_store( output7, o0 ); stbir__simdfX_store( output7+stbir__simdfX_float_count, o1 ); stbir__simdfX_store( output7+(2*stbir__simdfX_float_count), o2 ); stbir__simdfX_store( output7+(3*stbir__simdfX_float_count), o3 ); )
#endif
input += (4*stbir__simdfX_float_count);
stbIF0( output0 += (4*stbir__simdfX_float_count); ) stbIF1( output1 += (4*stbir__simdfX_float_count); ) stbIF2( output2 += (4*stbir__simdfX_float_count); ) stbIF3( output3 += (4*stbir__simdfX_float_count); ) stbIF4( output4 += (4*stbir__simdfX_float_count); ) stbIF5( output5 += (4*stbir__simdfX_float_count); ) stbIF6( output6 += (4*stbir__simdfX_float_count); ) stbIF7( output7 += (4*stbir__simdfX_float_count); )
}
- while ( ( (char*)input_end - (char*) input ) >= 16 )
+ STBIR_SIMD_NO_UNROLL_LOOP_START
+ while ( ( (char*)input_end - (char*) input ) >= 16 )
{
stbir__simdf o0, r0;
STBIR_SIMD_NO_UNROLL(output0);
@@ -9692,13 +9935,14 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output
stbIF6( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c6 ) ); stbir__simdf_store( output6, o0 ); )
stbIF7( stbir__simdf_mult( o0, r0, stbir__if_simdf8_cast_to_simdf4( c7 ) ); stbir__simdf_store( output7, o0 ); )
#endif
-
+
input += 4;
stbIF0( output0 += 4; ) stbIF1( output1 += 4; ) stbIF2( output2 += 4; ) stbIF3( output3 += 4; ) stbIF4( output4 += 4; ) stbIF5( output5 += 4; ) stbIF6( output6 += 4; ) stbIF7( output7 += 4; )
}
}
#else
- while ( ( (char*)input_end - (char*) input ) >= 16 )
+ STBIR_NO_UNROLL_LOOP_START
+ while ( ( (char*)input_end - (char*) input ) >= 16 )
{
float r0, r1, r2, r3;
STBIR_NO_UNROLL(input);
@@ -9729,7 +9973,8 @@ static void STBIR_chans( stbir__vertical_scatter_with_,_coeffs)( float ** output
stbIF0( output0 += 4; ) stbIF1( output1 += 4; ) stbIF2( output2 += 4; ) stbIF3( output3 += 4; ) stbIF4( output4 += 4; ) stbIF5( output5 += 4; ) stbIF6( output6 += 4; ) stbIF7( output7 += 4; )
}
#endif
- while ( input < input_end )
+ STBIR_NO_UNROLL_LOOP_START
+ while ( input < input_end )
{
float r = input[0];
STBIR_NO_UNROLL(output0);
@@ -9779,7 +10024,7 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp,
STBIR_MEMCPY( output, input0, (char*)input0_end - (char*)input0 );
return;
}
-#endif
+#endif
#ifdef STBIR_SIMD
{
@@ -9791,14 +10036,15 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp,
stbIF5(stbir__simdfX c5 = stbir__simdf_frepX( c5s ); )
stbIF6(stbir__simdfX c6 = stbir__simdf_frepX( c6s ); )
stbIF7(stbir__simdfX c7 = stbir__simdf_frepX( c7s ); )
-
- while ( ( (char*)input0_end - (char*) input0 ) >= (16*stbir__simdfX_float_count) )
+
+ STBIR_SIMD_NO_UNROLL_LOOP_START
+ while ( ( (char*)input0_end - (char*) input0 ) >= (16*stbir__simdfX_float_count) )
{
stbir__simdfX o0, o1, o2, o3, r0, r1, r2, r3;
STBIR_SIMD_NO_UNROLL(output);
// prefetch four loop iterations ahead (doesn't affect much for small resizes, but helps with big ones)
- stbIF0( stbir__prefetch( input0 + (16*stbir__simdfX_float_count) ); )
+ stbIF0( stbir__prefetch( input0 + (16*stbir__simdfX_float_count) ); )
stbIF1( stbir__prefetch( input1 + (16*stbir__simdfX_float_count) ); )
stbIF2( stbir__prefetch( input2 + (16*stbir__simdfX_float_count) ); )
stbIF3( stbir__prefetch( input3 + (16*stbir__simdfX_float_count) ); )
@@ -9836,7 +10082,8 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp,
stbIF0( input0 += (4*stbir__simdfX_float_count); ) stbIF1( input1 += (4*stbir__simdfX_float_count); ) stbIF2( input2 += (4*stbir__simdfX_float_count); ) stbIF3( input3 += (4*stbir__simdfX_float_count); ) stbIF4( input4 += (4*stbir__simdfX_float_count); ) stbIF5( input5 += (4*stbir__simdfX_float_count); ) stbIF6( input6 += (4*stbir__simdfX_float_count); ) stbIF7( input7 += (4*stbir__simdfX_float_count); )
}
- while ( ( (char*)input0_end - (char*) input0 ) >= 16 )
+ STBIR_SIMD_NO_UNROLL_LOOP_START
+ while ( ( (char*)input0_end - (char*) input0 ) >= 16 )
{
stbir__simdf o0, r0;
STBIR_SIMD_NO_UNROLL(output);
@@ -9860,7 +10107,8 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp,
}
}
#else
- while ( ( (char*)input0_end - (char*) input0 ) >= 16 )
+ STBIR_NO_UNROLL_LOOP_START
+ while ( ( (char*)input0_end - (char*) input0 ) >= 16 )
{
float o0, o1, o2, o3;
STBIR_NO_UNROLL(output);
@@ -9881,7 +10129,8 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp,
stbIF0( input0 += 4; ) stbIF1( input1 += 4; ) stbIF2( input2 += 4; ) stbIF3( input3 += 4; ) stbIF4( input4 += 4; ) stbIF5( input5 += 4; ) stbIF6( input6 += 4; ) stbIF7( input7 += 4; )
}
#endif
- while ( input0 < input0_end )
+ STBIR_NO_UNROLL_LOOP_START
+ while ( input0 < input0_end )
{
float o0;
STBIR_NO_UNROLL(output);
@@ -9897,7 +10146,7 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp,
stbIF5( o0 += input5[0] * c5s; )
stbIF6( o0 += input6[0] * c6s; )
stbIF7( o0 += input7[0] * c7s; )
- output[0] = o0;
+ output[0] = o0;
++output;
stbIF0( ++input0; ) stbIF1( ++input1; ) stbIF2( ++input2; ) stbIF3( ++input3; ) stbIF4( ++input4; ) stbIF5( ++input5; ) stbIF6( ++input6; ) stbIF7( ++input7; )
}
@@ -9928,25 +10177,25 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp,
#ifndef stbir__2_coeff_only
#define stbir__2_coeff_only() \
stbir__1_coeff_only(); \
- stbir__1_coeff_remnant(1);
+ stbir__1_coeff_remnant(1);
#endif
#ifndef stbir__2_coeff_remnant
#define stbir__2_coeff_remnant( ofs ) \
stbir__1_coeff_remnant(ofs); \
- stbir__1_coeff_remnant((ofs)+1);
+ stbir__1_coeff_remnant((ofs)+1);
#endif
-
+
#ifndef stbir__3_coeff_only
#define stbir__3_coeff_only() \
stbir__2_coeff_only(); \
- stbir__1_coeff_remnant(2);
+ stbir__1_coeff_remnant(2);
#endif
-
+
#ifndef stbir__3_coeff_remnant
#define stbir__3_coeff_remnant( ofs ) \
stbir__2_coeff_remnant(ofs); \
- stbir__1_coeff_remnant((ofs)+2);
+ stbir__1_coeff_remnant((ofs)+2);
#endif
#ifndef stbir__3_coeff_setup
@@ -9956,13 +10205,13 @@ static void STBIR_chans( stbir__vertical_gather_with_,_coeffs)( float * outputp,
#ifndef stbir__4_coeff_start
#define stbir__4_coeff_start() \
stbir__2_coeff_only(); \
- stbir__2_coeff_remnant(2);
+ stbir__2_coeff_remnant(2);
#endif
-
+
#ifndef stbir__4_coeff_continue_from_4
#define stbir__4_coeff_continue_from_4( ofs ) \
stbir__2_coeff_remnant(ofs); \
- stbir__2_coeff_remnant((ofs)+2);
+ stbir__2_coeff_remnant((ofs)+2);
#endif
#ifndef stbir__store_output_tiny
@@ -9973,8 +10222,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_1_coeff)( floa
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__1_coeff_only();
stbir__store_output_tiny();
@@ -9985,8 +10235,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_2_coeffs)( flo
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__2_coeff_only();
stbir__store_output_tiny();
@@ -9997,8 +10248,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_3_coeffs)( flo
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__3_coeff_only();
stbir__store_output_tiny();
@@ -10009,8 +10261,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_4_coeffs)( flo
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
stbir__store_output();
@@ -10021,8 +10274,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_5_coeffs)( flo
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
stbir__1_coeff_remnant(4);
@@ -10034,8 +10288,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_6_coeffs)( flo
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
stbir__2_coeff_remnant(4);
@@ -10048,10 +10303,11 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_7_coeffs)( flo
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
stbir__3_coeff_setup();
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
-
+
stbir__4_coeff_start();
stbir__3_coeff_remnant(4);
stbir__store_output();
@@ -10062,8 +10318,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_8_coeffs)( flo
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
stbir__4_coeff_continue_from_4(4);
@@ -10075,8 +10332,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_9_coeffs)( flo
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
stbir__4_coeff_continue_from_4(4);
@@ -10089,8 +10347,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_10_coeffs)( fl
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
stbir__4_coeff_continue_from_4(4);
@@ -10104,8 +10363,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_11_coeffs)( fl
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
stbir__3_coeff_setup();
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
stbir__4_coeff_continue_from_4(4);
@@ -10118,8 +10378,9 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_12_coeffs)( fl
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
stbir__4_coeff_continue_from_4(4);
@@ -10132,12 +10393,14 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod0
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
- int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 4 + 3 ) >> 2;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 4 + 3 ) >> 2;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
hc += 4;
decode += STBIR__horizontal_channels * 4;
@@ -10152,19 +10415,21 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod1
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
- int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 5 + 3 ) >> 2;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 5 + 3 ) >> 2;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
hc += 4;
decode += STBIR__horizontal_channels * 4;
stbir__4_coeff_continue_from_4( 0 );
--n;
} while ( n > 0 );
- stbir__1_coeff_remnant( 4 );
+ stbir__1_coeff_remnant( 4 );
stbir__store_output();
} while ( output < output_end );
}
@@ -10173,19 +10438,21 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod2
{
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
- int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 6 + 3 ) >> 2;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 6 + 3 ) >> 2;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
hc += 4;
decode += STBIR__horizontal_channels * 4;
stbir__4_coeff_continue_from_4( 0 );
--n;
} while ( n > 0 );
- stbir__2_coeff_remnant( 4 );
+ stbir__2_coeff_remnant( 4 );
stbir__store_output();
} while ( output < output_end );
@@ -10196,19 +10463,21 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod3
float const * output_end = output_buffer + output_sub_size * STBIR__horizontal_channels;
float STBIR_SIMD_STREAMOUT_PTR( * ) output = output_buffer;
stbir__3_coeff_setup();
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
- float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
- int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 7 + 3 ) >> 2;
+ float const * decode = decode_buffer + horizontal_contributors->n0 * STBIR__horizontal_channels;
+ int n = ( ( horizontal_contributors->n1 - horizontal_contributors->n0 + 1 ) - 7 + 3 ) >> 2;
float const * hc = horizontal_coefficients;
stbir__4_coeff_start();
+ STBIR_SIMD_NO_UNROLL_LOOP_START
do {
hc += 4;
decode += STBIR__horizontal_channels * 4;
stbir__4_coeff_continue_from_4( 0 );
--n;
} while ( n > 0 );
- stbir__3_coeff_remnant( 4 );
+ stbir__3_coeff_remnant( 4 );
stbir__store_output();
} while ( output < output_end );
@@ -10216,26 +10485,26 @@ static void STBIR_chans( stbir__horizontal_gather_,_channels_with_n_coeffs_mod3
static stbir__horizontal_gather_channels_func * STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_funcs)[4]=
{
- STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod0),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod1),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod2),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod3),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod0),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod1),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod2),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_n_coeffs_mod3),
};
static stbir__horizontal_gather_channels_func * STBIR_chans(stbir__horizontal_gather_,_channels_funcs)[12]=
{
- STBIR_chans(stbir__horizontal_gather_,_channels_with_1_coeff),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_2_coeffs),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_1_coeff),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_2_coeffs),
STBIR_chans(stbir__horizontal_gather_,_channels_with_3_coeffs),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_4_coeffs),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_5_coeffs),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_6_coeffs),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_4_coeffs),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_5_coeffs),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_6_coeffs),
STBIR_chans(stbir__horizontal_gather_,_channels_with_7_coeffs),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_8_coeffs),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_9_coeffs),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_10_coeffs),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_11_coeffs),
- STBIR_chans(stbir__horizontal_gather_,_channels_with_12_coeffs),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_8_coeffs),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_9_coeffs),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_10_coeffs),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_11_coeffs),
+ STBIR_chans(stbir__horizontal_gather_,_channels_with_12_coeffs),
};
#undef STBIR__horizontal_channels
@@ -10266,38 +10535,38 @@ This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included in all
+The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
-Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
-software, either in source code form or as a compiled binary, for any purpose,
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
-In jurisdictions that recognize copyright laws, the author or authors of this
-software dedicate any and all copyright interest in the software to the public
-domain. We make this dedication for the benefit of the public at large and to
-the detriment of our heirs and successors. We intend this dedication to be an
-overt act of relinquishment in perpetuity of all present and future rights to
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/
diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c
index 7a2162025..88438c9b0 100644
--- a/src/platforms/rcore_android.c
+++ b/src/platforms/rcore_android.c
@@ -74,7 +74,7 @@ typedef struct {
// Global Variables Definition
//----------------------------------------------------------------------------------
extern CoreData CORE; // Global CORE state context
-
+extern bool isGpuReady; // Flag to note GPU has been initialized successfully
static PlatformData platform = { 0 }; // Platform specific data
//----------------------------------------------------------------------------------
@@ -694,16 +694,16 @@ void PollInputEvents(void)
// Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
- // NOTE: Never close window, native activity is controlled by the system!
+ // NOTE: Allow closing the window in case a configuration change happened.
+ // The android_main function should be allowed to return to its caller in order for the
+ // Android OS to relaunch the activity.
if (platform.app->destroyRequested != 0)
{
- //CORE.Window.shouldClose = true;
- //ANativeActivity_finish(platform.app->activity);
+ CORE.Window.shouldClose = true;
}
}
}
-
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
@@ -781,7 +781,7 @@ int InitPlatform(void)
// Process this event
if (platform.source != NULL) platform.source->process(platform.app, platform.source);
- // NOTE: Never close window, native activity is controlled by the system!
+ // NOTE: It's highly likely destroyRequested will never be non-zero at the start of the activity lifecycle.
//if (platform.app->destroyRequested != 0) CORE.Window.shouldClose = true;
}
}
@@ -812,6 +812,12 @@ void ClosePlatform(void)
eglTerminate(platform.device);
platform.device = EGL_NO_DISPLAY;
}
+
+ // NOTE: Reset global state in case the activity is being relaunched.
+ if (platform.app->destroyRequested != 0) {
+ CORE = (CoreData){0};
+ platform = (PlatformData){0};
+ }
}
// Initialize display device and framebuffer
@@ -982,6 +988,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
// Initialize OpenGL context (states and resources)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
+ isGpuReady = true;
// Setup default viewport
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c
index d64bf60db..0bc52ac9e 100644
--- a/src/platforms/rcore_desktop_glfw.c
+++ b/src/platforms/rcore_desktop_glfw.c
@@ -109,6 +109,7 @@ static void ErrorCallback(int error, const char *description);
// Window callbacks events
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
+static void WindowPosCallback(GLFWwindow* window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
static void WindowMaximizeCallback(GLFWwindow* window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
@@ -147,7 +148,7 @@ void ToggleFullscreen(void)
if (!CORE.Window.fullscreen)
{
// Store previous window position (in case we exit fullscreen)
- glfwGetWindowPos(platform.handle, &CORE.Window.position.x, &CORE.Window.position.y);
+ CORE.Window.previousPosition = CORE.Window.position;
int monitorCount = 0;
int monitorIndex = GetCurrentMonitor();
@@ -179,7 +180,11 @@ void ToggleFullscreen(void)
CORE.Window.fullscreen = false;
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
- glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
+ glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
+
+ // we update the window position right away
+ CORE.Window.position.x = CORE.Window.previousPosition.x;
+ CORE.Window.position.y = CORE.Window.previousPosition.y;
}
// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
@@ -190,11 +195,11 @@ void ToggleFullscreen(void)
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
- // Leave fullscreen before attempting to set borderless windowed mode and get screen position from it
+ // Leave fullscreen before attempting to set borderless windowed mode
bool wasOnFullscreen = false;
if (CORE.Window.fullscreen)
{
- CORE.Window.previousPosition = CORE.Window.position;
+ // fullscreen already saves the previous position so it does not need to be set here again
ToggleFullscreen();
wasOnFullscreen = true;
}
@@ -213,7 +218,7 @@ void ToggleBorderlessWindowed(void)
{
// Store screen position and size
// NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here
- if (!wasOnFullscreen) glfwGetWindowPos(platform.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y);
+ if (!wasOnFullscreen) CORE.Window.previousPosition = CORE.Window.position;
CORE.Window.previousScreen = CORE.Window.screen;
// Set undecorated and topmost modes and flags
@@ -255,6 +260,9 @@ void ToggleBorderlessWindowed(void)
glfwFocusWindow(platform.handle);
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
+
+ CORE.Window.position.x = CORE.Window.previousPosition.x;
+ CORE.Window.position.y = CORE.Window.previousPosition.y;
}
}
else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
@@ -592,6 +600,9 @@ void SetWindowTitle(const char *title)
// Set window position on screen (windowed mode)
void SetWindowPosition(int x, int y)
{
+ // Update CORE.Window.position as well
+ CORE.Window.position.x = x;
+ CORE.Window.position.y = y;
glfwSetWindowPos(platform.handle, x, y);
}
@@ -614,8 +625,9 @@ void SetWindowMonitor(int monitor)
{
TRACELOG(LOG_INFO, "GLFW: Selected monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
- const int screenWidth = CORE.Window.screen.width;
- const int screenHeight = CORE.Window.screen.height;
+ // Here the render width has to be used again in case high dpi flag is enabled
+ const int screenWidth = CORE.Window.render.width;
+ const int screenHeight = CORE.Window.render.height;
int monitorWorkareaX = 0;
int monitorWorkareaY = 0;
int monitorWorkareaWidth = 0;
@@ -1222,7 +1234,6 @@ void PollInputEvents(void)
glfwSetWindowShouldClose(platform.handle, GLFW_FALSE);
}
-
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
@@ -1278,7 +1289,7 @@ int InitPlatform(void)
// Disable GlFW auto iconify behaviour
// Auto Iconify automatically minimizes (iconifies) the window if the window loses focus
// additionally auto iconify restores the hardware resolution of the monitor if the window that loses focus is a fullscreen window
- glfwWindowHint(GLFW_AUTO_ICONIFY, 0);
+ glfwWindowHint(GLFW_AUTO_ICONIFY, 0);
// Check window creation flags
if ((CORE.Window.flags & FLAG_FULLSCREEN_MODE) > 0) CORE.Window.fullscreen = true;
@@ -1435,7 +1446,7 @@ int InitPlatform(void)
}
}
- TRACELOG(LOG_WARNING, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
+ TRACELOG(LOG_INFO, "SYSTEM: Closest fullscreen videomode: %i x %i", CORE.Window.display.width, CORE.Window.display.height);
// NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example,
// for a desired screen size of 800x450 (16:9), closest supported videomode is 800x600 (4:3),
@@ -1569,11 +1580,16 @@ int InitPlatform(void)
int monitorHeight = 0;
glfwGetMonitorWorkarea(monitor, &monitorX, &monitorY, &monitorWidth, &monitorHeight);
- int posX = monitorX + (monitorWidth - (int)CORE.Window.screen.width)/2;
- int posY = monitorY + (monitorHeight - (int)CORE.Window.screen.height)/2;
+ // Here CORE.Window.render.width/height should be used instead of CORE.Window.screen.width/height to center the window correctly when the high dpi flag is enabled.
+ int posX = monitorX + (monitorWidth - (int)CORE.Window.render.width)/2;
+ int posY = monitorY + (monitorHeight - (int)CORE.Window.render.height)/2;
if (posX < monitorX) posX = monitorX;
if (posY < monitorY) posY = monitorY;
SetWindowPosition(posX, posY);
+
+ // Update CORE.Window.position here so it is correct from the start
+ CORE.Window.position.x = posX;
+ CORE.Window.position.y = posY;
}
// Load OpenGL extensions
@@ -1585,6 +1601,7 @@ int InitPlatform(void)
//----------------------------------------------------------------------------
// Set window callback events
glfwSetWindowSizeCallback(platform.handle, WindowSizeCallback); // NOTE: Resizing not allowed by default!
+ glfwSetWindowPosCallback(platform.handle, WindowPosCallback);
glfwSetWindowMaximizeCallback(platform.handle, WindowMaximizeCallback);
glfwSetWindowIconifyCallback(platform.handle, WindowIconifyCallback);
glfwSetWindowFocusCallback(platform.handle, WindowFocusCallback);
@@ -1681,7 +1698,12 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
// NOTE: Postprocessing texture is not scaled to new size
}
-
+static void WindowPosCallback(GLFWwindow* window, int x, int y)
+{
+ // Set current window position
+ CORE.Window.position.x = x;
+ CORE.Window.position.y = y;
+}
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley)
{
CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c
index afea0c2e6..20bff2128 100644
--- a/src/platforms/rcore_desktop_rgfw.c
+++ b/src/platforms/rcore_desktop_rgfw.c
@@ -1,6 +1,6 @@
/**********************************************************************************************
*
-* rcore_desktop_rgfw template - Functions to manage window, graphics device and inputs
+* rcore_desktop_rgfw - Functions to manage window, graphics device and inputs
*
* PLATFORM: RGFW
* - Windows (Win32, Win64)
@@ -69,6 +69,7 @@ void CloseWindow(void);
#define CloseWindow CloseWindow_win32
#define ShowCursor __imp_ShowCursor
#define _APISETSTRING_
+ __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
#endif
#if defined(__APPLE__)
@@ -76,10 +77,6 @@ void CloseWindow(void);
#define Size NSSIZE
#endif
-#if defined(_MSC_VER)
-__declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar);
-#endif
-
#include "../external/RGFW.h"
#if defined(__WIN32) || defined(__WIN64)
@@ -291,7 +288,6 @@ void SetWindowState(unsigned int flags)
}
if (flags & FLAG_WINDOW_RESIZABLE)
{
- printf("%i %i\n", platform.window->r.w, platform.window->r.h);
RGFW_window_setMaxSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h));
RGFW_window_setMinSize(platform.window, RGFW_AREA(platform.window->r.w, platform.window->r.h));
}
@@ -538,10 +534,8 @@ void *GetWindowHandle(void)
{
#ifdef RGFW_WEBASM
return (void*)platform.window->src.ctx;
-#elif !defined(RGFW_WINDOWS)
- return (void *)platform.window->src.window;
#else
- return platform.window->src.hwnd;
+ return (void*)platform.window->src.window;
#endif
}
@@ -692,7 +686,7 @@ void DisableCursor(void)
{
RGFW_disableCursor = true;
- RGFW_window_mouseHold(platform.window, RGFW_AREA(CORE.Window.screen.width / 2, CORE.Window.screen.height / 2));
+ RGFW_window_mouseHold(platform.window, RGFW_AREA(0, 0));
HideCursor();
}
@@ -876,9 +870,8 @@ void PollInputEvents(void)
//-----------------------------------------------------------------------------
CORE.Window.resizedLastFrame = false;
-
- #define RGFW_HOLD_MOUSE (1L<<2)
- #if defined(RGFW_X11) //|| defined(RGFW_MACOS)
+ CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
+ #define RGFW_HOLD_MOUSE (1L<<2)
if (platform.window->_winArgs & RGFW_HOLD_MOUSE)
{
CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
@@ -888,11 +881,9 @@ void PollInputEvents(void)
{
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
}
-#endif
while (RGFW_window_checkEvent(platform.window))
{
-
if ((platform.window->event.type >= RGFW_jsButtonPressed) && (platform.window->event.type <= RGFW_jsAxisMove))
{
if (!CORE.Input.Gamepad.ready[platform.window->event.joystick])
@@ -944,7 +935,7 @@ void PollInputEvents(void)
SetupViewport(platform.window->r.w, platform.window->r.h);
CORE.Window.screen.width = platform.window->r.w;
CORE.Window.screen.height = platform.window->r.h;
- CORE.Window.currentFbo.width = platform.window->r.w;;
+ CORE.Window.currentFbo.width = platform.window->r.w;
CORE.Window.currentFbo.height = platform.window->r.h;
CORE.Window.resizedLastFrame = true;
} break;
@@ -1034,15 +1025,8 @@ void PollInputEvents(void)
{
if (platform.window->_winArgs & RGFW_HOLD_MOUSE)
{
- CORE.Input.Mouse.previousPosition = (Vector2){ 0.0f, 0.0f };
-
- if (event->point.x)
- CORE.Input.Mouse.previousPosition.x = CORE.Input.Mouse.currentPosition.x;
- if (event->point.y)
- CORE.Input.Mouse.previousPosition.y = CORE.Input.Mouse.currentPosition.y;
-
- CORE.Input.Mouse.currentPosition.x = (float)event->point.x;
- CORE.Input.Mouse.currentPosition.y = (float)event->point.y;
+ CORE.Input.Mouse.currentPosition.x += (float)event->point.x;
+ CORE.Input.Mouse.currentPosition.y += (float)event->point.y;
}
else
{
@@ -1209,7 +1193,6 @@ void PollInputEvents(void)
//-----------------------------------------------------------------------------
}
-
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
@@ -1266,7 +1249,6 @@ int InitPlatform(void)
*/
SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
-
if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
RGFW_window_makeCurrent(platform.window);
diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c
index 794f9e6a0..b4ceb78eb 100644
--- a/src/platforms/rcore_desktop_sdl.c
+++ b/src/platforms/rcore_desktop_sdl.c
@@ -57,6 +57,13 @@
#include "SDL_opengl.h" // SDL OpenGL functionality (if required, instead of internal renderer)
#endif
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#ifndef MAX_CLIPBOARD_BUFFER_LENGTH
+ #define MAX_CLIPBOARD_BUFFER_LENGTH 1024 // Size of the clipboard buffer used on GetClipboardText()
+#endif
+
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
@@ -852,10 +859,22 @@ void SetClipboardText(const char *text)
}
// Get clipboard text content
-// NOTE: returned string must be freed with SDL_free()
const char *GetClipboardText(void)
{
- return SDL_GetClipboardText();
+ static char buffer[MAX_CLIPBOARD_BUFFER_LENGTH] = { 0 };
+
+ char *clipboard = SDL_GetClipboardText();
+
+ int clipboardSize = snprintf(buffer, sizeof(buffer), "%s", clipboard);
+ if (clipboardSize >= MAX_CLIPBOARD_BUFFER_LENGTH)
+ {
+ char *truncate = buffer + MAX_CLIPBOARD_BUFFER_LENGTH - 4;
+ sprintf(truncate, "...");
+ }
+
+ SDL_free(clipboard);
+
+ return buffer;
}
// Show mouse cursor
@@ -1589,8 +1608,7 @@ int InitPlatform(void)
// Initialize storage system
//----------------------------------------------------------------------------
// Define base path for storage
- CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();
- CHDIR(CORE.Storage.basePath);
+ CORE.Storage.basePath = SDL_GetBasePath(); // Alternative: GetWorkingDirectory();
//----------------------------------------------------------------------------
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP (SDL): Initialized successfully");
diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c
index 291fd93c7..e77457b1b 100644
--- a/src/platforms/rcore_drm.c
+++ b/src/platforms/rcore_drm.c
@@ -206,7 +206,7 @@ static const short linuxToRaylibMap[KEYMAP_SIZE] = {
[BTN_TL] = GAMEPAD_BUTTON_LEFT_TRIGGER_1,
[BTN_TL2] = GAMEPAD_BUTTON_LEFT_TRIGGER_2,
[BTN_TR] = GAMEPAD_BUTTON_RIGHT_TRIGGER_1,
- [BTN_TR2] GAMEPAD_BUTTON_RIGHT_TRIGGER_2,
+ [BTN_TR2] = GAMEPAD_BUTTON_RIGHT_TRIGGER_2,
[BTN_SELECT] = GAMEPAD_BUTTON_MIDDLE_LEFT,
[BTN_MODE] = GAMEPAD_BUTTON_MIDDLE,
[BTN_START] = GAMEPAD_BUTTON_MIDDLE_RIGHT,
@@ -763,8 +763,10 @@ int InitPlatform(void)
drmModeConnector *con = drmModeGetConnector(platform.fd, res->connectors[i]);
TRACELOG(LOG_TRACE, "DISPLAY: Connector modes detected: %i", con->count_modes);
-
- if ((con->connection == DRM_MODE_CONNECTED) && (con->encoder_id))
+
+ // In certain cases the status of the conneciton is reported as UKNOWN, but it is still connected.
+ // This might be a hardware or software limitation like on Raspberry Pi Zero with composite output.
+ if (((con->connection == DRM_MODE_CONNECTED) || (con->connection == DRM_MODE_UNKNOWNCONNECTION)) && (con->encoder_id))
{
TRACELOG(LOG_TRACE, "DISPLAY: DRM mode connected");
platform.connector = con;
@@ -1478,7 +1480,6 @@ static void ConfigureEvdevDevice(char *device)
TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
}
-
if (TEST_BIT(evBits, EV_KEY))
{
// The first 32 keys as defined in input-event-codes.h are pretty much
diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c
index 938f4ed7d..6bc3432eb 100644
--- a/src/platforms/rcore_template.c
+++ b/src/platforms/rcore_template.c
@@ -430,7 +430,6 @@ void PollInputEvents(void)
// TODO: Poll input events for current platform
}
-
//----------------------------------------------------------------------------------
// Module Internal Functions Definition
//----------------------------------------------------------------------------------
diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c
index ff7a92dbc..36af66a47 100644
--- a/src/platforms/rcore_web.c
+++ b/src/platforms/rcore_web.c
@@ -74,6 +74,8 @@
typedef struct {
GLFWwindow *handle; // GLFW window handle (graphic device)
bool ourFullscreen; // Internal var to filter our handling of fullscreen vs the user handling of fullscreen
+ int unmaximizedWidth; // Internal var to store the unmaximized window (canvas) width
+ int unmaximizedHeight; // Internal var to store the unmaximized window (canvas) height
} PlatformData;
//----------------------------------------------------------------------------------
@@ -317,7 +319,18 @@ void ToggleBorderlessWindowed(void)
// Set window state: maximized, if resizable
void MaximizeWindow(void)
{
- TRACELOG(LOG_WARNING, "MaximizeWindow() not available on target platform");
+ if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE && !(CORE.Window.flags & FLAG_WINDOW_MAXIMIZED))
+ {
+ platform.unmaximizedWidth = CORE.Window.screen.width;
+ platform.unmaximizedHeight = CORE.Window.screen.height;
+
+ const int tabWidth = EM_ASM_INT( { return window.innerWidth; }, 0);
+ const int tabHeight = EM_ASM_INT( { return window.innerHeight; }, 0);
+
+ if (tabWidth && tabHeight) glfwSetWindowSize(platform.handle, tabWidth, tabHeight);
+
+ CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
+ }
}
// Set window state: minimized
@@ -329,7 +342,12 @@ void MinimizeWindow(void)
// Set window state: not minimized/maximized
void RestoreWindow(void)
{
- TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform");
+ if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE && (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED))
+ {
+ if (platform.unmaximizedWidth && platform.unmaximizedHeight) glfwSetWindowSize(platform.handle, platform.unmaximizedWidth, platform.unmaximizedHeight);
+
+ CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
+ }
}
// Set window configuration state using flags
@@ -398,9 +416,20 @@ void SetWindowState(unsigned int flags)
}
// State change: FLAG_WINDOW_MAXIMIZED
- if ((flags & FLAG_WINDOW_MAXIMIZED) > 0)
+ if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) != (flags & FLAG_WINDOW_MAXIMIZED)) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0))
{
- TRACELOG(LOG_WARNING, "SetWindowState(FLAG_WINDOW_MAXIMIZED) not available on target platform");
+ if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
+ {
+ platform.unmaximizedWidth = CORE.Window.screen.width;
+ platform.unmaximizedHeight = CORE.Window.screen.height;
+
+ const int tabWidth = EM_ASM_INT( { return window.innerWidth; }, 0);
+ const int tabHeight = EM_ASM_INT( { return window.innerHeight; }, 0);
+
+ if (tabWidth && tabHeight) glfwSetWindowSize(platform.handle, tabWidth, tabHeight);
+
+ CORE.Window.flags |= FLAG_WINDOW_MAXIMIZED;
+ }
}
// State change: FLAG_WINDOW_UNFOCUSED
@@ -516,9 +545,14 @@ void ClearWindowState(unsigned int flags)
}
// State change: FLAG_WINDOW_MAXIMIZED
- if ((flags & FLAG_WINDOW_MAXIMIZED) > 0)
+ if (((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0) && ((flags & FLAG_WINDOW_MAXIMIZED) > 0))
{
- TRACELOG(LOG_WARNING, "ClearWindowState(FLAG_WINDOW_MAXIMIZED) not available on target platform");
+ if (glfwGetWindowAttrib(platform.handle, GLFW_RESIZABLE) == GLFW_TRUE)
+ {
+ if (platform.unmaximizedWidth && platform.unmaximizedHeight) glfwSetWindowSize(platform.handle, platform.unmaximizedWidth, platform.unmaximizedHeight);
+
+ CORE.Window.flags &= ~FLAG_WINDOW_MAXIMIZED;
+ }
}
// State change: FLAG_WINDOW_UNDECORATED
@@ -639,7 +673,9 @@ void SetWindowSize(int width, int height)
// Set window opacity, value opacity is between 0.0 and 1.0
void SetWindowOpacity(float opacity)
{
- TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform");
+ if (opacity >= 1.0f) opacity = 1.0f;
+ else if (opacity <= 0.0f) opacity = 0.0f;
+ EM_ASM({ document.getElementById('canvas').style.opacity = $0; }, opacity);
}
// Set window focused
@@ -935,7 +971,6 @@ void PollInputEvents(void)
// so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed!
//for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 };
-
// Gamepad support using emscripten API
// NOTE: GLFW3 joystick functionality not available in web
diff --git a/src/raudio.c b/src/raudio.c
index 79d53b565..15859a661 100644
--- a/src/raudio.c
+++ b/src/raudio.c
@@ -892,8 +892,8 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int
return wave;
}
-// Checks if wave data is ready
-bool IsWaveReady(Wave wave)
+// Checks if wave data is valid (data loaded and parameters)
+bool IsWaveValid(Wave wave)
{
bool result = false;
@@ -993,8 +993,8 @@ Sound LoadSoundAlias(Sound source)
}
-// Checks if a sound is ready
-bool IsSoundReady(Sound sound)
+// Checks if a sound is valid (data loaded and buffers initialized)
+bool IsSoundValid(Sound sound)
{
bool result = false;
@@ -1726,8 +1726,8 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
return music;
}
-// Checks if a music stream is ready
-bool IsMusicReady(Music music)
+// Checks if a music stream is valid (context and buffers initialized)
+bool IsMusicValid(Music music)
{
return ((music.ctxData != NULL) && // Validate context loaded
(music.frameCount > 0) && // Validate audio frame count
@@ -2119,8 +2119,8 @@ AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
return stream;
}
-// Checks if an audio stream is ready
-bool IsAudioStreamReady(AudioStream stream)
+// Checks if an audio stream is valid (buffers initialized)
+bool IsAudioStreamValid(AudioStream stream)
{
return ((stream.buffer != NULL) && // Validate stream buffer
(stream.sampleRate > 0) && // Validate sample rate is supported
diff --git a/src/raylib.h b/src/raylib.h
index 0759c259f..25ee6943f 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -352,8 +352,10 @@ typedef struct Mesh {
// Animation vertex data
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)
- float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning)
+ 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
@@ -790,7 +792,10 @@ typedef enum {
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_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
} ShaderLocationIndex;
#define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO
@@ -968,8 +973,8 @@ RLAPI bool IsWindowResized(void); // Check if wi
RLAPI bool IsWindowState(unsigned int flag); // Check if one specific window flag is enabled
RLAPI void SetWindowState(unsigned int flags); // Set window configuration state using flags (only PLATFORM_DESKTOP)
RLAPI void ClearWindowState(unsigned int flags); // Clear window configuration state flags
-RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)
-RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed (only PLATFORM_DESKTOP)
+RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed [resizes monitor to match window resolution] (only PLATFORM_DESKTOP)
+RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed [resizes window to match monitor resolution] (only PLATFORM_DESKTOP)
RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP)
RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable (only PLATFORM_DESKTOP)
RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized (only PLATFORM_DESKTOP)
@@ -1039,7 +1044,7 @@ RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR s
// NOTE: Shader functionality is not available on OpenGL 1.1
RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
-RLAPI bool IsShaderReady(Shader shader); // Check if a shader is ready
+RLAPI bool IsShaderValid(Shader shader); // Check if a shader is valid (loaded on GPU)
RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location
RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value
@@ -1122,11 +1127,12 @@ RLAPI const char *GetDirectoryPath(const char *filePath); // Get full pa
RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string)
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 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
+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 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
@@ -1138,6 +1144,10 @@ RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *
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, memory must be MemFree()
RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, 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)
+
// Automation events functionality
RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS
@@ -1205,7 +1215,7 @@ RLAPI int GetTouchPointCount(void); // Get number of t
RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags
RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture have been detected
RLAPI int GetGestureDetected(void); // Get latest detected gesture
-RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds
+RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in seconds
RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector
RLAPI float GetGestureDragAngle(void); // Get gesture drag angle
RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta
@@ -1228,8 +1238,8 @@ RLAPI Texture2D GetShapesTexture(void); // Get t
RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source rectangle that is used for shapes drawing
// Basic shapes drawing functions
-RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel
-RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version)
+RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel using geometry [Can be slow, use with care]
+RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel using geometry (Vector version) [Can be slow, use with care]
RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line
RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines)
RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads)
@@ -1306,13 +1316,12 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2);
// NOTE: These functions do not require GPU access
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
-RLAPI Image LoadImageSvg(const char *fileNameOrString, int width, int height); // Load image from SVG file data or string with specified size
RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data)
RLAPI Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames); // Load image sequence from memory buffer
RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png'
RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data
RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer and (screenshot)
-RLAPI bool IsImageReady(Image image); // Check if an image is ready
+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
@@ -1398,9 +1407,9 @@ RLAPI Texture2D LoadTexture(const char *fileName);
RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data
RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout); // Load cubemap from image, multiple image cubemap layouts supported
RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer)
-RLAPI bool IsTextureReady(Texture2D texture); // Check if a texture is ready
+RLAPI bool IsTextureValid(Texture2D texture); // Check if a texture is valid (loaded in GPU)
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
-RLAPI bool IsRenderTextureReady(RenderTexture2D target); // Check if a render texture is ready
+RLAPI bool IsRenderTextureValid(RenderTexture2D target); // Check if a render texture is valid (loaded in GPU)
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data
@@ -1431,6 +1440,7 @@ RLAPI Color ColorBrightness(Color color, float factor); // G
RLAPI Color ColorContrast(Color color, float contrast); // Get color with contrast correction, contrast values between -1.0f and 1.0f
RLAPI Color ColorAlpha(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f
RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Get src alpha-blended into dst color with tint
+RLAPI Color ColorLerp(Color color1, Color color2, float factor); // Get color lerp interpolation between two colors, factor [0.0f..1.0f]
RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value
RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format
RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer
@@ -1443,10 +1453,10 @@ RLAPI int GetPixelDataSize(int width, int height, int format); // G
// Font loading/unloading functions
RLAPI Font GetFontDefault(void); // Get the default Font
RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM)
-RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set
+RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height
RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style)
RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
-RLAPI bool IsFontReady(Font font); // Check if a font is ready
+RLAPI bool IsFontValid(Font font); // Check if a font is valid (font data loaded, WARNING: GPU texture not checked)
RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type); // Load font data for further use
RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM)
@@ -1536,7 +1546,7 @@ RLAPI void DrawGrid(int slices, float spacing);
// Model management functions
RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials)
RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material)
-RLAPI bool IsModelReady(Model model); // Check if a model is ready
+RLAPI bool IsModelValid(Model model); // Check if a model is valid (loaded in GPU, VAO/VBOs)
RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM)
RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes)
@@ -1545,6 +1555,8 @@ 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
@@ -1577,7 +1589,7 @@ RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
// Material loading/unloading functions
RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file
RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
-RLAPI bool IsMaterialReady(Material material); // Check if a material is ready
+RLAPI bool IsMaterialValid(Material material); // Check if a material is valid (shader assigned, map textures loaded in GPU)
RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM)
RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh
@@ -1588,6 +1600,7 @@ RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame);
RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data
RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data
RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match
+RLAPI void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int frame); // Update model animation mesh bone matrices (Note GPU skinning does not work on Mac)
// Collision detection functions
RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres
@@ -1614,11 +1627,11 @@ RLAPI float GetMasterVolume(void); // Get mas
// Wave/Sound loading/unloading functions
RLAPI Wave LoadWave(const char *fileName); // Load wave data from file
RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav'
-RLAPI bool IsWaveReady(Wave wave); // Checks if wave data is ready
+RLAPI bool IsWaveValid(Wave wave); // Checks if wave data is valid (data loaded and parameters)
RLAPI Sound LoadSound(const char *fileName); // Load sound from file
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 IsSoundReady(Sound sound); // Checks if a sound is ready
+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
RLAPI void UnloadWave(Wave wave); // Unload wave data
RLAPI void UnloadSound(Sound sound); // Unload sound
@@ -1644,7 +1657,7 @@ RLAPI void UnloadWaveSamples(float *samples); // Unload
// Music management functions
RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file
RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data
-RLAPI bool IsMusicReady(Music music); // Checks if a music stream is ready
+RLAPI bool IsMusicValid(Music music); // Checks if a music stream is valid (context and buffers initialized)
RLAPI void UnloadMusicStream(Music music); // Unload music stream
RLAPI void PlayMusicStream(Music music); // Start music playing
RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing
@@ -1661,7 +1674,7 @@ RLAPI float GetMusicTimePlayed(Music music); // Get cur
// AudioStream management functions
RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data)
-RLAPI bool IsAudioStreamReady(AudioStream stream); // Checks if an audio stream is ready
+RLAPI bool IsAudioStreamValid(AudioStream stream); // Checks if an audio stream is valid (buffers initialized)
RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory
RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data
RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
diff --git a/src/raymath.h b/src/raymath.h
index 62d52f8fd..d1b5ab01e 100644
--- a/src/raymath.h
+++ b/src/raymath.h
@@ -1,6 +1,6 @@
/**********************************************************************************************
*
-* raymath v1.5 - Math functions to work with Vector2, Vector3, Matrix and Quaternions
+* raymath v2.0 - Math functions to work with Vector2, Vector3, Matrix and Quaternions
*
* CONVENTIONS:
* - Matrix structure is defined as row-major (memory layout) but parameters naming AND all
@@ -12,7 +12,7 @@
* - Functions are always self-contained, no function use another raymath function inside,
* required code is directly re-implemented inside
* - Functions input parameters are always received by value (2 unavoidable exceptions)
-* - Functions use always a "result" variable for return
+* - Functions use always a "result" variable for return (except C++ operators)
* - Functions are always defined inline
* - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience)
* - No compound literals used to make sure libray is compatible with C++
@@ -27,6 +27,8 @@
* 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.
*
* LICENSE: zlib/libpng
*
@@ -2580,4 +2582,354 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio
}
}
+#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS)
+
+// Optional C++ math operators
+//-------------------------------------------------------------------------------
+
+// Vector2 operators
+static constexpr Vector2 Vector2Zeros = { 0, 0 };
+static constexpr Vector2 Vector2Ones = { 1, 1 };
+static constexpr Vector2 Vector2UnitX = { 1, 0 };
+static constexpr Vector2 Vector2UnitY = { 0, 1 };
+
+inline Vector2 operator + (const Vector2& lhs, const Vector2& rhs)
+{
+ return Vector2Add(lhs, rhs);
+}
+
+inline const Vector2& operator += (Vector2& lhs, const Vector2& rhs)
+{
+ lhs = Vector2Add(lhs, rhs);
+ return lhs;
+}
+
+inline Vector2 operator - (const Vector2& lhs, const Vector2& rhs)
+{
+ return Vector2Subtract(lhs, rhs);
+}
+
+inline const Vector2& operator -= (Vector2& lhs, const Vector2& rhs)
+{
+ lhs = Vector2Subtract(lhs, rhs);
+ return lhs;
+}
+
+inline Vector2 operator * (const Vector2& lhs, const float& rhs)
+{
+ return Vector2Scale(lhs, rhs);
+}
+
+inline const Vector2& operator *= (Vector2& lhs, const float& rhs)
+{
+ lhs = Vector2Scale(lhs, rhs);
+ return lhs;
+}
+
+inline Vector2 operator * (const Vector2& lhs, const Vector2& rhs)
+{
+ return Vector2Multiply(lhs, rhs);
+}
+
+inline const Vector2& operator *= (Vector2& lhs, const Vector2& rhs)
+{
+ lhs = Vector2Multiply(lhs, rhs);
+ return lhs;
+}
+
+inline Vector2 operator * (const Vector2& lhs, const Matrix& rhs)
+{
+ return Vector2Transform(lhs, rhs);
+}
+
+inline const Vector2& operator -= (Vector2& lhs, const Matrix& rhs)
+{
+ lhs = Vector2Transform(lhs, rhs);
+ return lhs;
+}
+
+inline Vector2 operator / (const Vector2& lhs, const float& rhs)
+{
+ return Vector2Scale(lhs, 1.0f / rhs);
+}
+
+inline const Vector2& operator /= (Vector2& lhs, const float& rhs)
+{
+ lhs = Vector2Scale(lhs, rhs);
+ return lhs;
+}
+
+inline Vector2 operator / (const Vector2& lhs, const Vector2& rhs)
+{
+ return Vector2Divide(lhs, rhs);
+}
+
+inline const Vector2& operator /= (Vector2& lhs, const Vector2& rhs)
+{
+ lhs = Vector2Divide(lhs, rhs);
+ return lhs;
+}
+
+inline bool operator == (const Vector2& lhs, const Vector2& rhs)
+{
+ return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y);
+}
+
+inline bool operator != (const Vector2& lhs, const Vector2& rhs)
+{
+ return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y);
+}
+
+// Vector3 operators
+static constexpr Vector3 Vector3Zeros = { 0, 0, 0 };
+static constexpr Vector3 Vector3Ones = { 1, 1, 1 };
+static constexpr Vector3 Vector3UnitX = { 1, 0, 0 };
+static constexpr Vector3 Vector3UnitY = { 0, 1, 0 };
+static constexpr Vector3 Vector3UnitZ = { 0, 0, 1 };
+
+inline Vector3 operator + (const Vector3& lhs, const Vector3& rhs)
+{
+ return Vector3Add(lhs, rhs);
+}
+
+inline const Vector3& operator += (Vector3& lhs, const Vector3& rhs)
+{
+ lhs = Vector3Add(lhs, rhs);
+ return lhs;
+}
+
+inline Vector3 operator - (const Vector3& lhs, const Vector3& rhs)
+{
+ return Vector3Subtract(lhs, rhs);
+}
+
+inline const Vector3& operator -= (Vector3& lhs, const Vector3& rhs)
+{
+ lhs = Vector3Subtract(lhs, rhs);
+ return lhs;
+}
+
+inline Vector3 operator * (const Vector3& lhs, const float& rhs)
+{
+ return Vector3Scale(lhs, rhs);
+}
+
+inline const Vector3& operator *= (Vector3& lhs, const float& rhs)
+{
+ lhs = Vector3Scale(lhs, rhs);
+ return lhs;
+}
+
+inline Vector3 operator * (const Vector3& lhs, const Vector3& rhs)
+{
+ return Vector3Multiply(lhs, rhs);
+}
+
+inline const Vector3& operator *= (Vector3& lhs, const Vector3& rhs)
+{
+ lhs = Vector3Multiply(lhs, rhs);
+ return lhs;
+}
+
+inline Vector3 operator * (const Vector3& lhs, const Matrix& rhs)
+{
+ return Vector3Transform(lhs, rhs);
+}
+
+inline const Vector3& operator -= (Vector3& lhs, const Matrix& rhs)
+{
+ lhs = Vector3Transform(lhs, rhs);
+ return lhs;
+}
+
+inline Vector3 operator / (const Vector3& lhs, const float& rhs)
+{
+ return Vector3Scale(lhs, 1.0f / rhs);
+}
+
+inline const Vector3& operator /= (Vector3& lhs, const float& rhs)
+{
+ lhs = Vector3Scale(lhs, rhs);
+ return lhs;
+}
+
+inline Vector3 operator / (const Vector3& lhs, const Vector3& rhs)
+{
+ return Vector3Divide(lhs, rhs);
+}
+
+inline const Vector3& operator /= (Vector3& lhs, const Vector3& rhs)
+{
+ lhs = Vector3Divide(lhs, rhs);
+ return lhs;
+}
+
+inline bool operator == (const Vector3& lhs, const Vector3& rhs)
+{
+ return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z);
+}
+
+inline bool operator != (const Vector3& lhs, const Vector3& rhs)
+{
+ return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z);
+}
+
+// Vector4 operators
+static constexpr Vector4 Vector4Zeros = { 0, 0, 0, 0 };
+static constexpr Vector4 Vector4Ones = { 1, 1, 1, 1 };
+static constexpr Vector4 Vector4UnitX = { 1, 0, 0, 0 };
+static constexpr Vector4 Vector4UnitY = { 0, 1, 0, 0 };
+static constexpr Vector4 Vector4UnitZ = { 0, 0, 1, 0 };
+static constexpr Vector4 Vector4UnitW = { 0, 0, 0, 1 };
+
+inline Vector4 operator + (const Vector4& lhs, const Vector4& rhs)
+{
+ return Vector4Add(lhs, rhs);
+}
+
+inline const Vector4& operator += (Vector4& lhs, const Vector4& rhs)
+{
+ lhs = Vector4Add(lhs, rhs);
+ return lhs;
+}
+
+inline Vector4 operator - (const Vector4& lhs, const Vector4& rhs)
+{
+ return Vector4Subtract(lhs, rhs);
+}
+
+inline const Vector4& operator -= (Vector4& lhs, const Vector4& rhs)
+{
+ lhs = Vector4Subtract(lhs, rhs);
+ return lhs;
+}
+
+inline Vector4 operator * (const Vector4& lhs, const float& rhs)
+{
+ return Vector4Scale(lhs, rhs);
+}
+
+inline const Vector4& operator *= (Vector4& lhs, const float& rhs)
+{
+ lhs = Vector4Scale(lhs, rhs);
+ return lhs;
+}
+
+inline Vector4 operator * (const Vector4& lhs, const Vector4& rhs)
+{
+ return Vector4Multiply(lhs, rhs);
+}
+
+inline const Vector4& operator *= (Vector4& lhs, const Vector4& rhs)
+{
+ lhs = Vector4Multiply(lhs, rhs);
+ return lhs;
+}
+
+inline Vector4 operator / (const Vector4& lhs, const float& rhs)
+{
+ return Vector4Scale(lhs, 1.0f / rhs);
+}
+
+inline const Vector4& operator /= (Vector4& lhs, const float& rhs)
+{
+ lhs = Vector4Scale(lhs, rhs);
+ return lhs;
+}
+
+inline Vector4 operator / (const Vector4& lhs, const Vector4& rhs)
+{
+ return Vector4Divide(lhs, rhs);
+}
+
+inline const Vector4& operator /= (Vector4& lhs, const Vector4& rhs)
+{
+ lhs = Vector4Divide(lhs, rhs);
+ return lhs;
+}
+
+inline bool operator == (const Vector4& lhs, const Vector4& rhs)
+{
+ return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z) && FloatEquals(lhs.w, rhs.w);
+}
+
+inline bool operator != (const Vector4& lhs, const Vector4& rhs)
+{
+ return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z) || !FloatEquals(lhs.w, rhs.w);
+}
+
+// Quaternion operators
+static constexpr Quaternion QuaternionZeros = { 0, 0, 0, 0 };
+static constexpr Quaternion QuaternionOnes = { 1, 1, 1, 1 };
+static constexpr Quaternion QuaternionUnitX = { 0, 0, 0, 1 };
+
+inline Quaternion operator + (const Quaternion& lhs, const float& rhs)
+{
+ return QuaternionAddValue(lhs, rhs);
+}
+
+inline const Quaternion& operator += (Quaternion& lhs, const float& rhs)
+{
+ lhs = QuaternionAddValue(lhs, rhs);
+ return lhs;
+}
+
+inline Quaternion operator - (const Quaternion& lhs, const float& rhs)
+{
+ return QuaternionSubtractValue(lhs, rhs);
+}
+
+inline const Quaternion& operator -= (Quaternion& lhs, const float& rhs)
+{
+ lhs = QuaternionSubtractValue(lhs, rhs);
+ return lhs;
+}
+
+inline Quaternion operator * (const Quaternion& lhs, const Matrix& rhs)
+{
+ return QuaternionTransform(lhs, rhs);
+}
+
+inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs)
+{
+ lhs = QuaternionTransform(lhs, rhs);
+ return lhs;
+}
+
+// Matrix operators
+inline Matrix operator + (const Matrix& lhs, const Matrix& rhs)
+{
+ return MatrixAdd(lhs, rhs);
+}
+
+inline const Matrix& operator += (Matrix& lhs, const Matrix& rhs)
+{
+ lhs = MatrixAdd(lhs, rhs);
+ return lhs;
+}
+
+inline Matrix operator - (const Matrix& lhs, const Matrix& rhs)
+{
+ return MatrixSubtract(lhs, rhs);
+}
+
+inline const Matrix& operator -= (Matrix& lhs, const Matrix& rhs)
+{
+ lhs = MatrixSubtract(lhs, rhs);
+ return lhs;
+}
+
+inline Matrix operator * (const Matrix& lhs, const Matrix& rhs)
+{
+ return MatrixMultiply(lhs, rhs);
+}
+
+inline const Matrix& operator *= (Matrix& lhs, const Matrix& rhs)
+{
+ lhs = MatrixMultiply(lhs, rhs);
+ return lhs;
+}
+//-------------------------------------------------------------------------------
+#endif // C++ operators
+
#endif // RAYMATH_H
diff --git a/src/rcamera.h b/src/rcamera.h
index c7f6fed3a..bd2b36e03 100644
--- a/src/rcamera.h
+++ b/src/rcamera.h
@@ -162,7 +162,6 @@ RLAPI Matrix GetCameraProjectionMatrix(Camera* camera, float aspect);
#endif // RCAMERA_H
-
/***********************************************************************************
*
* CAMERA IMPLEMENTATION
@@ -444,11 +443,17 @@ void UpdateCamera(Camera *camera, int mode)
bool lockView = ((mode == CAMERA_FREE) || (mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL));
bool rotateUp = false;
+ // Camera speeds based on frame time
+ float cameraMoveSpeed = CAMERA_MOVE_SPEED*GetFrameTime();
+ float cameraRotationSpeed = CAMERA_ROTATION_SPEED*GetFrameTime();
+ float cameraPanSpeed = CAMERA_PAN_SPEED*GetFrameTime();
+ float cameraOrbitalSpeed = CAMERA_ORBITAL_SPEED*GetFrameTime();
+
if (mode == CAMERA_CUSTOM) {}
else if (mode == CAMERA_ORBITAL)
{
// Orbital can just orbit
- Matrix rotation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED*GetFrameTime());
+ Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed);
Vector3 view = Vector3Subtract(camera->position, camera->target);
view = Vector3Transform(view, rotation);
camera->position = Vector3Add(camera->target, view);
@@ -456,22 +461,22 @@ void UpdateCamera(Camera *camera, int mode)
else
{
// Camera rotation
- if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);
- if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);
- if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget);
- if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget);
- if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED);
- if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED);
+ if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp);
+ if (IsKeyDown(KEY_UP)) CameraPitch(camera, cameraRotationSpeed, lockView, rotateAroundTarget, rotateUp);
+ if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -cameraRotationSpeed, rotateAroundTarget);
+ if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, cameraRotationSpeed, rotateAroundTarget);
+ if (IsKeyDown(KEY_Q)) CameraRoll(camera, -cameraRotationSpeed);
+ if (IsKeyDown(KEY_E)) CameraRoll(camera, cameraRotationSpeed);
// Camera movement
// Camera pan (for CAMERA_FREE)
if ((mode == CAMERA_FREE) && (IsMouseButtonDown(MOUSE_BUTTON_MIDDLE)))
{
const Vector2 mouseDelta = GetMouseDelta();
- if (mouseDelta.x > 0.0f) CameraMoveRight(camera, CAMERA_PAN_SPEED, moveInWorldPlane);
- if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -CAMERA_PAN_SPEED, moveInWorldPlane);
- if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -CAMERA_PAN_SPEED);
- if (mouseDelta.y < 0.0f) CameraMoveUp(camera, CAMERA_PAN_SPEED);
+ if (mouseDelta.x > 0.0f) CameraMoveRight(camera, cameraPanSpeed, moveInWorldPlane);
+ if (mouseDelta.x < 0.0f) CameraMoveRight(camera, -cameraPanSpeed, moveInWorldPlane);
+ if (mouseDelta.y > 0.0f) CameraMoveUp(camera, -cameraPanSpeed);
+ if (mouseDelta.y < 0.0f) CameraMoveUp(camera, cameraPanSpeed);
}
else
{
@@ -481,7 +486,6 @@ void UpdateCamera(Camera *camera, int mode)
}
// Keyboard support
- float cameraMoveSpeed = CAMERA_MOVE_SPEED*GetFrameTime();
if (IsKeyDown(KEY_W)) CameraMoveForward(camera, cameraMoveSpeed, moveInWorldPlane);
if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -cameraMoveSpeed, moveInWorldPlane);
if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -cameraMoveSpeed, moveInWorldPlane);
diff --git a/src/rcore.c b/src/rcore.c
index e8041ea41..a1771d18e 100644
--- a/src/rcore.c
+++ b/src/rcore.c
@@ -165,6 +165,10 @@ unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod);
unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
#elif defined(__linux__)
#include
+#elif defined(__FreeBSD__)
+ #include
+ #include
+ #include
#elif defined(__APPLE__)
#include
#include
@@ -187,14 +191,16 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
#endif
#if defined(_WIN32)
- #include // Required for: _getch(), _chdir()
+ #include // Required for: _access() [Used in FileExists()]
+ #include // Required for: _getch(), _chdir(), _mkdir()
#define GETCWD _getcwd // NOTE: MSDN recommends not to use getcwd(), chdir()
#define CHDIR _chdir
- #include // Required for: _access() [Used in FileExists()]
+ #define MKDIR(dir) _mkdir(dir)
#else
- #include // Required for: getch(), chdir() (POSIX), access()
+ #include // Required for: getch(), chdir(), mkdir(), access()
#define GETCWD getcwd
#define CHDIR chdir
+ #define MKDIR(dir) mkdir(dir, 0777)
#endif
//----------------------------------------------------------------------------------
@@ -247,6 +253,10 @@ unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
#define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record
#endif
+#ifndef DIRECTORY_FILTER_TAG
+ #define DIRECTORY_FILTER_TAG "DIR" // Name tag used to request directory inclusion on directory scan
+#endif // NOTE: Used in ScanDirectoryFiles(), ScanDirectoryFilesRecursively() and LoadDirectoryFilesEx()
+
// Flags operation macros
#define FLAG_SET(n, f) ((n) |= (f))
#define FLAG_CLEAR(n, f) ((n) &= ~(f))
@@ -360,10 +370,15 @@ typedef struct CoreData {
//----------------------------------------------------------------------------------
RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported symbol, required for some bindings
-CoreData CORE = { 0 }; // Global CORE state context
+CoreData CORE = { 0 }; // Global CORE state context
+
+// Flag to note GPU acceleration is available,
+// referenced from other modules to support GPU data loading
+// NOTE: Useful to allow Texture, RenderTexture, Font.texture, Mesh.vaoId/vboId, Shader loading
+bool isGpuReady = false;
#if defined(SUPPORT_SCREEN_CAPTURE)
-static int screenshotCounter = 0; // Screenshots counter
+static int screenshotCounter = 0; // Screenshots counter
#endif
#if defined(SUPPORT_GIF_RECORDING)
@@ -563,7 +578,6 @@ const char *TextFormat(const char *text, ...); // Formatting of tex
//void DisableCursor(void)
// Initialize window and OpenGL context
-// NOTE: data parameter could be used to pass any kind of required data to the initialization
void InitWindow(int width, int height, const char *title)
{
TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION);
@@ -637,28 +651,31 @@ void InitWindow(int width, int height, const char *title)
// Initialize rlgl default data (buffers and shaders)
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
+ isGpuReady = true; // Flag to note GPU has been initialized successfully
// Setup default viewport
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
-#if defined(SUPPORT_MODULE_RTEXT) && defined(SUPPORT_DEFAULT_FONT)
- // Load default font
- // WARNING: External function: Module required: rtext
- LoadFontDefault();
- #if defined(SUPPORT_MODULE_RSHAPES)
- // Set font white rectangle for shapes drawing, so shapes and text can be batched together
- // WARNING: rshapes module is required, if not available, default internal white rectangle is used
- Rectangle rec = GetFontDefault().recs[95];
- if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
- {
- // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
- SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
- }
- else
- {
- // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
- SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
- }
+#if defined(SUPPORT_MODULE_RTEXT)
+ #if defined(SUPPORT_DEFAULT_FONT)
+ // Load default font
+ // WARNING: External function: Module required: rtext
+ LoadFontDefault();
+ #if defined(SUPPORT_MODULE_RSHAPES)
+ // Set font white rectangle for shapes drawing, so shapes and text can be batched together
+ // WARNING: rshapes module is required, if not available, default internal white rectangle is used
+ Rectangle rec = GetFontDefault().recs[95];
+ if (CORE.Window.flags & FLAG_MSAA_4X_HINT)
+ {
+ // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering
+ SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 2, rec.y + 2, 1, 1 });
+ }
+ else
+ {
+ // NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding
+ SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 });
+ }
+ #endif
#endif
#else
#if defined(SUPPORT_MODULE_RSHAPES)
@@ -674,7 +691,7 @@ void InitWindow(int width, int height, const char *title)
// Initialize random seed
SetRandomSeed((unsigned int)time(NULL));
-
+
TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", GetWorkingDirectory());
}
@@ -1287,6 +1304,8 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
// vertex color location = 3
// vertex tangent location = 4
// vertex texcoord2 location = 5
+ // vertex boneIds location = 6
+ // vertex boneWeights location = 7
// NOTE: If any location is not found, loc point becomes -1
@@ -1302,6 +1321,8 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
shader.locs[SHADER_LOC_VERTEX_NORMAL] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL);
shader.locs[SHADER_LOC_VERTEX_TANGENT] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT);
shader.locs[SHADER_LOC_VERTEX_COLOR] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR);
+ shader.locs[SHADER_LOC_VERTEX_BONEIDS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEIDS);
+ shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS);
// Get handles to GLSL uniform locations (vertex shader)
shader.locs[SHADER_LOC_MATRIX_MVP] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MVP);
@@ -1309,6 +1330,7 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
shader.locs[SHADER_LOC_MATRIX_PROJECTION] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION);
shader.locs[SHADER_LOC_MATRIX_MODEL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL);
shader.locs[SHADER_LOC_MATRIX_NORMAL] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL);
+ shader.locs[SHADER_LOC_BONE_MATRICES] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_BONE_MATRICES);
// Get handles to GLSL uniform locations (fragment shader)
shader.locs[SHADER_LOC_COLOR_DIFFUSE] = rlGetLocationUniform(shader.id, RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR);
@@ -1320,10 +1342,10 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
return shader;
}
-// Check if a shader is ready
-bool IsShaderReady(Shader shader)
+// Check if a shader is valid (loaded on GPU)
+bool IsShaderValid(Shader shader)
{
- return ((shader.id > 0) && // Validate shader id (loaded successfully)
+ return ((shader.id > 0) && // Validate shader id (GPU loaded successfully)
(shader.locs != NULL)); // Validate memory has been allocated for default shader locations
// The following locations are tried to be set automatically (locs[i] >= 0),
@@ -2153,6 +2175,28 @@ const char *GetApplicationDirectory(void)
appDir[0] = '.';
appDir[1] = '/';
}
+#elif defined(__FreeBSD__)
+ size_t size = sizeof(appDir);
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+
+ if (sysctl(mib, 4, appDir, &size, NULL, 0) == 0)
+ {
+ int len = strlen(appDir);
+ for (int i = len; i >= 0; --i)
+ {
+ if (appDir[i] == '/')
+ {
+ appDir[i + 1] = '\0';
+ break;
+ }
+ }
+ }
+ else
+ {
+ appDir[0] = '.';
+ appDir[1] = '/';
+ }
+
#endif
return appDir;
@@ -2224,6 +2268,40 @@ void UnloadDirectoryFiles(FilePathList files)
RL_FREE(files.paths);
}
+// Create directories (including full path requested), returns 0 on success
+int MakeDirectory(const char *dirPath)
+{
+ if ((dirPath == NULL) || (dirPath[0] == '\0')) return 1; // Path is not valid
+ if (DirectoryExists(dirPath)) return 0; // Path already exists (is valid)
+
+ // Copy path string to avoid modifying original
+ int len = (int)strlen(dirPath) + 1;
+ char *pathcpy = (char *)RL_CALLOC(len, 1);
+ memcpy(pathcpy, dirPath, len);
+
+ // Iterate over pathcpy, create each subdirectory as needed
+ for (int i = 0; (i < len) && (pathcpy[i] != '\0'); i++)
+ {
+ if (pathcpy[i] == ':') i++;
+ else
+ {
+ if ((pathcpy[i] == '\\') || (pathcpy[i] == '/'))
+ {
+ pathcpy[i] = '\0';
+ if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);
+ pathcpy[i] = '/';
+ }
+ }
+ }
+
+ // Create final directory
+ if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);
+
+ RL_FREE(pathcpy);
+
+ return 0;
+}
+
// Change working directory, returns true on success
bool ChangeDirectory(const char *dir)
{
@@ -2499,6 +2577,265 @@ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
return decodedData;
}
+// Compute CRC32 hash code
+unsigned int ComputeCRC32(unsigned char *data, int dataSize)
+{
+ static unsigned int crcTable[256] = {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+ };
+
+ unsigned int crc = ~0u;
+
+ for (int i = 0; i < dataSize; i++) crc = (crc >> 8) ^ crcTable[data[i] ^ (crc & 0xff)];
+
+ return ~crc;
+}
+
+// Compute MD5 hash code
+// NOTE: Returns a static int[4] array (16 bytes)
+unsigned int *ComputeMD5(unsigned char *data, int dataSize)
+{
+ #define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
+
+ static unsigned int hash[4] = { 0 }; // Hash to be returned
+
+ // WARNING: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating
+
+ // NOTE: r specifies the per-round shift amounts
+ unsigned int r[] = {
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+ 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
+ 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+ 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
+ };
+
+ // Using binary integer part of the sines of integers (in radians) as constants
+ unsigned int k[] = {
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+ };
+
+ hash[0] = 0x67452301;
+ hash[1] = 0xefcdab89;
+ hash[2] = 0x98badcfe;
+ hash[3] = 0x10325476;
+
+ // Pre-processing: adding a single 1 bit
+ // Append '1' bit to message
+ // NOTE: The input bytes are considered as bits strings,
+ // where the first bit is the most significant bit of the byte
+
+ // Pre-processing: padding with zeros
+ // Append '0' bit until message length in bit 448 (mod 512)
+ // Append length mod (2 pow 64) to message
+
+ int newDataSize = ((((dataSize + 8)/64) + 1)*64) - 8;
+
+ unsigned char *msg = RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
+ memcpy(msg, data, dataSize);
+ msg[dataSize] = 128; // Write the '1' bit
+
+ unsigned int bitsLen = 8*dataSize;
+ memcpy(msg + newDataSize, &bitsLen, 4); // Append the len in bits at the end of the buffer
+
+ // Process the message in successive 512-bit chunks for each 512-bit chunk of message
+ for (int offset = 0; offset < newDataSize; offset += (512/8))
+ {
+ // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
+ unsigned int *w = (unsigned int *)(msg + offset);
+
+ // Initialize hash value for this chunk
+ unsigned int a = hash[0];
+ unsigned int b = hash[1];
+ unsigned int c = hash[2];
+ unsigned int d = hash[3];
+
+ for (int i = 0; i < 64; i++)
+ {
+ unsigned int f = 0;
+ unsigned int g = 0;
+
+ if (i < 16)
+ {
+ f = (b & c) | ((~b) & d);
+ g = i;
+ }
+ else if (i < 32)
+ {
+ f = (d & b) | ((~d) & c);
+ g = (5*i + 1)%16;
+ }
+ else if (i < 48)
+ {
+ f = b ^ c ^ d;
+ g = (3*i + 5)%16;
+ }
+ else
+ {
+ f = c ^ (b | (~d));
+ g = (7*i)%16;
+ }
+
+ unsigned int temp = d;
+ d = c;
+ c = b;
+ b = b + ROTATE_LEFT((a + f + k[i] + w[g]), r[i]);
+ a = temp;
+ }
+
+ // Add chunk's hash to result so far
+ hash[0] += a;
+ hash[1] += b;
+ hash[2] += c;
+ hash[3] += d;
+ }
+
+ RL_FREE(msg);
+
+ return hash;
+}
+
+// Compute SHA-1 hash code
+// NOTE: Returns a static int[5] array (20 bytes)
+unsigned int *ComputeSHA1(unsigned char *data, int dataSize) {
+ #define ROTATE_LEFT(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
+
+ static unsigned int hash[5] = { 0 }; // Hash to be returned
+
+ // Initialize hash values
+ hash[0] = 0x67452301;
+ hash[1] = 0xEFCDAB89;
+ hash[2] = 0x98BADCFE;
+ hash[3] = 0x10325476;
+ hash[4] = 0xC3D2E1F0;
+
+ // Pre-processing: adding a single 1 bit
+ // Append '1' bit to message
+ // NOTE: The input bytes are considered as bits strings,
+ // where the first bit is the most significant bit of the byte
+
+ // Pre-processing: padding with zeros
+ // Append '0' bit until message length in bit 448 (mod 512)
+ // Append length mod (2 pow 64) to message
+
+ int newDataSize = ((((dataSize + 8)/64) + 1)*64);
+
+ unsigned char *msg = RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
+ memcpy(msg, data, dataSize);
+ msg[dataSize] = 128; // Write the '1' bit
+
+ unsigned int bitsLen = 8*dataSize;
+ msg[newDataSize-1] = bitsLen;
+
+ // Process the message in successive 512-bit chunks
+ for (int offset = 0; offset < newDataSize; offset += (512/8))
+ {
+ // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15
+ unsigned int w[80] = {0};
+ for (int i = 0; i < 16; i++) {
+ w[i] = (msg[offset + (i * 4) + 0] << 24) |
+ (msg[offset + (i * 4) + 1] << 16) |
+ (msg[offset + (i * 4) + 2] << 8) |
+ (msg[offset + (i * 4) + 3]);
+ }
+
+ // Message schedule: extend the sixteen 32-bit words into eighty 32-bit words:
+ for (int i = 16; i < 80; ++i) {
+ w[i] = ROTATE_LEFT(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
+ }
+
+ // Initialize hash value for this chunk
+ unsigned int a = hash[0];
+ unsigned int b = hash[1];
+ unsigned int c = hash[2];
+ unsigned int d = hash[3];
+ unsigned int e = hash[4];
+
+ for (int i = 0; i < 80; i++)
+ {
+ unsigned int f = 0;
+ unsigned int k = 0;
+
+ if (i < 20) {
+ f = (b & c) | ((~b) & d);
+ k = 0x5A827999;
+ } else if (i < 40) {
+ f = b ^ c ^ d;
+ k = 0x6ED9EBA1;
+ } else if (i < 60) {
+ f = (b & c) | (b & d) | (c & d);
+ k = 0x8F1BBCDC;
+ } else {
+ f = b ^ c ^ d;
+ k = 0xCA62C1D6;
+ }
+
+ unsigned int temp = ROTATE_LEFT(a, 5) + f + e + k + w[i];
+ e = d;
+ d = c;
+ c = ROTATE_LEFT(b, 30);
+ b = a;
+ a = temp;
+ }
+
+ // Add this chunk's hash to result so far
+ hash[0] += a;
+ hash[1] += b;
+ hash[2] += c;
+ hash[3] += d;
+ hash[4] += e;
+ }
+
+ free(msg);
+
+ return hash;
+}
+
//----------------------------------------------------------------------------------
// Module Functions Definition: Automation Events Recording and Playing
//----------------------------------------------------------------------------------
@@ -3305,10 +3642,21 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
if (filter != NULL)
{
- if (IsFileExtension(path, filter))
+ if (IsPathFile(path))
{
- strcpy(files->paths[files->count], path);
- files->count++;
+ if (IsFileExtension(path, filter))
+ {
+ strcpy(files->paths[files->count], path);
+ files->count++;
+ }
+ }
+ else
+ {
+ if (TextFindIndex(filter, DIRECTORY_FILTER_TAG) >= 0)
+ {
+ strcpy(files->paths[files->count], path);
+ files->count++;
+ }
}
}
else
@@ -3368,7 +3716,22 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi
break;
}
}
- else ScanDirectoryFilesRecursively(path, files, filter);
+ else
+ {
+ if ((filter != NULL) && (TextFindIndex(filter, DIRECTORY_FILTER_TAG) >= 0))
+ {
+ strcpy(files->paths[files->count], path);
+ files->count++;
+ }
+
+ if (files->count >= files->capacity)
+ {
+ TRACELOG(LOG_WARNING, "FILEIO: Maximum filepath scan capacity reached (%i files)", files->capacity);
+ break;
+ }
+
+ ScanDirectoryFilesRecursively(path, files, filter);
+ }
}
}
diff --git a/src/rgestures.h b/src/rgestures.h
index 664a6e1cc..b5624be56 100644
--- a/src/rgestures.h
+++ b/src/rgestures.h
@@ -434,7 +434,7 @@ int GetGestureDetected(void)
return (GESTURES.enabledFlags & GESTURES.current);
}
-// Hold time measured in ms
+// Hold time measured in seconds
float GetGestureHoldDuration(void)
{
// NOTE: time is calculated on current gesture HOLD
@@ -517,7 +517,7 @@ static double rgGetCurrentTime(void)
#if defined(_WIN32)
unsigned long long int clockFrequency, currentTime;
- QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation!
+ QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation!
QueryPerformanceCounter(¤tTime);
time = (double)currentTime/clockFrequency; // Time in seconds
diff --git a/src/rlgl.h b/src/rlgl.h
index 5fb9497cd..6cfc2dcfb 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -68,12 +68,15 @@
* #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_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
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
* #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_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)
@@ -324,22 +327,33 @@
// Default shader vertex attribute locations
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
- #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD
- #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1
+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL
- #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2
+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR
- #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3
+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT
-#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4
+#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4
#endif
#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2
- #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5
+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5
+#endif
+#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
+#endif
+#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS
+ #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
+#endif
#endif
//----------------------------------------------------------------------------------
@@ -527,6 +541,10 @@ typedef enum {
RL_SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int)
RL_SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int)
RL_SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int)
+ RL_SHADER_UNIFORM_UINT, // Shader uniform type: unsigned int
+ RL_SHADER_UNIFORM_UIVEC2, // Shader uniform type: uivec2 (2 unsigned int)
+ RL_SHADER_UNIFORM_UIVEC3, // Shader uniform type: uivec3 (3 unsigned int)
+ RL_SHADER_UNIFORM_UIVEC4, // Shader uniform type: uivec4 (4 unsigned int)
RL_SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d
} rlShaderUniformDataType;
@@ -665,7 +683,7 @@ RLAPI void rlDisableScissorTest(void); // Disable scissor test
RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test
RLAPI void rlEnableWireMode(void); // Enable wire mode
RLAPI void rlEnablePointMode(void); // Enable point mode
-RLAPI void rlDisableWireMode(void); // Disable wire mode ( and point ) maybe rename
+RLAPI void rlDisableWireMode(void); // Disable wire (and point) mode
RLAPI void rlSetLineWidth(float width); // Set the line drawing width
RLAPI float rlGetLineWidth(void); // Get the line drawing width
RLAPI void rlEnableSmoothLines(void); // Enable line aliasing
@@ -755,6 +773,7 @@ RLAPI int rlGetLocationUniform(unsigned int shaderId, const char *uniformName);
RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName); // Get shader location attribute
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
RLAPI void rlSetUniformSampler(int locIndex, unsigned int textureId); // Set shader value sampler
RLAPI void rlSetShader(unsigned int id, int *locs); // Set shader currently active (id and locations)
@@ -973,6 +992,12 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
#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
#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
+#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
+#endif
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
@@ -992,6 +1017,9 @@ 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
@@ -1948,6 +1976,7 @@ void rlEnableWireMode(void)
#endif
}
+// Enable point mode
void rlEnablePointMode(void)
{
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
@@ -1956,6 +1985,7 @@ void rlEnablePointMode(void)
glEnable(GL_PROGRAM_POINT_SIZE);
#endif
}
+
// Disable wire mode
void rlDisableWireMode(void)
{
@@ -2442,25 +2472,47 @@ void rlLoadExtensions(void *loader)
}
// Check instanced rendering support
- if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // Web ANGLE
+ if (strstr(extList[i], (const char*)"instanced_arrays") != NULL) // Broad check for instanced_arrays
{
- glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedANGLE");
- glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedANGLE");
- glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorANGLE");
-
- if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true;
- }
- else
- {
- if ((strcmp(extList[i], (const char *)"GL_EXT_draw_instanced") == 0) && // Standard EXT
- (strcmp(extList[i], (const char *)"GL_EXT_instanced_arrays") == 0))
+ // Specific check
+ if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // ANGLE
+ {
+ glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedANGLE");
+ glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedANGLE");
+ glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorANGLE");
+ }
+ else if (strcmp(extList[i], (const char *)"GL_EXT_instanced_arrays") == 0) // EXT
{
glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT");
glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT");
glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorEXT");
-
- if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true;
}
+ else if (strcmp(extList[i], (const char *)"GL_NV_instanced_arrays") == 0) // NVIDIA GLES
+ {
+ glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV");
+ glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV");
+ glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorNV");
+ }
+
+ // The feature will only be marked as supported if the elements from GL_XXX_instanced_arrays are present
+ if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true;
+ }
+ else if (strstr(extList[i], (const char *)"draw_instanced") != NULL)
+ {
+ // GL_ANGLE_draw_instanced doesn't exist
+ if (strcmp(extList[i], (const char *)"GL_EXT_draw_instanced") == 0)
+ {
+ glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT");
+ glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT");
+ }
+ else if (strcmp(extList[i], (const char*)"GL_NV_draw_instanced") == 0)
+ {
+ glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV");
+ glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV");
+ }
+
+ // But the functions will at least be loaded if only GL_XX_EXT_draw_instanced exist
+ if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true;
}
// Check NPOT textures support
@@ -4143,6 +4195,11 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
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);
+#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);
@@ -4234,8 +4291,16 @@ void rlSetUniform(int locIndex, const void *value, int uniformType, int count)
case RL_SHADER_UNIFORM_IVEC2: glUniform2iv(locIndex, count, (int *)value); break;
case RL_SHADER_UNIFORM_IVEC3: glUniform3iv(locIndex, count, (int *)value); break;
case RL_SHADER_UNIFORM_IVEC4: glUniform4iv(locIndex, count, (int *)value); break;
+ #if !defined(GRAPHICS_API_OPENGL_ES2)
+ case RL_SHADER_UNIFORM_UINT: glUniform1uiv(locIndex, count, (unsigned int *)value); break;
+ case RL_SHADER_UNIFORM_UIVEC2: glUniform2uiv(locIndex, count, (unsigned int *)value); break;
+ case RL_SHADER_UNIFORM_UIVEC3: glUniform3uiv(locIndex, count, (unsigned int *)value); break;
+ case RL_SHADER_UNIFORM_UIVEC4: glUniform4uiv(locIndex, count, (unsigned int *)value); break;
+ #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
}
@@ -4269,6 +4334,14 @@ void rlSetUniformMatrix(int locIndex, Matrix mat)
#endif
}
+// Set shader value uniform matrix
+void rlSetUniformMatrices(int locIndex, const Matrix *matrices, int count)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+ glUniformMatrix4fv(locIndex, count, true, (const float*)matrices);
+#endif
+}
+
// Set shader value uniform sampler
void rlSetUniformSampler(int locIndex, unsigned int textureId)
{
@@ -4410,14 +4483,14 @@ void rlUpdateShaderBuffer(unsigned int id, const void *data, unsigned int dataSi
// Get SSBO buffer size
unsigned int rlGetShaderBufferSize(unsigned int id)
{
- GLint64 size = 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);
-#endif
-
return (size > 0)? (unsigned int)size : 0;
+#else
+ return 0;
+#endif
}
// Read SSBO buffer data (GPU->CPU)
diff --git a/src/rmodels.c b/src/rmodels.c
index 8afa3df57..30130d9e0 100644
--- a/src/rmodels.c
+++ b/src/rmodels.c
@@ -130,7 +130,7 @@
#define MAX_MATERIAL_MAPS 12 // Maximum number of maps supported
#endif
#ifndef MAX_MESH_VERTEX_BUFFERS
- #define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
+ #define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh
#endif
//----------------------------------------------------------------------------------
@@ -426,14 +426,14 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
{
#if 0
// Basic implementation, do not use it!
- // For a sphere with 16 rings and 16 slices it requires 8640 cos()/sin() function calls!
+ // For a sphere with 16 rings and 16 slices it requires 8640 cos()/sin() function calls!
// New optimized version below only requires 4 cos()/sin() calls
-
+
rlPushMatrix();
// NOTE: Transformation is applied in inverse order (scale -> translate)
rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
rlScalef(radius, radius, radius);
-
+
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
@@ -488,7 +488,7 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
for (int i = 0; i < rings + 1; i++)
{
- for (int j = 0; j < slices; j++)
+ for (int j = 0; j < slices; j++)
{
vertices[0] = vertices[2]; // Rotate around y axis to set up vertices for next face
vertices[1] = vertices[3];
@@ -702,7 +702,6 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl
rlPopMatrix();
}
-
// Draw a wired cylinder with base at startPos and top at endPos
// NOTE: It could be also used for pyramid and cone
void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color)
@@ -1156,8 +1155,8 @@ Model LoadModelFromMesh(Mesh mesh)
return model;
}
-// Check if a model is ready
-bool IsModelReady(Model model)
+// Check if a model is valid (loaded in GPU, VAO/VBOs)
+bool IsModelValid(Model model)
{
bool result = false;
@@ -1167,7 +1166,23 @@ bool IsModelReady(Model model)
(model.meshCount > 0) && // Validate mesh count
(model.materialCount > 0)) result = true; // Validate material count
- // NOTE: This is a very general model validation, many elements could be validated from a model...
+ // NOTE: Many elements could be validated from a model, including every model mesh VAO/VBOs
+ // but some VBOs could not be used, it depends on Mesh vertex data
+ for (int i = 0; i < model.meshCount; i++)
+ {
+ if ((model.meshes[i].vertices != NULL) && (model.meshes[i].vboId[0] == 0)) { result = false; break; } // Vertex position buffer not uploaded to GPU
+ if ((model.meshes[i].texcoords != NULL) && (model.meshes[i].vboId[1] == 0)) { result = false; break; } // Vertex textcoords buffer not uploaded to GPU
+ if ((model.meshes[i].normals != NULL) && (model.meshes[i].vboId[2] == 0)) { result = false; break; } // Vertex normals buffer not uploaded to GPU
+ if ((model.meshes[i].colors != NULL) && (model.meshes[i].vboId[3] == 0)) { result = false; break; } // Vertex colors buffer not uploaded to GPU
+ if ((model.meshes[i].tangents != NULL) && (model.meshes[i].vboId[4] == 0)) { result = false; break; } // Vertex tangents buffer not uploaded to GPU
+ if ((model.meshes[i].texcoords2 != NULL) && (model.meshes[i].vboId[5] == 0)) { result = false; break; } // Vertex texcoords2 buffer not uploaded to GPU
+ if ((model.meshes[i].indices != NULL) && (model.meshes[i].vboId[6] == 0)) { result = false; break; } // Vertex indices buffer not uploaded to GPU
+ if ((model.meshes[i].boneIds != NULL) && (model.meshes[i].vboId[7] == 0)) { result = false; break; } // Vertex boneIds buffer not uploaded to GPU
+ if ((model.meshes[i].boneWeights != NULL) && (model.meshes[i].vboId[8] == 0)) { result = false; break; } // Vertex boneWeights buffer not uploaded to GPU
+
+ // NOTE: Some OpenGL versions do not support VAO, so we don't check it
+ //if (model.meshes[i].vaoId == 0) { result = false; break }
+ }
return result;
}
@@ -1246,13 +1261,18 @@ void UploadMesh(Mesh *mesh, bool dynamic)
mesh->vboId = (unsigned int *)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
mesh->vaoId = 0; // Vertex Array Object
- mesh->vboId[0] = 0; // Vertex buffer: positions
- mesh->vboId[1] = 0; // Vertex buffer: texcoords
- mesh->vboId[2] = 0; // Vertex buffer: normals
- mesh->vboId[3] = 0; // Vertex buffer: colors
- mesh->vboId[4] = 0; // Vertex buffer: tangents
- mesh->vboId[5] = 0; // Vertex buffer: texcoords2
- mesh->vboId[6] = 0; // Vertex buffer: indices
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = 0; // Vertex buffer: positions
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = 0; // Vertex buffer: texcoords
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = 0; // Vertex buffer: normals
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = 0; // Vertex buffer: colors
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = 0; // Vertex buffer: tangents
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = 0; // Vertex buffer: texcoords2
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = 0; // Vertex buffer: indices
+
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = 0; // Vertex buffer: boneIds
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = 0; // Vertex buffer: boneWeights
+#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
mesh->vaoId = rlLoadVertexArray();
@@ -1262,12 +1282,12 @@ void UploadMesh(Mesh *mesh, bool dynamic)
// Enable vertex attributes: position (shader-location = 0)
void *vertices = (mesh->animVertices != NULL)? mesh->animVertices : mesh->vertices;
- mesh->vboId[0] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic);
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION] = rlLoadVertexBuffer(vertices, mesh->vertexCount*3*sizeof(float), dynamic);
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION);
// Enable vertex attributes: texcoords (shader-location = 1)
- mesh->vboId[1] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD] = rlLoadVertexBuffer(mesh->texcoords, mesh->vertexCount*2*sizeof(float), dynamic);
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD);
@@ -1278,7 +1298,7 @@ void UploadMesh(Mesh *mesh, bool dynamic)
{
// Enable vertex attributes: normals (shader-location = 2)
void *normals = (mesh->animNormals != NULL)? mesh->animNormals : mesh->normals;
- mesh->vboId[2] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic);
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL] = rlLoadVertexBuffer(normals, mesh->vertexCount*3*sizeof(float), dynamic);
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL);
}
@@ -1294,7 +1314,7 @@ void UploadMesh(Mesh *mesh, bool dynamic)
if (mesh->colors != NULL)
{
// Enable vertex attribute: color (shader-location = 3)
- mesh->vboId[3] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] = rlLoadVertexBuffer(mesh->colors, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, 4, RL_UNSIGNED_BYTE, 1, 0, 0);
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR);
}
@@ -1310,7 +1330,7 @@ void UploadMesh(Mesh *mesh, bool dynamic)
if (mesh->tangents != NULL)
{
// Enable vertex attribute: tangent (shader-location = 4)
- mesh->vboId[4] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic);
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), dynamic);
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
}
@@ -1326,7 +1346,7 @@ void UploadMesh(Mesh *mesh, bool dynamic)
if (mesh->texcoords2 != NULL)
{
// Enable vertex attribute: texcoord2 (shader-location = 5)
- mesh->vboId[5] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic);
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2] = rlLoadVertexBuffer(mesh->texcoords2, mesh->vertexCount*2*sizeof(float), dynamic);
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
}
@@ -1339,9 +1359,43 @@ void UploadMesh(Mesh *mesh, bool dynamic)
rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2);
}
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
+ if (mesh->boneIds != NULL)
+ {
+ // Enable vertex attribute: boneIds (shader-location = 7)
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS] = rlLoadVertexBuffer(mesh->boneIds, mesh->vertexCount*4*sizeof(unsigned char), dynamic);
+ rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, 4, RL_UNSIGNED_BYTE, 0, 0, 0);
+ rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS);
+ }
+ else
+ {
+ // Default vertex attribute: boneIds
+ // WARNING: Default value provided to shader if location available
+ float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS, value, SHADER_ATTRIB_VEC4, 4);
+ rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS);
+ }
+
+ if (mesh->boneWeights != NULL)
+ {
+ // Enable vertex attribute: boneWeights (shader-location = 8)
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS] = rlLoadVertexBuffer(mesh->boneWeights, mesh->vertexCount*4*sizeof(float), dynamic);
+ rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, 4, RL_FLOAT, 0, 0, 0);
+ rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);
+ }
+ else
+ {
+ // Default vertex attribute: boneWeights
+ // WARNING: Default value provided to shader if location available
+ float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ rlSetVertexAttributeDefault(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, value, SHADER_ATTRIB_VEC4, 2);
+ rlDisableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS);
+ }
+#endif
+
if (mesh->indices != NULL)
{
- mesh->vboId[6] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic);
+ mesh->vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES] = rlLoadVertexBufferElement(mesh->indices, mesh->triangleCount*3*sizeof(unsigned short), dynamic);
}
if (mesh->vaoId > 0) TRACELOG(LOG_INFO, "VAO: [ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId);
@@ -1451,6 +1505,14 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
// Upload model normal matrix (if locations available)
if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
+
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
+ // Upload Bone Transforms
+ if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices)
+ {
+ rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);
+ }
+#endif
//-----------------------------------------------------
// Bind active texture maps (if available)
@@ -1478,19 +1540,19 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
if (!rlEnableVertexArray(mesh.vaoId))
{
// Bind mesh VBO data: vertex position (shader-location = 0)
- rlEnableVertexBuffer(mesh.vboId[0]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
// Bind mesh VBO data: vertex texcoords (shader-location = 1)
- rlEnableVertexBuffer(mesh.vboId[1]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
{
// Bind mesh VBO data: vertex normals (shader-location = 2)
- rlEnableVertexBuffer(mesh.vboId[2]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]);
}
@@ -1498,9 +1560,9 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
// Bind mesh VBO data: vertex colors (shader-location = 3, if available)
if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
{
- if (mesh.vboId[3] != 0)
+ if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0)
{
- rlEnableVertexBuffer(mesh.vboId[3]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
}
@@ -1517,7 +1579,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
// Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
{
- rlEnableVertexBuffer(mesh.vboId[4]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]);
}
@@ -1525,12 +1587,30 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
// Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
{
- rlEnableVertexBuffer(mesh.vboId[5]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
}
- if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
+ // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
+ {
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);
+ }
+
+ // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)
+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)
+ {
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
+ }
+#endif
+
+ if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
}
int eyeCount = 1;
@@ -1671,6 +1751,15 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
// Upload model normal matrix (if locations available)
if (material.shader.locs[SHADER_LOC_MATRIX_NORMAL] != -1) rlSetUniformMatrix(material.shader.locs[SHADER_LOC_MATRIX_NORMAL], MatrixTranspose(MatrixInvert(matModel)));
+
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
+ // Upload Bone Transforms
+ if (material.shader.locs[SHADER_LOC_BONE_MATRICES] != -1 && mesh.boneMatrices)
+ {
+ rlSetUniformMatrices(material.shader.locs[SHADER_LOC_BONE_MATRICES], mesh.boneMatrices, mesh.boneCount);
+ }
+#endif
+
//-----------------------------------------------------
// Bind active texture maps (if available)
@@ -1696,19 +1785,19 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
if (!rlEnableVertexArray(mesh.vaoId))
{
// Bind mesh VBO data: vertex position (shader-location = 0)
- rlEnableVertexBuffer(mesh.vboId[0]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION], 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_POSITION]);
// Bind mesh VBO data: vertex texcoords (shader-location = 1)
- rlEnableVertexBuffer(mesh.vboId[1]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01], 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD01]);
if (material.shader.locs[SHADER_LOC_VERTEX_NORMAL] != -1)
{
// Bind mesh VBO data: vertex normals (shader-location = 2)
- rlEnableVertexBuffer(mesh.vboId[2]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL], 3, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_NORMAL]);
}
@@ -1716,9 +1805,9 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
// Bind mesh VBO data: vertex colors (shader-location = 3, if available)
if (material.shader.locs[SHADER_LOC_VERTEX_COLOR] != -1)
{
- if (mesh.vboId[3] != 0)
+ if (mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR] != 0)
{
- rlEnableVertexBuffer(mesh.vboId[3]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR], 4, RL_UNSIGNED_BYTE, 1, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
}
@@ -1735,7 +1824,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
// Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
if (material.shader.locs[SHADER_LOC_VERTEX_TANGENT] != -1)
{
- rlEnableVertexBuffer(mesh.vboId[4]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT], 4, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TANGENT]);
}
@@ -1743,12 +1832,30 @@ void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, i
// Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
if (material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] != -1)
{
- rlEnableVertexBuffer(mesh.vboId[5]);
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2]);
rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02], 2, RL_FLOAT, 0, 0, 0);
rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]);
}
- if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
+#ifdef RL_SUPPORT_MESH_GPU_SKINNING
+ // Bind mesh VBO data: vertex bone ids (shader-location = 6, if available)
+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEIDS] != -1)
+ {
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS]);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS], 4, RL_UNSIGNED_BYTE, 0, 0, 0);
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEIDS]);
+ }
+
+ // Bind mesh VBO data: vertex bone weights (shader-location = 7, if available)
+ if (material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS] != -1)
+ {
+ rlEnableVertexBuffer(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS]);
+ rlSetVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS], 4, RL_FLOAT, 0, 0, 0);
+ rlEnableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_BONEWEIGHTS]);
+ }
+#endif
+
+ if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES]);
}
int eyeCount = 1;
@@ -1825,6 +1932,7 @@ void UnloadMesh(Mesh mesh)
RL_FREE(mesh.animNormals);
RL_FREE(mesh.boneWeights);
RL_FREE(mesh.boneIds);
+ RL_FREE(mesh.boneMatrices);
}
// Export mesh data to file
@@ -2004,7 +2112,6 @@ bool ExportMeshAsCode(Mesh mesh, const char *fileName)
return success;
}
-
#if defined(SUPPORT_FILEFORMAT_OBJ) || defined(SUPPORT_FILEFORMAT_MTL)
// Process obj materials
static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, int materialCount)
@@ -2016,6 +2123,8 @@ static void ProcessMaterialsOBJ(Material *materials, tinyobj_material_t *mats, i
// NOTE: Uses default shader, which only supports MATERIAL_MAP_DIFFUSE
materials[m] = LoadMaterialDefault();
+ if (mats == NULL) continue;
+
// Get default texture, in case no texture is defined
// NOTE: rlgl default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8
materials[m].maps[MATERIAL_MAP_DIFFUSE].texture = (Texture2D){ rlGetTextureIdDefault(), 1, 1, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
@@ -2089,14 +2198,16 @@ Material LoadMaterialDefault(void)
return material;
}
-// Check if a material is ready
-bool IsMaterialReady(Material material)
+// Check if a material is valid (map textures loaded in GPU)
+bool IsMaterialValid(Material material)
{
bool result = false;
if ((material.maps != NULL) && // Validate material contain some map
(material.shader.id > 0)) result = true; // Validate material shader is valid
+ // TODO: Check if available maps contain loaded textures
+
return result;
}
@@ -2253,6 +2364,50 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
}
}
+void UpdateModelAnimationBoneMatrices(Model model, ModelAnimation anim, int frame)
+{
+ if ((anim.frameCount > 0) && (anim.bones != NULL) && (anim.framePoses != NULL))
+ {
+ if (frame >= anim.frameCount) frame = frame%anim.frameCount;
+
+ for (int i = 0; i < model.meshCount; i++)
+ {
+ if (model.meshes[i].boneMatrices)
+ {
+ assert(model.meshes[i].boneCount == anim.boneCount);
+
+ for (int boneId = 0; boneId < model.meshes[i].boneCount; boneId++)
+ {
+ Vector3 inTranslation = model.bindPose[boneId].translation;
+ Quaternion inRotation = model.bindPose[boneId].rotation;
+ Vector3 inScale = model.bindPose[boneId].scale;
+
+ Vector3 outTranslation = anim.framePoses[frame][boneId].translation;
+ Quaternion outRotation = anim.framePoses[frame][boneId].rotation;
+ Vector3 outScale = anim.framePoses[frame][boneId].scale;
+
+ Vector3 invTranslation = Vector3RotateByQuaternion(Vector3Negate(inTranslation), QuaternionInvert(inRotation));
+ Quaternion invRotation = QuaternionInvert(inRotation);
+ Vector3 invScale = Vector3Divide((Vector3){ 1.0f, 1.0f, 1.0f }, inScale);
+
+ Vector3 boneTranslation = Vector3Add(
+ Vector3RotateByQuaternion(Vector3Multiply(outScale, invTranslation),
+ outRotation), outTranslation);
+ Quaternion boneRotation = QuaternionMultiply(outRotation, invRotation);
+ Vector3 boneScale = Vector3Multiply(outScale, invScale);
+
+ Matrix boneMatrix = MatrixMultiply(MatrixMultiply(
+ QuaternionToMatrix(boneRotation),
+ MatrixTranslate(boneTranslation.x, boneTranslation.y, boneTranslation.z)),
+ MatrixScale(boneScale.x, boneScale.y, boneScale.z));
+
+ model.meshes[i].boneMatrices[boneId] = boneMatrix;
+ }
+ }
+ }
+ }
+}
+
// Unload animation array data
void UnloadModelAnimations(ModelAnimation *animations, int animCount)
{
@@ -3631,6 +3786,30 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float
rlDisableWireMode();
}
+// Draw a model points
+void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
+{
+ rlEnablePointMode();
+ rlDisableBackfaceCulling();
+
+ DrawModel(model, position, scale, tint);
+
+ rlEnableBackfaceCulling();
+ rlDisableWireMode();
+}
+
+// Draw a model points
+void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
+{
+ rlEnablePointMode();
+ rlDisableBackfaceCulling();
+
+ DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
+
+ rlEnableBackfaceCulling();
+ rlDisableWireMode();
+}
+
// Draw a billboard
void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint)
{
@@ -4049,130 +4228,236 @@ static void BuildPoseFromParentJoints(BoneInfo *bones, int boneCount, Transform
// - the mesh is automatically triangulated by tinyobj
static Model LoadOBJ(const char *fileName)
{
+ tinyobj_attrib_t objAttributes = { 0 };
+ tinyobj_shape_t* objShapes = NULL;
+ unsigned int objShapeCount = 0;
+
+ tinyobj_material_t* objMaterials = NULL;
+ unsigned int objMaterialCount = 0;
+
Model model = { 0 };
+ model.transform = MatrixIdentity();
- tinyobj_attrib_t attrib = { 0 };
- tinyobj_shape_t *meshes = NULL;
- unsigned int meshCount = 0;
+ char* fileText = LoadFileText(fileName);
- tinyobj_material_t *materials = NULL;
- unsigned int materialCount = 0;
-
- char *fileText = LoadFileText(fileName);
-
- if (fileText != NULL)
+ if (fileText == NULL)
{
- unsigned int dataSize = (unsigned int)strlen(fileText);
+ TRACELOG(LOG_ERROR, "MODEL Unable to read obj file %s", fileName);
+ return model;
+ }
- char currentDir[1024] = { 0 };
- strcpy(currentDir, GetWorkingDirectory()); // Save current working directory
- const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness
- if (CHDIR(workingDir) != 0)
+ char currentDir[1024] = { 0 };
+ strcpy(currentDir, GetWorkingDirectory()); // Save current working directory
+ const char* workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness
+ if (CHDIR(workingDir) != 0)
+ {
+ TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);
+ }
+
+ unsigned int dataSize = (unsigned int)strlen(fileText);
+
+ unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
+ int ret = tinyobj_parse_obj(&objAttributes, &objShapes, &objShapeCount, &objMaterials, &objMaterialCount, fileText, dataSize, flags);
+
+ if (ret != TINYOBJ_SUCCESS)
+ {
+ TRACELOG(LOG_ERROR, "MODEL Unable to read obj data %s", fileName);
+ return model;
+ }
+
+ UnloadFileText(fileText);
+
+ unsigned int faceVertIndex = 0;
+ unsigned int nextShape = 1;
+ int lastMaterial = -1;
+ unsigned int meshIndex = 0;
+
+ // count meshes
+ unsigned int nextShapeEnd = objAttributes.num_face_num_verts;
+
+ // see how many verts till the next shape
+
+ if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;
+
+ // walk all the faces
+ for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
+ {
+ if (faceVertIndex >= nextShapeEnd)
{
- TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir);
+ // try to find the last vert in the next shape
+ nextShape++;
+ if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
+ else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces
+ meshIndex++;
+ }
+ else if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial)
+ {
+ meshIndex++;// if this is a new material, we need to allocate a new mesh
}
- unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
- int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileText, dataSize, flags);
+ lastMaterial = objAttributes.material_ids[faceId];
+ faceVertIndex += objAttributes.face_num_verts[faceId];
+ }
- if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName);
- else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes/%i materials", fileName, meshCount, materialCount);
+ // allocate the base meshes and materials
+ model.meshCount = meshIndex + 1;
+ model.meshes = (Mesh*)MemAlloc(sizeof(Mesh) * model.meshCount);
- // WARNING: We are not splitting meshes by materials (previous implementation)
- // Depending on the provided OBJ that was not the best option and it just crashed
- // so, implementation was simplified to prioritize parsed meshes
- model.meshCount = meshCount;
+ if (objMaterialCount > 0)
+ {
+ model.materialCount = objMaterialCount;
+ model.materials = (Material*)MemAlloc(sizeof(Material) * objMaterialCount);
+ }
+ else // we must allocate at least one material
+ {
+ model.materialCount = 1;
+ model.materials = (Material*)MemAlloc(sizeof(Material) * 1);
+ }
- // Set number of materials available
- // NOTE: There could be more materials available than meshes but it will be resolved at
- // model.meshMaterial, just assigning the right material to corresponding mesh
- model.materialCount = materialCount;
- if (model.materialCount == 0)
+ model.meshMaterial = (int*)MemAlloc(sizeof(int) * model.meshCount);
+
+ // see how many verts are in each mesh
+ unsigned int* localMeshVertexCounts = (unsigned int*)MemAlloc(sizeof(unsigned int) * model.meshCount);
+
+ faceVertIndex = 0;
+ nextShapeEnd = objAttributes.num_face_num_verts;
+ lastMaterial = -1;
+ meshIndex = 0;
+ unsigned int localMeshVertexCount = 0;
+
+ nextShape = 1;
+ if (objShapeCount > 1)
+ nextShapeEnd = objShapes[nextShape].face_offset;
+
+ // walk all the faces
+ for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
+ {
+ bool newMesh = false; // do we need a new mesh?
+ if (faceVertIndex >= nextShapeEnd)
{
- model.materialCount = 1;
- TRACELOG(LOG_INFO, "MODEL: No materials provided, setting one default material for all meshes");
+ // try to find the last vert in the next shape
+ nextShape++;
+ if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
+ else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces
+
+ newMesh = true;
}
- else if (model.materialCount > 1 && model.meshCount > 1)
+ else if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial)
{
- // TEMP warning about multiple materials, to be removed when proper splitting code is implemented
- // any obj with multiple materials will need to have it's materials assigned by the user in code to work at this time
- TRACELOG(LOG_INFO, "MODEL: OBJ has multiple materials, manual material assignment will be required.");
+ newMesh = true;
}
- // Init model meshes and materials
- model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
- model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int)); // Material index assigned to each mesh
- model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
+ lastMaterial = objAttributes.material_ids[faceId];
- // Process each provided mesh
- for (int i = 0; i < model.meshCount; i++)
+ if (newMesh)
{
- // WARNING: We need to calculate the mesh triangles manually using meshes[i].face_offset
- // because in case of triangulated quads, meshes[i].length actually report quads,
- // despite the triangulation that is efectively considered on attrib.num_faces
- unsigned int tris = 0;
- if (i == model.meshCount - 1) tris = attrib.num_faces - meshes[i].face_offset;
- else tris = meshes[i + 1].face_offset;
+ localMeshVertexCounts[meshIndex] = localMeshVertexCount;
- model.meshes[i].vertexCount = tris*3;
- model.meshes[i].triangleCount = tris; // Face count (triangulated)
- model.meshes[i].vertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
- model.meshes[i].texcoords = (float *)RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float));
- model.meshes[i].normals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
- model.meshMaterial[i] = 0; // By default, assign material 0 to each mesh
-
- // Process all mesh faces
- for (unsigned int face = 0, f = meshes[i].face_offset, v = 0, vt = 0, vn = 0; face < tris; face++, f++, v += 3, vt += 3, vn += 3)
- {
- // Get indices for the face
- tinyobj_vertex_index_t idx0 = attrib.faces[f*3 + 0];
- tinyobj_vertex_index_t idx1 = attrib.faces[f*3 + 1];
- tinyobj_vertex_index_t idx2 = attrib.faces[f*3 + 2];
-
- // Fill vertices buffer (float) using vertex index of the face
- for (int n = 0; n < 3; n++) { model.meshes[i].vertices[v*3 + n] = attrib.vertices[idx0.v_idx*3 + n]; }
- for (int n = 0; n < 3; n++) { model.meshes[i].vertices[(v + 1)*3 + n] = attrib.vertices[idx1.v_idx*3 + n]; }
- for (int n = 0; n < 3; n++) { model.meshes[i].vertices[(v + 2)*3 + n] = attrib.vertices[idx2.v_idx*3 + n]; }
-
- if (attrib.num_texcoords > 0)
- {
- // Fill texcoords buffer (float) using vertex index of the face
- // NOTE: Y-coordinate must be flipped upside-down
- model.meshes[i].texcoords[vt*2 + 0] = attrib.texcoords[idx0.vt_idx*2 + 0];
- model.meshes[i].texcoords[vt*2 + 1] = 1.0f - attrib.texcoords[idx0.vt_idx*2 + 1];
-
- model.meshes[i].texcoords[(vt + 1)*2 + 0] = attrib.texcoords[idx1.vt_idx*2 + 0];
- model.meshes[i].texcoords[(vt + 1)*2 + 1] = 1.0f - attrib.texcoords[idx1.vt_idx*2 + 1];
-
- model.meshes[i].texcoords[(vt + 2)*2 + 0] = attrib.texcoords[idx2.vt_idx*2 + 0];
- model.meshes[i].texcoords[(vt + 2)*2 + 1] = 1.0f - attrib.texcoords[idx2.vt_idx*2 + 1];
- }
-
- if (attrib.num_normals > 0)
- {
- // Fill normals buffer (float) using vertex index of the face
- for (int n = 0; n < 3; n++) { model.meshes[i].normals[vn*3 + n] = attrib.normals[idx0.vn_idx*3 + n]; }
- for (int n = 0; n < 3; n++) { model.meshes[i].normals[(vn + 1)*3 + n] = attrib.normals[idx1.vn_idx*3 + n]; }
- for (int n = 0; n < 3; n++) { model.meshes[i].normals[(vn + 2)*3 + n] = attrib.normals[idx2.vn_idx*3 + n]; }
- }
- }
+ localMeshVertexCount = 0;
+ meshIndex++;
}
- // Init model materials
- if (materialCount > 0) ProcessMaterialsOBJ(model.materials, materials, materialCount);
- else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh
+ faceVertIndex += objAttributes.face_num_verts[faceId];
+ localMeshVertexCount += objAttributes.face_num_verts[faceId];
+ }
+ localMeshVertexCounts[meshIndex] = localMeshVertexCount;
- tinyobj_attrib_free(&attrib);
- tinyobj_shapes_free(meshes, model.meshCount);
- tinyobj_materials_free(materials, materialCount);
+ for (int i = 0; i < model.meshCount; i++)
+ {
+ // allocate the buffers for each mesh
+ unsigned int vertexCount = localMeshVertexCounts[i];
- UnloadFileText(fileText);
+ model.meshes[i].vertexCount = vertexCount;
+ model.meshes[i].triangleCount = vertexCount / 3;
- // Restore current working directory
- if (CHDIR(currentDir) != 0)
+ model.meshes[i].vertices = (float*)MemAlloc(sizeof(float) * vertexCount * 3);
+ model.meshes[i].normals = (float*)MemAlloc(sizeof(float) * vertexCount * 3);
+ model.meshes[i].texcoords = (float*)MemAlloc(sizeof(float) * vertexCount * 2);
+ model.meshes[i].colors = (unsigned char*)MemAlloc(sizeof(unsigned char) * vertexCount * 4);
+ }
+
+ MemFree(localMeshVertexCounts);
+ localMeshVertexCounts = NULL;
+
+ // fill meshes
+ faceVertIndex = 0;
+
+ nextShapeEnd = objAttributes.num_face_num_verts;
+
+ // see how many verts till the next shape
+ nextShape = 1;
+ if (objShapeCount > 1) nextShapeEnd = objShapes[nextShape].face_offset;
+ lastMaterial = -1;
+ meshIndex = 0;
+ localMeshVertexCount = 0;
+
+ // walk all the faces
+ for (unsigned int faceId = 0; faceId < objAttributes.num_faces; faceId++)
+ {
+ bool newMesh = false; // do we need a new mesh?
+ if (faceVertIndex >= nextShapeEnd)
{
- TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir);
+ // try to find the last vert in the next shape
+ nextShape++;
+ if (nextShape < objShapeCount) nextShapeEnd = objShapes[nextShape].face_offset;
+ else nextShapeEnd = objAttributes.num_face_num_verts; // this is actually the total number of face verts in the file, not faces
+ newMesh = true;
}
+ // if this is a new material, we need to allocate a new mesh
+ if (lastMaterial != -1 && objAttributes.material_ids[faceId] != lastMaterial) newMesh = true;
+ lastMaterial = objAttributes.material_ids[faceId];
+
+ if (newMesh)
+ {
+ localMeshVertexCount = 0;
+ meshIndex++;
+ }
+
+ int matId = 0;
+ if (lastMaterial >= 0 && lastMaterial < (int)objMaterialCount)
+ matId = lastMaterial;
+
+ model.meshMaterial[meshIndex] = matId;
+
+ for (int f = 0; f < objAttributes.face_num_verts[faceId]; f++)
+ {
+ int vertIndex = objAttributes.faces[faceVertIndex].v_idx;
+ int normalIndex = objAttributes.faces[faceVertIndex].vn_idx;
+ int texcordIndex = objAttributes.faces[faceVertIndex].vt_idx;
+
+ for (int i = 0; i < 3; i++)
+ model.meshes[meshIndex].vertices[localMeshVertexCount * 3 + i] = objAttributes.vertices[vertIndex * 3 + i];
+
+ for (int i = 0; i < 3; i++)
+ model.meshes[meshIndex].normals[localMeshVertexCount * 3 + i] = objAttributes.normals[normalIndex * 3 + i];
+
+ for (int i = 0; i < 2; i++)
+ model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + i] = objAttributes.texcoords[texcordIndex * 2 + i];
+
+ model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + 1] = 1.0f - model.meshes[meshIndex].texcoords[localMeshVertexCount * 2 + 1];
+
+ for (int i = 0; i < 4; i++)
+ model.meshes[meshIndex].colors[localMeshVertexCount * 4 + i] = 255;
+
+ faceVertIndex++;
+ localMeshVertexCount++;
+ }
+ }
+
+ if (objMaterialCount > 0) ProcessMaterialsOBJ(model.materials, objMaterials, objMaterialCount);
+ else model.materials[0] = LoadMaterialDefault(); // Set default material for the mesh
+
+ tinyobj_attrib_free(&objAttributes);
+ tinyobj_shapes_free(objShapes, objShapeCount);
+ tinyobj_materials_free(objMaterials, objMaterialCount);
+
+ for (int i = 0; i < model.meshCount; i++)
+ UploadMesh(model.meshes + i, true);
+
+ // Restore current working directory
+ if (CHDIR(currentDir) != 0)
+ {
+ TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", currentDir);
}
return model;
@@ -4540,6 +4825,17 @@ static Model LoadIQM(const char *fileName)
BuildPoseFromParentJoints(model.bones, model.boneCount, model.bindPose);
+ for (int i = 0; i < model.meshCount; i++)
+ {
+ model.meshes[i].boneCount = model.boneCount;
+ model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
+
+ for (int j = 0; j < model.meshes[i].boneCount; j++)
+ {
+ model.meshes[i].boneMatrices[j] = MatrixIdentity();
+ }
+ }
+
UnloadFileData(fileData);
RL_FREE(imesh);
@@ -4948,17 +5244,19 @@ static Model LoadGLTF(const char *fileName)
***********************************************************************************************/
// Macro to simplify attributes loading code
- #define LOAD_ATTRIBUTE(accesor, numComp, dataType, dstPtr) \
+ #define LOAD_ATTRIBUTE(accesor, numComp, srcType, dstPtr) LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, srcType)
+
+ #define LOAD_ATTRIBUTE_CAST(accesor, numComp, srcType, dstPtr, dstType) \
{ \
int n = 0; \
- dataType *buffer = (dataType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(dataType) + accesor->offset/sizeof(dataType); \
+ srcType *buffer = (srcType *)accesor->buffer_view->buffer->data + accesor->buffer_view->offset/sizeof(srcType) + accesor->offset/sizeof(srcType); \
for (unsigned int k = 0; k < accesor->count; k++) \
{\
for (int l = 0; l < numComp; l++) \
{\
- dstPtr[numComp*k + l] = buffer[n + l];\
+ dstPtr[numComp*k + l] = (dstType)buffer[n + l];\
}\
- n += (int)(accesor->stride/sizeof(dataType));\
+ n += (int)(accesor->stride/sizeof(srcType));\
}\
}
@@ -5399,8 +5697,6 @@ static Model LoadGLTF(const char *fileName)
else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
}
else TRACELOG(LOG_WARNING, "MODEL: [%s] Color attribute data format not supported", fileName);
-
-
}
// NOTE: Attributes related to animations are processed separately
@@ -5421,23 +5717,25 @@ static Model LoadGLTF(const char *fileName)
// Load unsigned short data type into mesh.indices
LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices)
}
+ else if (attribute->component_type == cgltf_component_type_r_8u)
+ {
+ // Init raylib mesh indices to copy glTF attribute data
+ model.meshes[meshIndex].indices = RL_MALLOC(attribute->count * sizeof(unsigned short));
+ LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, unsigned short)
+
+ }
else if (attribute->component_type == cgltf_component_type_r_32u)
{
// Init raylib mesh indices to copy glTF attribute data
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
-
- // Load data into a temp buffer to be converted to raylib data type
- unsigned int *temp = RL_MALLOC(attribute->count*sizeof(unsigned int));
- LOAD_ATTRIBUTE(attribute, 1, unsigned int, temp);
-
- // Convert data to raylib indices data type (unsigned short)
- for (unsigned int d = 0; d < attribute->count; d++) model.meshes[meshIndex].indices[d] = (unsigned short)temp[d];
+ LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short);
TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
-
- RL_FREE(temp);
}
- else TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName);
+ else
+ {
+ TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data format not supported, use u16", fileName);
+ }
}
else model.meshes[meshIndex].triangleCount = model.meshes[meshIndex].vertexCount/3; // Unindexed mesh
@@ -5469,7 +5767,7 @@ static Model LoadGLTF(const char *fileName)
// - Only supports linear interpolation (default method in Blender when checked "Always Sample Animations" when exporting a GLTF file)
// - Only supports translation/rotation/scale animation channel.path, weights not considered (i.e. morph targets)
//----------------------------------------------------------------------------------------------------
- if (data->skins_count == 1)
+ if (data->skins_count > 0)
{
cgltf_skin skin = data->skins[0];
model.bones = LoadBoneInfoGLTF(skin, &model.boneCount);
@@ -5489,9 +5787,9 @@ static Model LoadGLTF(const char *fileName)
MatrixDecompose(worldMatrix, &(model.bindPose[i].translation), &(model.bindPose[i].rotation), &(model.bindPose[i].scale));
}
}
- else if (data->skins_count > 1)
+ if (data->skins_count > 1)
{
- TRACELOG(LOG_ERROR, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count);
+ TRACELOG(LOG_WARNING, "MODEL: [%s] can only load one skin (armature) per model, but gltf skins_count == %i", fileName, data->skins_count);
}
meshIndex = 0;
@@ -5623,6 +5921,15 @@ static Model LoadGLTF(const char *fileName)
memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
}
+ // Bone Transform Matrices
+ model.meshes[meshIndex].boneCount = model.boneCount;
+ model.meshes[meshIndex].boneMatrices = RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));
+
+ for (int j = 0; j < model.meshes[meshIndex].boneCount; j++)
+ {
+ model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity();
+ }
+
meshIndex++; // Move to next mesh
}
@@ -5803,7 +6110,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
if (result == cgltf_result_success)
{
- if (data->skins_count == 1)
+ if (data->skins_count > 0)
{
cgltf_skin skin = data->skins[0];
*animCount = (int)data->animations_count;
@@ -5938,7 +6245,11 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
RL_FREE(boneChannels);
}
}
- else TRACELOG(LOG_ERROR, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count);
+
+ if (data->skins_count > 1)
+ {
+ TRACELOG(LOG_WARNING, "MODEL: [%s] expected exactly one skin to load animation data from, but found %i", fileName, data->skins_count);
+ }
cgltf_free(data);
}
@@ -6390,6 +6701,13 @@ static Model LoadM3D(const char *fileName)
{
memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float));
memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float));
+
+ model.meshes[i].boneCount = model.boneCount;
+ model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
+ for (j = 0; j < model.meshes[i].boneCount; j++)
+ {
+ model.meshes[i].boneMatrices[j] = MatrixIdentity();
+ }
}
}
diff --git a/src/rshapes.c b/src/rshapes.c
index 66dfbf3b6..e9b5ca87b 100644
--- a/src/rshapes.c
+++ b/src/rshapes.c
@@ -828,8 +828,8 @@ void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color)
{
if ((lineThick > rec.width) || (lineThick > rec.height))
{
- if (rec.width > rec.height) lineThick = rec.height/2;
- else if (rec.width < rec.height) lineThick = rec.width/2;
+ if (rec.width >= rec.height) lineThick = rec.height/2;
+ else if (rec.width <= rec.height) lineThick = rec.width/2;
}
// When rec = { x, y, 8.0f, 6.0f } and lineThick = 2, the following
diff --git a/src/rtext.c b/src/rtext.c
index 8c1dc3c5e..3510671be 100644
--- a/src/rtext.c
+++ b/src/rtext.c
@@ -124,6 +124,7 @@
//----------------------------------------------------------------------------------
// Global variables
//----------------------------------------------------------------------------------
+extern bool isGpuReady;
#if defined(SUPPORT_DEFAULT_FONT)
// Default font provided by raylib
// NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
@@ -252,15 +253,15 @@ extern void LoadFontDefault(void)
counter++;
}
- defaultFont.texture = LoadTextureFromImage(imFont);
+ if (isGpuReady) defaultFont.texture = LoadTextureFromImage(imFont);
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
//------------------------------------------------------------------------------
// Allocate space for our characters info data
// NOTE: This memory must be freed at end! --> Done by CloseWindow()
- defaultFont.glyphs = (GlyphInfo *)RL_MALLOC(defaultFont.glyphCount*sizeof(GlyphInfo));
- defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.glyphCount*sizeof(Rectangle));
+ defaultFont.glyphs = (GlyphInfo *)RL_CALLOC(defaultFont.glyphCount, sizeof(GlyphInfo));
+ defaultFont.recs = (Rectangle *)RL_CALLOC(defaultFont.glyphCount, sizeof(Rectangle));
int currentLine = 0;
int currentPosX = charsDivisor;
@@ -308,7 +309,7 @@ extern void LoadFontDefault(void)
extern void UnloadFontDefault(void)
{
for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image);
- UnloadTexture(defaultFont.texture);
+ if (isGpuReady) UnloadTexture(defaultFont.texture);
RL_FREE(defaultFont.glyphs);
RL_FREE(defaultFont.recs);
}
@@ -362,11 +363,14 @@ Font LoadFont(const char *fileName)
UnloadImage(image);
}
- if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
- else
+ if (isGpuReady)
{
- SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
- TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS);
+ if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
+ else
+ {
+ SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
+ TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS);
+ }
}
return font;
@@ -487,7 +491,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
};
// Set font with all data parsed from image
- font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
+ if (isGpuReady) font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
font.glyphCount = index;
font.glyphPadding = 0;
@@ -556,7 +560,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING;
Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0);
- font.texture = LoadTextureFromImage(atlas);
+ if (isGpuReady) font.texture = LoadTextureFromImage(atlas);
// Update glyphs[i].image to use alpha, required to be used on ImageDrawText()
for (int i = 0; i < font.glyphCount; i++)
@@ -577,17 +581,16 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
return font;
}
-// Check if a font is ready
-bool IsFontReady(Font font)
+// Check if a font is valid (font data loaded)
+// WARNING: GPU texture not checked
+bool IsFontValid(Font font)
{
- return ((font.texture.id > 0) && // Validate OpenGL id fot font texture atlas
- (font.baseSize > 0) && // Validate font size
+ return ((font.baseSize > 0) && // Validate font size
(font.glyphCount > 0) && // Validate font contains some glyph
(font.recs != NULL) && // Validate font recs defining glyphs on texture atlas
(font.glyphs != NULL)); // Validate glyph data is loaded
- // NOTE: Further validations could be done to verify if recs count and glyphs count
- // match glyphCount and to verify that data contained is valid (glyphs values, metrics...)
+ // NOTE: Further validations could be done to verify if recs and glyphs contain valid data (glyphs values, metrics...)
}
// Load font data for further use
@@ -674,6 +677,8 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);
+ if (chh > fontSize) TRACELOG(LOG_WARNING, "FONT: Character [0x%08x] size is bigger than expected font size", ch);
+
// Load characters images
chars[i].image.width = chw;
chars[i].image.height = chh;
@@ -946,7 +951,7 @@ void UnloadFont(Font font)
if (font.texture.id != GetFontDefault().texture.id)
{
UnloadFontData(font.glyphs, font.glyphCount);
- UnloadTexture(font.texture);
+ if (isGpuReady) UnloadTexture(font.texture);
RL_FREE(font.recs);
TRACELOGD("FONT: Unloaded font data from RAM and VRAM");
@@ -1066,7 +1071,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
byteCount += sprintf(txtData + byteCount, " Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, image.width, image.height, image.format);
#endif
byteCount += sprintf(txtData + byteCount, " // Load texture from image\n");
- byteCount += sprintf(txtData + byteCount, " font.texture = LoadTextureFromImage(imFont);\n");
+ byteCount += sprintf(txtData + byteCount, " if (isGpuReady) font.texture = LoadTextureFromImage(imFont);\n");
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
byteCount += sprintf(txtData + byteCount, " UnloadImage(imFont); // Uncompressed data can be unloaded from memory\n\n");
#endif
@@ -1277,7 +1282,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
{
Vector2 textSize = { 0 };
- if ((font.texture.id == 0) || (text == NULL)) return textSize; // Security check
+ if ((isGpuReady && (font.texture.id == 0)) || (text == NULL)) return textSize; // Security check
int size = TextLength(text); // Get size in bytes of text
int tempByteCounter = 0; // Used to count longer text line num chars
@@ -1296,15 +1301,15 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
{
byteCounter++;
- int next = 0;
- letter = GetCodepointNext(&text[i], &next);
+ int codepointByteCount = 0;
+ letter = GetCodepointNext(&text[i], &codepointByteCount);
index = GetGlyphIndex(font, letter);
- i += next;
+ i += codepointByteCount;
if (letter != '\n')
{
- if (font.glyphs[index].advanceX != 0) textWidth += font.glyphs[index].advanceX;
+ if (font.glyphs[index].advanceX > 0) textWidth += font.glyphs[index].advanceX;
else textWidth += (font.recs[index].width + font.glyphs[index].offsetX);
}
else
@@ -1924,7 +1929,8 @@ int GetCodepointCount(const char *text)
const char *CodepointToUTF8(int codepoint, int *utf8Size)
{
static char utf8[6] = { 0 };
- int size = 0; // Byte size of codepoint
+ memset(utf8, 0, 6); // Clear static array
+ int size = 0; // Byte size of codepoint
if (codepoint <= 0x7f)
{
@@ -2257,7 +2263,7 @@ static Font LoadBMFont(const char *fileName)
RL_FREE(imFonts);
- font.texture = LoadTextureFromImage(fullFont);
+ if (isGpuReady) font.texture = LoadTextureFromImage(fullFont);
// Fill font characters info data
font.baseSize = fontSize;
@@ -2299,7 +2305,7 @@ static Font LoadBMFont(const char *fileName)
UnloadImage(fullFont);
UnloadFileText(fileText);
- if (font.texture.id == 0)
+ if (isGpuReady && (font.texture.id == 0))
{
UnloadFont(font);
font = GetFontDefault();
diff --git a/src/rtextures.c b/src/rtextures.c
index 867add38e..a4534a7a2 100644
--- a/src/rtextures.c
+++ b/src/rtextures.c
@@ -225,14 +225,6 @@
#pragma GCC diagnostic pop
#endif
-#if defined(SUPPORT_FILEFORMAT_SVG)
- #define NANOSVG_IMPLEMENTATION // Expands implementation
- #include "external/nanosvg.h"
-
- #define NANOSVGRAST_IMPLEMENTATION
- #include "external/nanosvgrast.h"
-#endif
-
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@@ -335,84 +327,6 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
return image;
}
-// Load an image from a SVG file or string with custom size
-Image LoadImageSvg(const char *fileNameOrString, int width, int height)
-{
- Image image = { 0 };
-
-#if defined(SUPPORT_FILEFORMAT_SVG)
- bool isSvgStringValid = false;
-
- // Validate fileName or string
- if (fileNameOrString != NULL)
- {
- int dataSize = 0;
- unsigned char *fileData = NULL;
-
- if (FileExists(fileNameOrString))
- {
- fileData = LoadFileData(fileNameOrString, &dataSize);
- isSvgStringValid = true;
- }
- else
- {
- // Validate fileData as valid SVG string data
- //