Update raylib
This commit is contained in:
commit
2ee0842778
@ -13,10 +13,12 @@ Some people ported raylib to other languages in the form of bindings or wrappers
|
|||||||
| [raylib-cs](https://github.com/raylib-cs/raylib-cs) | **5.5** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | Zlib |
|
| [raylib-cs](https://github.com/raylib-cs/raylib-cs) | **5.5** | [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-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 |
|
| [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 |
|
||||||
| [Raylib-CSharp](https://github.com/MrScautHD/Raylib-CSharp) | **5.1-dev** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MIT |
|
| [Raylib-CSharp](https://github.com/MrScautHD/Raylib-CSharp) | **5.5** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MIT |
|
||||||
|
| [Raylib-cs.BleedingEdge](https://github.com/danilwhale/Raylib-cs.BleedingEdge) | **5.6-dev** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | Zlib |
|
||||||
| [cl-raylib](https://github.com/longlene/cl-raylib) | 4.0 | [Common Lisp](https://common-lisp.net) | MIT |
|
| [cl-raylib](https://github.com/longlene/cl-raylib) | 4.0 | [Common Lisp](https://common-lisp.net) | MIT |
|
||||||
| [claylib/wrap](https://github.com/defun-games/claylib) | 4.5 | [Common Lisp](https://common-lisp.net) | Zlib |
|
| [claylib/wrap](https://github.com/defun-games/claylib) | 4.5 | [Common Lisp](https://common-lisp.net) | Zlib |
|
||||||
| [claw-raylib](https://github.com/bohonghuang/claw-raylib) | **auto** | [Common Lisp](https://common-lisp.net) | Apache-2.0 |
|
| [claw-raylib](https://github.com/bohonghuang/claw-raylib) | **auto** | [Common Lisp](https://common-lisp.net) | Apache-2.0 |
|
||||||
|
| [raylib](https://github.com/fosskers/raylib) | 5.5 | [Common Lisp](https://common-lisp.net) | MPL-2.0 |
|
||||||
| [chez-raylib](https://github.com/Yunoinsky/chez-raylib) | **auto** | [Chez Scheme](https://cisco.github.io/ChezScheme) | GPLv3 |
|
| [chez-raylib](https://github.com/Yunoinsky/chez-raylib) | **auto** | [Chez Scheme](https://cisco.github.io/ChezScheme) | GPLv3 |
|
||||||
| [CLIPSraylib](https://github.com/mrryanjohnston/CLIPSraylib) | **auto** | [CLIPS](https://www.clipsrules.net/) | MIT |
|
| [CLIPSraylib](https://github.com/mrryanjohnston/CLIPSraylib) | **auto** | [CLIPS](https://www.clipsrules.net/) | MIT |
|
||||||
| [raylib-cr](https://github.com/sol-vin/raylib-cr) | 4.6-dev (5e1a81) | [Crystal](https://crystal-lang.org) | Apache-2.0 |
|
| [raylib-cr](https://github.com/sol-vin/raylib-cr) | 4.6-dev (5e1a81) | [Crystal](https://crystal-lang.org) | Apache-2.0 |
|
||||||
@ -93,6 +95,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
|
|||||||
| [raylib-apl](https://github.com/Brian-ED/raylib-apl) | **5.0** | [Dyalog APL](https://www.dyalog.com/) | MIT |
|
| [raylib-apl](https://github.com/Brian-ED/raylib-apl) | **5.0** | [Dyalog APL](https://www.dyalog.com/) | MIT |
|
||||||
| [raylib-jai](https://github.com/ahmedqarmout2/raylib-jai) | **5.5** | [Jai](https://github.com/BSVino/JaiPrimer/blob/master/JaiPrimer.md) | MIT |
|
| [raylib-jai](https://github.com/ahmedqarmout2/raylib-jai) | **5.5** | [Jai](https://github.com/BSVino/JaiPrimer/blob/master/JaiPrimer.md) | MIT |
|
||||||
| [fnl-raylib](https://github.com/0riginaln0/fnl-raylib) | **5.5** | [Fennel](https://fennel-lang.org/) | MIT |
|
| [fnl-raylib](https://github.com/0riginaln0/fnl-raylib) | **5.5** | [Fennel](https://fennel-lang.org/) | MIT |
|
||||||
|
| [Rayua](https://github.com/uiua-lang/rayua) | **5.5** | [Uiua](https://www.uiua.org/) | **???** |
|
||||||
|
|
||||||
### Utility Wrapers
|
### Utility Wrapers
|
||||||
|
|
||||||
@ -103,6 +106,7 @@ These are utility wrappers for specific languages, they are not required to use
|
|||||||
| [claylib](https://github.com/defun-games/claylib) | 4.5 | [Common Lisp](https://common-lisp.net) | 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 |
|
| [rayed-bqn](https://github.com/Brian-ED/rayed-bqn) | **5.0** | [BQN](https://mlochbaum.github.io/BQN) | MIT |
|
||||||
| [DOOR](https://github.com/RealDoigt/DOOR) | 4.0 | [D](https://dlang.org) | MIT |
|
| [DOOR](https://github.com/RealDoigt/DOOR) | 4.0 | [D](https://dlang.org) | MIT |
|
||||||
|
| [Iris](https://github.com/Marcos-cat/iris) | **5.5** | [Uiua](https://www.uiua.org/) | MIT |
|
||||||
|
|
||||||
### Older or Unmaintained Language Bindings
|
### Older or Unmaintained Language Bindings
|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@ const builtin = @import("builtin");
|
|||||||
/// Minimum supported version of Zig
|
/// Minimum supported version of Zig
|
||||||
const min_ver = "0.13.0";
|
const min_ver = "0.13.0";
|
||||||
|
|
||||||
|
const emccOutputDir = "zig-out" ++ std.fs.path.sep_str ++ "htmlout" ++ std.fs.path.sep_str;
|
||||||
|
const emccOutputFile = "index.html";
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
const order = std.SemanticVersion.order;
|
const order = std.SemanticVersion.order;
|
||||||
const parse = std.SemanticVersion.parse;
|
const parse = std.SemanticVersion.parse;
|
||||||
@ -45,6 +48,26 @@ fn emSdkSetupStep(b: *std.Build, emsdk: *std.Build.Dependency) !?*std.Build.Step
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adapted from Not-Nik/raylib-zig
|
||||||
|
fn emscriptenRunStep(b: *std.Build, emsdk: *std.Build.Dependency, examplePath: []const u8) !*std.Build.Step.Run {
|
||||||
|
const dot_emsc_path = emsdk.path("upstream/emscripten/cache/sysroot/include").getPath(b);
|
||||||
|
// If compiling on windows , use emrun.bat.
|
||||||
|
const emrunExe = switch (builtin.os.tag) {
|
||||||
|
.windows => "emrun.bat",
|
||||||
|
else => "emrun",
|
||||||
|
};
|
||||||
|
var emrun_run_arg = try b.allocator.alloc(u8, dot_emsc_path.len + emrunExe.len + 1);
|
||||||
|
defer b.allocator.free(emrun_run_arg);
|
||||||
|
|
||||||
|
if (b.sysroot == null) {
|
||||||
|
emrun_run_arg = try std.fmt.bufPrint(emrun_run_arg, "{s}" ++ std.fs.path.sep_str ++ "{s}", .{ emsdk.path("upstream/emscripten").getPath(b), emrunExe });
|
||||||
|
} else {
|
||||||
|
emrun_run_arg = try std.fmt.bufPrint(emrun_run_arg, "{s}" ++ std.fs.path.sep_str ++ "{s}", .{ dot_emsc_path, emrunExe });
|
||||||
|
}
|
||||||
|
const run_cmd = b.addSystemCommand(&.{ emrun_run_arg, examplePath });
|
||||||
|
return run_cmd;
|
||||||
|
}
|
||||||
|
|
||||||
/// A list of all flags from `src/config.h` that one may override
|
/// A list of all flags from `src/config.h` that one may override
|
||||||
const config_h_flags = outer: {
|
const config_h_flags = outer: {
|
||||||
// Set this value higher if compile errors happen as `src/config.h` gets larger
|
// Set this value higher if compile errors happen as `src/config.h` gets larger
|
||||||
@ -205,7 +228,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
|||||||
raylib.root_module.addCMacro("PLATFORM_DRM", "");
|
raylib.root_module.addCMacro("PLATFORM_DRM", "");
|
||||||
raylib.root_module.addCMacro("EGL_NO_X11", "");
|
raylib.root_module.addCMacro("EGL_NO_X11", "");
|
||||||
raylib.root_module.addCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", "");
|
raylib.root_module.addCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", "");
|
||||||
} else if (target.result.abi == .android) {
|
} else if (target.result.abi.isAndroid()) {
|
||||||
|
|
||||||
//these are the only tag options per https://developer.android.com/ndk/guides/other_build_systems
|
//these are the only tag options per https://developer.android.com/ndk/guides/other_build_systems
|
||||||
const hostTuple = switch (builtin.target.os.tag) {
|
const hostTuple = switch (builtin.target.os.tag) {
|
||||||
@ -215,7 +238,14 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
|||||||
else => @panic("unsupported host OS"),
|
else => @panic("unsupported host OS"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const androidTriple = try target.result.linuxTriple(b.allocator);
|
const androidTriple = switch (target.result.cpu.arch) {
|
||||||
|
.x86 => "i686-linux-android",
|
||||||
|
.x86_64 => "x86_64-linux-android",
|
||||||
|
.arm => "arm-linux-androideabi",
|
||||||
|
.aarch64 => "aarch64-linux-android",
|
||||||
|
.riscv64 => "riscv64-linux-android",
|
||||||
|
else => error.InvalidAndroidTarget,
|
||||||
|
} catch @panic("invalid android target!");
|
||||||
const androidNdkPathString: []const u8 = options.android_ndk;
|
const androidNdkPathString: []const u8 = options.android_ndk;
|
||||||
if (androidNdkPathString.len < 1) @panic("no ndk path provided and ANDROID_NDK_HOME is not set");
|
if (androidNdkPathString.len < 1) @panic("no ndk path provided and ANDROID_NDK_HOME is not set");
|
||||||
const androidApiLevel: []const u8 = options.android_api_version;
|
const androidApiLevel: []const u8 = options.android_api_version;
|
||||||
@ -249,6 +279,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
|||||||
raylib.root_module.linkSystemLibrary("GLESv2", .{});
|
raylib.root_module.linkSystemLibrary("GLESv2", .{});
|
||||||
raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", "");
|
raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", "");
|
||||||
}
|
}
|
||||||
|
raylib.root_module.linkSystemLibrary("EGL", .{});
|
||||||
|
|
||||||
setDesktopPlatform(raylib, .android);
|
setDesktopPlatform(raylib, .android);
|
||||||
} else {
|
} else {
|
||||||
@ -331,7 +362,6 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
|||||||
setDesktopPlatform(raylib, options.platform);
|
setDesktopPlatform(raylib, options.platform);
|
||||||
},
|
},
|
||||||
.emscripten => {
|
.emscripten => {
|
||||||
// Include emscripten for cross compilation
|
|
||||||
if (b.lazyDependency("emsdk", .{})) |dep| {
|
if (b.lazyDependency("emsdk", .{})) |dep| {
|
||||||
if (try emSdkSetupStep(b, dep)) |emSdkStep| {
|
if (try emSdkSetupStep(b, dep)) |emSdkStep| {
|
||||||
raylib.step.dependOn(&emSdkStep.step);
|
raylib.step.dependOn(&emSdkStep.step);
|
||||||
@ -358,8 +388,8 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
|||||||
return raylib;
|
return raylib;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addRaygui(b: *std.Build, raylib: *std.Build.Step.Compile, raygui_dep: *std.Build.Dependency) void {
|
pub fn addRaygui(b: *std.Build, raylib: *std.Build.Step.Compile, raygui_dep: *std.Build.Dependency, options: Options) void {
|
||||||
const raylib_dep = b.dependencyFromBuildZig(@This(), .{});
|
const raylib_dep = b.dependencyFromBuildZig(@This(), options);
|
||||||
var gen_step = b.addWriteFiles();
|
var gen_step = b.addWriteFiles();
|
||||||
raylib.step.dependOn(&gen_step.step);
|
raylib.step.dependOn(&gen_step.step);
|
||||||
|
|
||||||
@ -503,12 +533,9 @@ fn addExamples(
|
|||||||
optimize: std.builtin.OptimizeMode,
|
optimize: std.builtin.OptimizeMode,
|
||||||
raylib: *std.Build.Step.Compile,
|
raylib: *std.Build.Step.Compile,
|
||||||
) !*std.Build.Step {
|
) !*std.Build.Step {
|
||||||
if (target.result.os.tag == .emscripten) {
|
|
||||||
return &b.addFail("Emscripten building via Zig unsupported").step;
|
|
||||||
}
|
|
||||||
|
|
||||||
const all = b.step(module, "All " ++ module ++ " examples");
|
const all = b.step(module, "All " ++ module ++ " examples");
|
||||||
const module_subpath = b.pathJoin(&.{ "examples", module });
|
const module_subpath = b.pathJoin(&.{ "examples", module });
|
||||||
|
const module_resources = b.pathJoin(&.{ module_subpath, "resources@resources" });
|
||||||
var dir = try std.fs.cwd().openDir(b.pathFromRoot(module_subpath), .{ .iterate = true });
|
var dir = try std.fs.cwd().openDir(b.pathFromRoot(module_subpath), .{ .iterate = true });
|
||||||
defer if (comptime builtin.zig_version.minor >= 12) dir.close();
|
defer if (comptime builtin.zig_version.minor >= 12) dir.close();
|
||||||
|
|
||||||
@ -522,6 +549,88 @@ fn addExamples(
|
|||||||
// zig's mingw headers do not include pthread.h
|
// zig's mingw headers do not include pthread.h
|
||||||
if (std.mem.eql(u8, "core_loading_thread", name) and target.result.os.tag == .windows) continue;
|
if (std.mem.eql(u8, "core_loading_thread", name) and target.result.os.tag == .windows) continue;
|
||||||
|
|
||||||
|
if (target.result.os.tag == .emscripten) {
|
||||||
|
const exe_lib = b.addStaticLibrary(.{
|
||||||
|
.name = name,
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
exe_lib.addCSourceFile(.{
|
||||||
|
.file = b.path(path),
|
||||||
|
.flags = &.{},
|
||||||
|
});
|
||||||
|
exe_lib.linkLibC();
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, name, "rlgl_standalone")) {
|
||||||
|
//TODO: Make rlgl_standalone example work
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (std.mem.eql(u8, name, "raylib_opengl_interop")) {
|
||||||
|
//TODO: Make raylib_opengl_interop example work
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
exe_lib.linkLibrary(raylib);
|
||||||
|
|
||||||
|
// Include emscripten for cross compilation
|
||||||
|
if (b.lazyDependency("emsdk", .{})) |emsdk_dep| {
|
||||||
|
if (try emSdkSetupStep(b, emsdk_dep)) |emSdkStep| {
|
||||||
|
exe_lib.step.dependOn(&emSdkStep.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
exe_lib.addIncludePath(emsdk_dep.path("upstream/emscripten/cache/sysroot/include"));
|
||||||
|
|
||||||
|
// Create the output directory because emcc can't do it.
|
||||||
|
const emccOutputDirExample = b.pathJoin(&.{ emccOutputDir, name, std.fs.path.sep_str });
|
||||||
|
const mkdir_command = switch (builtin.os.tag) {
|
||||||
|
.windows => b.addSystemCommand(&.{ "cmd.exe", "/c", "if", "not", "exist", emccOutputDirExample, "mkdir", emccOutputDirExample }),
|
||||||
|
else => b.addSystemCommand(&.{ "mkdir", "-p", emccOutputDirExample }),
|
||||||
|
};
|
||||||
|
|
||||||
|
const emcc_exe = switch (builtin.os.tag) {
|
||||||
|
.windows => "emcc.bat",
|
||||||
|
else => "emcc",
|
||||||
|
};
|
||||||
|
|
||||||
|
const emcc_exe_path = b.pathJoin(&.{ emsdk_dep.path("upstream/emscripten").getPath(b), emcc_exe });
|
||||||
|
const emcc_command = b.addSystemCommand(&[_][]const u8{emcc_exe_path});
|
||||||
|
emcc_command.step.dependOn(&mkdir_command.step);
|
||||||
|
const emccOutputDirExampleWithFile = b.pathJoin(&.{ emccOutputDir, name, std.fs.path.sep_str, emccOutputFile });
|
||||||
|
emcc_command.addArgs(&[_][]const u8{
|
||||||
|
"-o",
|
||||||
|
emccOutputDirExampleWithFile,
|
||||||
|
"-sFULL-ES3=1",
|
||||||
|
"-sUSE_GLFW=3",
|
||||||
|
"-sSTACK_OVERFLOW_CHECK=1",
|
||||||
|
"-sEXPORTED_RUNTIME_METHODS=['requestFullscreen']",
|
||||||
|
"-sASYNCIFY",
|
||||||
|
"-O0",
|
||||||
|
"--emrun",
|
||||||
|
"--preload-file",
|
||||||
|
module_resources,
|
||||||
|
"--shell-file",
|
||||||
|
b.path("src/shell.html").getPath(b),
|
||||||
|
});
|
||||||
|
|
||||||
|
const link_items: []const *std.Build.Step.Compile = &.{
|
||||||
|
raylib,
|
||||||
|
exe_lib,
|
||||||
|
};
|
||||||
|
for (link_items) |item| {
|
||||||
|
emcc_command.addFileArg(item.getEmittedBin());
|
||||||
|
emcc_command.step.dependOn(&item.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
const run_step = try emscriptenRunStep(b, emsdk_dep, emccOutputDirExampleWithFile);
|
||||||
|
run_step.step.dependOn(&emcc_command.step);
|
||||||
|
run_step.addArg("--no_browser");
|
||||||
|
const run_option = b.step(name, name);
|
||||||
|
|
||||||
|
run_option.dependOn(&run_step.step);
|
||||||
|
|
||||||
|
all.dependOn(&emcc_command.step);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const exe = b.addExecutable(.{
|
const exe = b.addExecutable(.{
|
||||||
.name = name,
|
.name = name,
|
||||||
.target = target,
|
.target = target,
|
||||||
@ -588,6 +697,7 @@ fn addExamples(
|
|||||||
|
|
||||||
all.dependOn(&install_cmd.step);
|
all.dependOn(&install_cmd.step);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return all;
|
return all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
.lazy = true,
|
.lazy = true,
|
||||||
},
|
},
|
||||||
.emsdk = .{
|
.emsdk = .{
|
||||||
.url = "git+https://github.com/emscripten-core/emsdk#3.1.50",
|
.url = "git+https://github.com/emscripten-core/emsdk#4.0.9",
|
||||||
.hash = "N-V-__8AALRTBQDo_pUJ8IQ-XiIyYwDKQVwnr7-7o5kvPDGE",
|
.hash = "N-V-__8AAJl1DwBezhYo_VE6f53mPVm00R-Fk28NPW7P14EQ",
|
||||||
.lazy = true,
|
.lazy = true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -23,5 +23,6 @@
|
|||||||
"build.zig.zon",
|
"build.zig.zon",
|
||||||
"src",
|
"src",
|
||||||
"examples",
|
"examples",
|
||||||
|
"LICENSE",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -547,7 +547,8 @@ SHAPES = \
|
|||||||
shapes/shapes_rectangle_advanced \
|
shapes/shapes_rectangle_advanced \
|
||||||
shapes/shapes_rectangle_scaling \
|
shapes/shapes_rectangle_scaling \
|
||||||
shapes/shapes_splines_drawing \
|
shapes/shapes_splines_drawing \
|
||||||
shapes/shapes_top_down_lights
|
shapes/shapes_top_down_lights \
|
||||||
|
shapes/shapes_digital_clock
|
||||||
|
|
||||||
TEXTURES = \
|
TEXTURES = \
|
||||||
textures/textures_background_scrolling \
|
textures/textures_background_scrolling \
|
||||||
|
@ -429,7 +429,8 @@ SHAPES = \
|
|||||||
shapes/shapes_rectangle_advanced \
|
shapes/shapes_rectangle_advanced \
|
||||||
shapes/shapes_rectangle_scaling \
|
shapes/shapes_rectangle_scaling \
|
||||||
shapes/shapes_splines_drawing \
|
shapes/shapes_splines_drawing \
|
||||||
shapes/shapes_top_down_lights
|
shapes/shapes_top_down_lights \
|
||||||
|
shapes/shapes_digital_clock
|
||||||
|
|
||||||
TEXTURES = \
|
TEXTURES = \
|
||||||
textures/textures_background_scrolling \
|
textures/textures_background_scrolling \
|
||||||
|
@ -85,39 +85,39 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes](
|
|||||||
| 51 | [shapes_top_down_lights](shapes/shapes_top_down_lights.c) | <img src="shapes/shapes_top_down_lights.png" alt="shapes_top_down_lights" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 4.2 | [Jeffery Myers](https://github.com/JeffM2501) |
|
| 51 | [shapes_top_down_lights](shapes/shapes_top_down_lights.c) | <img src="shapes/shapes_top_down_lights.png" alt="shapes_top_down_lights" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 4.2 | [Jeffery Myers](https://github.com/JeffM2501) |
|
||||||
| 52 | [shapes_rectangle_advanced](shapes/shapes_rectangle_advanced.c) | <img src="shapes/shapes_rectangle_advanced.png" alt="shapes_rectangle_advanced" width="80"> | ⭐️⭐️⭐️⭐️ | 5.5 | 5.5 | [Everton Jr.](https://github.com/evertonse) |
|
| 52 | [shapes_rectangle_advanced](shapes/shapes_rectangle_advanced.c) | <img src="shapes/shapes_rectangle_advanced.png" alt="shapes_rectangle_advanced" width="80"> | ⭐️⭐️⭐️⭐️ | 5.5 | 5.5 | [Everton Jr.](https://github.com/evertonse) |
|
||||||
| 53 | [shapes_splines_drawing](shapes/shapes_splines_drawing.c) | <img src="shapes/shapes_splines_drawing.png" alt="shapes_splines_drawing" width="80"> | ⭐️⭐️⭐️☆ | 5.0 | 5.0 | [Ray](https://github.com/raysan5) |
|
| 53 | [shapes_splines_drawing](shapes/shapes_splines_drawing.c) | <img src="shapes/shapes_splines_drawing.png" alt="shapes_splines_drawing" width="80"> | ⭐️⭐️⭐️☆ | 5.0 | 5.0 | [Ray](https://github.com/raysan5) |
|
||||||
|
| 54 | [shapes_digital_clock](shapes/shapes_digital_clock.c) | <img src="shapes/shapes_digital_clock.png" alt="shapes_digital_clock" width="80"> | ⭐️⭐️☆☆ | 5.5 | 5.5 | [Hamza RAHAL](https://github.com/rhmz-rhl) |
|
||||||
### category: textures
|
### category: textures
|
||||||
|
|
||||||
Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/textures.c) modul
|
Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/textures.c) modul
|
||||||
|
|
||||||
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
||||||
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
||||||
| 54 | [textures_logo_raylib](textures/textures_logo_raylib.c) | <img src="textures/textures_logo_raylib.png" alt="textures_logo_raylib" width="80"> | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
|
| 55 | [textures_logo_raylib](textures/textures_logo_raylib.c) | <img src="textures/textures_logo_raylib.png" alt="textures_logo_raylib" width="80"> | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 55 | [textures_srcrec_dstrec](textures/textures_srcrec_dstrec.c) | <img src="textures/textures_srcrec_dstrec.png" alt="textures_srcrec_dstrec" width="80"> | ⭐️⭐️⭐️☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
|
| 56 | [textures_srcrec_dstrec](textures/textures_srcrec_dstrec.c) | <img src="textures/textures_srcrec_dstrec.png" alt="textures_srcrec_dstrec" width="80"> | ⭐️⭐️⭐️☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
|
||||||
| 56 | [textures_image_drawing](textures/textures_image_drawing.c) | <img src="textures/textures_image_drawing.png" alt="textures_image_drawing" width="80"> | ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
|
| 57 | [textures_image_drawing](textures/textures_image_drawing.c) | <img src="textures/textures_image_drawing.png" alt="textures_image_drawing" width="80"> | ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
|
||||||
| 57 | [textures_image_generation](textures/textures_image_generation.c) | <img src="textures/textures_image_generation.png" alt="textures_image_generation" width="80"> | ⭐️⭐️☆☆ | 1.8 | 1.8 | [Wilhem Barbier](https://github.com/nounoursheureux) |
|
| 58 | [textures_image_generation](textures/textures_image_generation.c) | <img src="textures/textures_image_generation.png" alt="textures_image_generation" width="80"> | ⭐️⭐️☆☆ | 1.8 | 1.8 | [Wilhem Barbier](https://github.com/nounoursheureux) |
|
||||||
| 58 | [textures_image_loading](textures/textures_image_loading.c) | <img src="textures/textures_image_loading.png" alt="textures_image_loading" width="80"> | ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
|
| 59 | [textures_image_loading](textures/textures_image_loading.c) | <img src="textures/textures_image_loading.png" alt="textures_image_loading" width="80"> | ⭐️☆☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
|
||||||
| 59 | [textures_image_processing](textures/textures_image_processing.c) | <img src="textures/textures_image_processing.png" alt="textures_image_processing" width="80"> | ⭐️⭐️⭐️☆ | 1.4 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 60 | [textures_image_processing](textures/textures_image_processing.c) | <img src="textures/textures_image_processing.png" alt="textures_image_processing" width="80"> | ⭐️⭐️⭐️☆ | 1.4 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 60 | [textures_image_text](textures/textures_image_text.c) | <img src="textures/textures_image_text.png" alt="textures_image_text" width="80"> | ⭐️⭐️☆☆ | 1.8 | 4.0 | [Ray](https://github.com/raysan5) |
|
| 61 | [textures_image_text](textures/textures_image_text.c) | <img src="textures/textures_image_text.png" alt="textures_image_text" width="80"> | ⭐️⭐️☆☆ | 1.8 | 4.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 61 | [textures_to_image](textures/textures_to_image.c) | <img src="textures/textures_to_image.png" alt="textures_to_image" width="80"> | ⭐️☆☆☆ | 1.3 | 4.0 | [Ray](https://github.com/raysan5) |
|
| 62 | [textures_to_image](textures/textures_to_image.c) | <img src="textures/textures_to_image.png" alt="textures_to_image" width="80"> | ⭐️☆☆☆ | 1.3 | 4.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 62 | [textures_raw_data](textures/textures_raw_data.c) | <img src="textures/textures_raw_data.png" alt="textures_raw_data" width="80"> | ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 63 | [textures_raw_data](textures/textures_raw_data.c) | <img src="textures/textures_raw_data.png" alt="textures_raw_data" width="80"> | ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 63 | [textures_particles_blending](textures/textures_particles_blending.c) | <img src="textures/textures_particles_blending.png" alt="textures_particles_blending" width="80"> | ⭐️☆☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 64 | [textures_particles_blending](textures/textures_particles_blending.c) | <img src="textures/textures_particles_blending.png" alt="textures_particles_blending" width="80"> | ⭐️☆☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 64 | [textures_npatch_drawing](textures/textures_npatch_drawing.c) | <img src="textures/textures_npatch_drawing.png" alt="textures_npatch_drawing" width="80"> | ⭐️⭐️⭐️☆ | 2.0 | 2.5 | [Jorge A. Gomes](https://github.com/overdev) |
|
| 65 | [textures_npatch_drawing](textures/textures_npatch_drawing.c) | <img src="textures/textures_npatch_drawing.png" alt="textures_npatch_drawing" width="80"> | ⭐️⭐️⭐️☆ | 2.0 | 2.5 | [Jorge A. Gomes](https://github.com/overdev) |
|
||||||
| 65 | [textures_background_scrolling](textures/textures_background_scrolling.c) | <img src="textures/textures_background_scrolling.png" alt="textures_background_scrolling" width="80"> | ⭐️☆☆☆ | 2.0 | 2.5 | [Ray](https://github.com/raysan5) |
|
| 66 | [textures_background_scrolling](textures/textures_background_scrolling.c) | <img src="textures/textures_background_scrolling.png" alt="textures_background_scrolling" width="80"> | ⭐️☆☆☆ | 2.0 | 2.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 66 | [textures_sprite_anim](textures/textures_sprite_anim.c) | <img src="textures/textures_sprite_anim.png" alt="textures_sprite_anim" width="80"> | ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
|
| 67 | [textures_sprite_anim](textures/textures_sprite_anim.c) | <img src="textures/textures_sprite_anim.png" alt="textures_sprite_anim" width="80"> | ⭐️⭐️☆☆ | 1.3 | 1.3 | [Ray](https://github.com/raysan5) |
|
||||||
| 67 | [textures_sprite_button](textures/textures_sprite_button.c) | <img src="textures/textures_sprite_button.png" alt="textures_sprite_button" width="80"> | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
|
| 68 | [textures_sprite_button](textures/textures_sprite_button.c) | <img src="textures/textures_sprite_button.png" alt="textures_sprite_button" width="80"> | ⭐️⭐️☆☆ | 2.5 | 2.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 68 | [textures_sprite_explosion](textures/textures_sprite_explosion.c) | <img src="textures/textures_sprite_explosion.png" alt="textures_sprite_explosion" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 69 | [textures_sprite_explosion](textures/textures_sprite_explosion.c) | <img src="textures/textures_sprite_explosion.png" alt="textures_sprite_explosion" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 69 | [textures_bunnymark](textures/textures_bunnymark.c) | <img src="textures/textures_bunnymark.png" alt="textures_bunnymark" width="80"> | ⭐️⭐️⭐️☆ | 1.6 | 2.5 | [Ray](https://github.com/raysan5) |
|
| 70 | [textures_bunnymark](textures/textures_bunnymark.c) | <img src="textures/textures_bunnymark.png" alt="textures_bunnymark" width="80"> | ⭐️⭐️⭐️☆ | 1.6 | 2.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 70 | [textures_mouse_painting](textures/textures_mouse_painting.c) | <img src="textures/textures_mouse_painting.png" alt="textures_mouse_painting" width="80"> | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) |
|
| 71 | [textures_mouse_painting](textures/textures_mouse_painting.c) | <img src="textures/textures_mouse_painting.png" alt="textures_mouse_painting" width="80"> | ⭐️⭐️⭐️☆ | 3.0 | 3.0 | [Chris Dill](https://github.com/MysteriousSpace) |
|
||||||
| 71 | [textures_blend_modes](textures/textures_blend_modes.c) | <img src="textures/textures_blend_modes.png" alt="textures_blend_modes" width="80"> | ⭐️☆☆☆ | 3.5 | 3.5 | [Karlo Licudine](https://github.com/accidentalrebel) |
|
| 72 | [textures_blend_modes](textures/textures_blend_modes.c) | <img src="textures/textures_blend_modes.png" alt="textures_blend_modes" width="80"> | ⭐️☆☆☆ | 3.5 | 3.5 | [Karlo Licudine](https://github.com/accidentalrebel) |
|
||||||
| 72 | [textures_draw_tiled](textures/textures_draw_tiled.c) | <img src="textures/textures_draw_tiled.png" alt="textures_draw_tiled" width="80"> | ⭐️⭐️⭐️☆ | 3.0 | 4.2 | [Vlad Adrian](https://github.com/demizdor) |
|
| 73 | [textures_draw_tiled](textures/textures_draw_tiled.c) | <img src="textures/textures_draw_tiled.png" alt="textures_draw_tiled" width="80"> | ⭐️⭐️⭐️☆ | 3.0 | 4.2 | [Vlad Adrian](https://github.com/demizdor) |
|
||||||
| 73 | [textures_polygon](textures/textures_polygon.c) | <img src="textures/textures_polygon.png" alt="textures_polygon" width="80"> | ⭐️☆☆☆ | 3.7 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
|
| 74 | [textures_polygon](textures/textures_polygon.c) | <img src="textures/textures_polygon.png" alt="textures_polygon" width="80"> | ⭐️☆☆☆ | 3.7 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
|
||||||
| 74 | [textures_fog_of_war](textures/textures_fog_of_war.c) | <img src="textures/textures_fog_of_war.png" alt="textures_fog_of_war" width="80"> | ⭐️⭐️⭐️☆ | 4.2 | 4.2 | [Ray](https://github.com/raysan5) |
|
| 75 | [textures_fog_of_war](textures/textures_fog_of_war.c) | <img src="textures/textures_fog_of_war.png" alt="textures_fog_of_war" width="80"> | ⭐️⭐️⭐️☆ | 4.2 | 4.2 | [Ray](https://github.com/raysan5) |
|
||||||
| 75 | [textures_gif_player](textures/textures_gif_player.c) | <img src="textures/textures_gif_player.png" alt="textures_gif_player" width="80"> | ⭐️⭐️⭐️☆ | 4.2 | 4.2 | [Ray](https://github.com/raysan5) |
|
| 76 | [textures_gif_player](textures/textures_gif_player.c) | <img src="textures/textures_gif_player.png" alt="textures_gif_player" width="80"> | ⭐️⭐️⭐️☆ | 4.2 | 4.2 | [Ray](https://github.com/raysan5) |
|
||||||
| 76 | [textures_image_kernel](textures/textures_image_kernel.c) | <img src="textures/textures_image_kernel.png" alt="textures_image_kernel" width="80"> | ⭐️⭐️⭐️⭐️ | 1.3 | 1.3 | [Karim Salem](https://github.com/kimo-s) |
|
| 77 | [textures_image_kernel](textures/textures_image_kernel.c) | <img src="textures/textures_image_kernel.png" alt="textures_image_kernel" width="80"> | ⭐️⭐️⭐️⭐️ | 1.3 | 1.3 | [Karim Salem](https://github.com/kimo-s) |
|
||||||
| 77 | [textures_image_channel](textures/textures_image_channel.c) | <img src="textures/textures_image_channel.png" alt="textures_image_channel" width="80"> | ⭐️⭐️☆☆ | 5.1-dev | 5.1-dev | [Bruno Cabral](https://github.com/brccabral) |
|
| 78 | [textures_image_channel](textures/textures_image_channel.c) | <img src="textures/textures_image_channel.png" alt="textures_image_channel" width="80"> | ⭐️⭐️☆☆ | 5.1-dev | 5.1-dev | [Bruno Cabral](https://github.com/brccabral) |
|
||||||
| 78 | [textures_image_rotate](textures/textures_image_rotate.c) | <img src="textures/textures_image_rotate.png" alt="textures_image_rotate" width="80"> | ⭐️⭐️☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
|
| 79 | [textures_image_rotate](textures/textures_image_rotate.c) | <img src="textures/textures_image_rotate.png" alt="textures_image_rotate" width="80"> | ⭐️⭐️☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 79 | [textures_textured_curve](textures/textures_textured_curve.c) | <img src="textures/textures_textured_curve.png" alt="textures_textured_curve" width="80"> | ⭐️⭐️⭐️☆ | 4.5 | 4.5 | [Jeffery Myers](https://github.com/JeffM2501) |
|
| 80 | [textures_textured_curve](textures/textures_textured_curve.c) | <img src="textures/textures_textured_curve.png" alt="textures_textured_curve" width="80"> | ⭐️⭐️⭐️☆ | 4.5 | 4.5 | [Jeffery Myers](https://github.com/JeffM2501) |
|
||||||
|
|
||||||
### category: text
|
### category: text
|
||||||
|
|
||||||
@ -125,18 +125,18 @@ Examples using raylib text functionality, including sprite fonts loading/generat
|
|||||||
|
|
||||||
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
||||||
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
||||||
| 80 | [text_raylib_fonts](text/text_raylib_fonts.c) | <img src="text/text_raylib_fonts.png" alt="text_raylib_fonts" width="80"> | ⭐️☆☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
|
| 81 | [text_raylib_fonts](text/text_raylib_fonts.c) | <img src="text/text_raylib_fonts.png" alt="text_raylib_fonts" width="80"> | ⭐️☆☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
|
||||||
| 81 | [text_font_spritefont](text/text_font_spritefont.c) | <img src="text/text_font_spritefont.png" alt="text_font_spritefont" width="80"> | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
|
| 82 | [text_font_spritefont](text/text_font_spritefont.c) | <img src="text/text_font_spritefont.png" alt="text_font_spritefont" width="80"> | ⭐️☆☆☆ | 1.0 | 1.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 82 | [text_font_filters](text/text_font_filters.c) | <img src="text/text_font_filters.png" alt="text_font_filters" width="80"> | ⭐️⭐️☆☆ | 1.3 | 4.2 | [Ray](https://github.com/raysan5) |
|
| 83 | [text_font_filters](text/text_font_filters.c) | <img src="text/text_font_filters.png" alt="text_font_filters" width="80"> | ⭐️⭐️☆☆ | 1.3 | 4.2 | [Ray](https://github.com/raysan5) |
|
||||||
| 83 | [text_font_loading](text/text_font_loading.c) | <img src="text/text_font_loading.png" alt="text_font_loading" width="80"> | ⭐️☆☆☆ | 1.4 | 3.0 | [Ray](https://github.com/raysan5) |
|
| 84 | [text_font_loading](text/text_font_loading.c) | <img src="text/text_font_loading.png" alt="text_font_loading" width="80"> | ⭐️☆☆☆ | 1.4 | 3.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 84 | [text_font_sdf](text/text_font_sdf.c) | <img src="text/text_font_sdf.png" alt="text_font_sdf" width="80"> | ⭐️⭐️⭐️☆ | 1.3 | 4.0 | [Ray](https://github.com/raysan5) |
|
| 85 | [text_font_sdf](text/text_font_sdf.c) | <img src="text/text_font_sdf.png" alt="text_font_sdf" width="80"> | ⭐️⭐️⭐️☆ | 1.3 | 4.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 85 | [text_format_text](text/text_format_text.c) | <img src="text/text_format_text.png" alt="text_format_text" width="80"> | ⭐️☆☆☆ | 1.1 | 3.0 | [Ray](https://github.com/raysan5) |
|
| 86 | [text_format_text](text/text_format_text.c) | <img src="text/text_format_text.png" alt="text_format_text" width="80"> | ⭐️☆☆☆ | 1.1 | 3.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 86 | [text_input_box](text/text_input_box.c) | <img src="text/text_input_box.png" alt="text_input_box" width="80"> | ⭐️⭐️☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 87 | [text_input_box](text/text_input_box.c) | <img src="text/text_input_box.png" alt="text_input_box" width="80"> | ⭐️⭐️☆☆ | 1.7 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 87 | [text_writing_anim](text/text_writing_anim.c) | <img src="text/text_writing_anim.png" alt="text_writing_anim" width="80"> | ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
|
| 88 | [text_writing_anim](text/text_writing_anim.c) | <img src="text/text_writing_anim.png" alt="text_writing_anim" width="80"> | ⭐️⭐️☆☆ | 1.4 | 1.4 | [Ray](https://github.com/raysan5) |
|
||||||
| 88 | [text_rectangle_bounds](text/text_rectangle_bounds.c) | <img src="text/text_rectangle_bounds.png" alt="text_rectangle_bounds" width="80"> | ⭐️⭐️⭐️⭐️ | 2.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) |
|
| 89 | [text_rectangle_bounds](text/text_rectangle_bounds.c) | <img src="text/text_rectangle_bounds.png" alt="text_rectangle_bounds" width="80"> | ⭐️⭐️⭐️⭐️ | 2.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) |
|
||||||
| 89 | [text_unicode](text/text_unicode.c) | <img src="text/text_unicode.png" alt="text_unicode" width="80"> | ⭐️⭐️⭐️⭐️ | 2.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) |
|
| 90 | [text_unicode](text/text_unicode.c) | <img src="text/text_unicode.png" alt="text_unicode" width="80"> | ⭐️⭐️⭐️⭐️ | 2.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) |
|
||||||
| 90 | [text_draw_3d](text/text_draw_3d.c) | <img src="text/text_draw_3d.png" alt="text_draw_3d" width="80"> | ⭐️⭐️⭐️⭐️ | 3.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) |
|
| 91 | [text_draw_3d](text/text_draw_3d.c) | <img src="text/text_draw_3d.png" alt="text_draw_3d" width="80"> | ⭐️⭐️⭐️⭐️ | 3.5 | 4.0 | [Vlad Adrian](https://github.com/demizdor) |
|
||||||
| 91 | [text_codepoints_loading](text/text_codepoints_loading.c) | <img src="text/text_codepoints_loading.png" alt="text_codepoints_loading" width="80"> | ⭐️⭐️⭐️☆ | 4.2 | 4.2 | [Ray](https://github.com/raysan5) |
|
| 92 | [text_codepoints_loading](text/text_codepoints_loading.c) | <img src="text/text_codepoints_loading.png" alt="text_codepoints_loading" width="80"> | ⭐️⭐️⭐️☆ | 4.2 | 4.2 | [Ray](https://github.com/raysan5) |
|
||||||
|
|
||||||
### category: models
|
### category: models
|
||||||
|
|
||||||
@ -144,29 +144,29 @@ Examples using raylib models functionality, including models loading/generation
|
|||||||
|
|
||||||
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
||||||
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
||||||
| 92 | [models_animation](models/models_animation.c) | <img src="models/models_animation.png" alt="models_animation" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.5 | [Culacant](https://github.com/culacant) |
|
| 93 | [models_animation](models/models_animation.c) | <img src="models/models_animation.png" alt="models_animation" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.5 | [Culacant](https://github.com/culacant) |
|
||||||
| 93 | [models_billboard](models/models_billboard.c) | <img src="models/models_billboard.png" alt="models_billboard" width="80"> | ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 94 | [models_billboard](models/models_billboard.c) | <img src="models/models_billboard.png" alt="models_billboard" width="80"> | ⭐️⭐️⭐️☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 94 | [models_box_collisions](models/models_box_collisions.c) | <img src="models/models_box_collisions.png" alt="models_box_collisions" width="80"> | ⭐️☆☆☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 95 | [models_box_collisions](models/models_box_collisions.c) | <img src="models/models_box_collisions.png" alt="models_box_collisions" width="80"> | ⭐️☆☆☆ | 1.3 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 95 | [models_cubicmap](models/models_cubicmap.c) | <img src="models/models_cubicmap.png" alt="models_cubicmap" width="80"> | ⭐️⭐️☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 96 | [models_cubicmap](models/models_cubicmap.c) | <img src="models/models_cubicmap.png" alt="models_cubicmap" width="80"> | ⭐️⭐️☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 96 | [models_first_person_maze](models/models_first_person_maze.c) | <img src="models/models_first_person_maze.png" alt="models_first_person_maze" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 97 | [models_first_person_maze](models/models_first_person_maze.c) | <img src="models/models_first_person_maze.png" alt="models_first_person_maze" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 97 | [models_geometric_shapes](models/models_geometric_shapes.c) | <img src="models/models_geometric_shapes.png" alt="models_geometric_shapes" width="80"> | ⭐️☆☆☆ | 1.0 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 98 | [models_geometric_shapes](models/models_geometric_shapes.c) | <img src="models/models_geometric_shapes.png" alt="models_geometric_shapes" width="80"> | ⭐️☆☆☆ | 1.0 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 98 | [models_mesh_generation](models/models_mesh_generation.c) | <img src="models/models_mesh_generation.png" alt="models_mesh_generation" width="80"> | ⭐️⭐️☆☆ | 1.8 | 4.0 | [Ray](https://github.com/raysan5) |
|
| 99 | [models_mesh_generation](models/models_mesh_generation.c) | <img src="models/models_mesh_generation.png" alt="models_mesh_generation" width="80"> | ⭐️⭐️☆☆ | 1.8 | 4.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 99 | [models_mesh_picking](models/models_mesh_picking.c) | <img src="models/models_mesh_picking.png" alt="models_mesh_picking" width="80"> | ⭐️⭐️⭐️☆ | 1.7 | 4.0 | [Joel Davis](https://github.com/joeld42) |
|
| 100 | [models_mesh_picking](models/models_mesh_picking.c) | <img src="models/models_mesh_picking.png" alt="models_mesh_picking" width="80"> | ⭐️⭐️⭐️☆ | 1.7 | 4.0 | [Joel Davis](https://github.com/joeld42) |
|
||||||
| 100 | [models_loading](models/models_loading.c) | <img src="models/models_loading.png" alt="models_loading" width="80"> | ⭐️☆☆☆ | 2.0 | 4.2 | [Ray](https://github.com/raysan5) |
|
| 101 | [models_loading](models/models_loading.c) | <img src="models/models_loading.png" alt="models_loading" width="80"> | ⭐️☆☆☆ | 2.0 | 4.2 | [Ray](https://github.com/raysan5) |
|
||||||
| 101 | [models_loading_gltf](models/models_loading_gltf.c) | <img src="models/models_loading_gltf.png" alt="models_loading_gltf" width="80"> | ⭐️☆☆☆ | 3.7 | 4.2 | [Ray](https://github.com/raysan5) |
|
| 102 | [models_loading_gltf](models/models_loading_gltf.c) | <img src="models/models_loading_gltf.png" alt="models_loading_gltf" width="80"> | ⭐️☆☆☆ | 3.7 | 4.2 | [Ray](https://github.com/raysan5) |
|
||||||
| 102 | [models_loading_vox](models/models_loading_vox.c) | <img src="models/models_loading_vox.png" alt="models_loading_vox" width="80"> | ⭐️☆☆☆ | 4.0 | 4.0 | [Johann Nadalutti](https://github.com/procfxgen) |
|
| 103 | [models_loading_vox](models/models_loading_vox.c) | <img src="models/models_loading_vox.png" alt="models_loading_vox" width="80"> | ⭐️☆☆☆ | 4.0 | 4.0 | [Johann Nadalutti](https://github.com/procfxgen) |
|
||||||
| 103 | [models_loading_m3d](models/models_loading_m3d.c) | <img src="models/models_loading_m3d.png" alt="models_loading_m3d" width="80"> | ⭐️⭐️☆☆ | 4.5 | 4.5 | [bzt](https://bztsrc.gitlab.io/model3d) |
|
| 104 | [models_loading_m3d](models/models_loading_m3d.c) | <img src="models/models_loading_m3d.png" alt="models_loading_m3d" width="80"> | ⭐️⭐️☆☆ | 4.5 | 4.5 | [bzt](https://bztsrc.gitlab.io/model3d) |
|
||||||
| 104 | [models_orthographic_projection](models/models_orthographic_projection.c) | <img src="models/models_orthographic_projection.png" alt="models_orthographic_projection" width="80"> | ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) |
|
| 105 | [models_orthographic_projection](models/models_orthographic_projection.c) | <img src="models/models_orthographic_projection.png" alt="models_orthographic_projection" width="80"> | ⭐️☆☆☆ | 2.0 | 3.7 | [Max Danielsson](https://github.com/autious) |
|
||||||
| 105 | [models_point_rendering](models/models_point_rendering.c) | <img src="models/models_point_rendering.png" alt="models_point_rendering" width="80"> | ⭐️⭐️⭐️☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) |
|
| 106 | [models_point_rendering](models/models_point_rendering.c) | <img src="models/models_point_rendering.png" alt="models_point_rendering" width="80"> | ⭐️⭐️⭐️☆ | 5.0 | 5.0 | [Reese Gallagher](https://github.com/satchelfrost) |
|
||||||
| 106 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | <img src="models/models_rlgl_solar_system.png" alt="models_rlgl_solar_system" width="80"> | ⭐️⭐️⭐️⭐️ | 2.5 | 4.0 | [Ray](https://github.com/raysan5) |
|
| 107 | [models_rlgl_solar_system](models/models_rlgl_solar_system.c) | <img src="models/models_rlgl_solar_system.png" alt="models_rlgl_solar_system" width="80"> | ⭐️⭐️⭐️⭐️ | 2.5 | 4.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 107 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | <img src="models/models_yaw_pitch_roll.png" alt="models_yaw_pitch_roll" width="80"> | ⭐️⭐️☆☆ | 1.8 | 4.0 | [Berni](https://github.com/Berni8k) |
|
| 108 | [models_yaw_pitch_roll](models/models_yaw_pitch_roll.c) | <img src="models/models_yaw_pitch_roll.png" alt="models_yaw_pitch_roll" width="80"> | ⭐️⭐️☆☆ | 1.8 | 4.0 | [Berni](https://github.com/Berni8k) |
|
||||||
| 108 | [models_waving_cubes](models/models_waving_cubes.c) | <img src="models/models_waving_cubes.png" alt="models_waving_cubes" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Codecat](https://github.com/codecat) |
|
| 109 | [models_waving_cubes](models/models_waving_cubes.c) | <img src="models/models_waving_cubes.png" alt="models_waving_cubes" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Codecat](https://github.com/codecat) |
|
||||||
| 109 | [models_heightmap](models/models_heightmap.c) | <img src="models/models_heightmap.png" alt="models_heightmap" width="80"> | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 110 | [models_heightmap](models/models_heightmap.c) | <img src="models/models_heightmap.png" alt="models_heightmap" width="80"> | ⭐️☆☆☆ | 1.8 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 110 | [models_skybox](models/models_skybox.c) | <img src="models/models_skybox.png" alt="models_skybox" width="80"> | ⭐️⭐️☆☆ | 1.8 | 4.0 | [Ray](https://github.com/raysan5) |
|
| 111 | [models_skybox](models/models_skybox.c) | <img src="models/models_skybox.png" alt="models_skybox" width="80"> | ⭐️⭐️☆☆ | 1.8 | 4.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 111 | [models_draw_cube_texture](models/models_draw_cube_texture.c) | <img src="models/models_draw_cube_texture.png" alt="models_draw_cube_texture" width="80"> | ⭐️⭐️☆☆ | 4.5 | 4.5 | [Ray](https://github.com/raysan5) |
|
| 112 | [models_draw_cube_texture](models/models_draw_cube_texture.c) | <img src="models/models_draw_cube_texture.png" alt="models_draw_cube_texture" width="80"> | ⭐️⭐️☆☆ | 4.5 | 4.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 112 | [models_gpu_skinning](models/models_gpu_skinning.c) | <img src="models/models_gpu_skinning.png" alt="models_gpu_skinning" width="80"> | ⭐️⭐️⭐️☆ | 4.5 | 4.5 | [Daniel Holden](https://github.com/orangeduck) |
|
| 113 | [models_gpu_skinning](models/models_gpu_skinning.c) | <img src="models/models_gpu_skinning.png" alt="models_gpu_skinning" width="80"> | ⭐️⭐️⭐️☆ | 4.5 | 4.5 | [Daniel Holden](https://github.com/orangeduck) |
|
||||||
| 113 | [models_bone_socket](models/models_bone_socket.c) | <img src="models/models_bone_socket.png" alt="models_bone_socket" width="80"> | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [iP](https://github.com/ipzaur) |
|
| 114 | [models_bone_socket](models/models_bone_socket.c) | <img src="models/models_bone_socket.png" alt="models_bone_socket" width="80"> | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [iP](https://github.com/ipzaur) |
|
||||||
| 114 | [models_tesseract_view](models/models_tesseract_view.c) | <img src="models/models_tesseract_view.png" alt="models_tesseract_view" width="80"> | ⭐️⭐️☆☆ | 5.6-dev | 5.6-dev | [Timothy van der Valk](https://github.com/arceryz) |
|
| 115 | [models_tesseract_view](models/models_tesseract_view.c) | <img src="models/models_tesseract_view.png" alt="models_tesseract_view" width="80"> | ⭐️⭐️☆☆ | 5.6-dev | 5.6-dev | [Timothy van der Valk](https://github.com/arceryz) |
|
||||||
|
|
||||||
### category: shaders
|
### category: shaders
|
||||||
|
|
||||||
@ -174,34 +174,34 @@ Examples using raylib shaders functionality, including shaders loading, paramete
|
|||||||
|
|
||||||
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
||||||
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
||||||
| 115 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | <img src="shaders/shaders_basic_lighting.png" alt="shaders_basic_lighting" width="80"> | ⭐️⭐️⭐️⭐️ | 3.0 | 4.2 | [Chris Camacho](https://github.com/chriscamacho) |
|
| 116 | [shaders_basic_lighting](shaders/shaders_basic_lighting.c) | <img src="shaders/shaders_basic_lighting.png" alt="shaders_basic_lighting" width="80"> | ⭐️⭐️⭐️⭐️ | 3.0 | 4.2 | [Chris Camacho](https://github.com/chriscamacho) |
|
||||||
| 116 | [shaders_model_shader](shaders/shaders_model_shader.c) | <img src="shaders/shaders_model_shader.png" alt="shaders_model_shader" width="80"> | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) |
|
| 117 | [shaders_model_shader](shaders/shaders_model_shader.c) | <img src="shaders/shaders_model_shader.png" alt="shaders_model_shader" width="80"> | ⭐️⭐️☆☆ | 1.3 | 3.7 | [Ray](https://github.com/raysan5) |
|
||||||
| 117 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | <img src="shaders/shaders_shapes_textures.png" alt="shaders_shapes_textures" width="80"> | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
|
| 118 | [shaders_shapes_textures](shaders/shaders_shapes_textures.c) | <img src="shaders/shaders_shapes_textures.png" alt="shaders_shapes_textures" width="80"> | ⭐️⭐️☆☆ | 1.7 | 3.7 | [Ray](https://github.com/raysan5) |
|
||||||
| 118 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | <img src="shaders/shaders_custom_uniform.png" alt="shaders_custom_uniform" width="80"> | ⭐️⭐️☆☆ | 1.3 | 4.0 | [Ray](https://github.com/raysan5) |
|
| 119 | [shaders_custom_uniform](shaders/shaders_custom_uniform.c) | <img src="shaders/shaders_custom_uniform.png" alt="shaders_custom_uniform" width="80"> | ⭐️⭐️☆☆ | 1.3 | 4.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 119 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | <img src="shaders/shaders_postprocessing.png" alt="shaders_postprocessing" width="80"> | ⭐️⭐️⭐️☆ | 1.3 | 4.0 | [Ray](https://github.com/raysan5) |
|
| 120 | [shaders_postprocessing](shaders/shaders_postprocessing.c) | <img src="shaders/shaders_postprocessing.png" alt="shaders_postprocessing" width="80"> | ⭐️⭐️⭐️☆ | 1.3 | 4.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 120 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | <img src="shaders/shaders_palette_switch.png" alt="shaders_palette_switch" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) |
|
| 121 | [shaders_palette_switch](shaders/shaders_palette_switch.c) | <img src="shaders/shaders_palette_switch.png" alt="shaders_palette_switch" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Marco Lizza](https://github.com/MarcoLizza) |
|
||||||
| 121 | [shaders_raymarching](shaders/shaders_raymarching.c) | <img src="shaders/shaders_raymarching.png" alt="shaders_raymarching" width="80"> | ⭐️⭐️⭐️⭐️ | 2.0 | 4.2 | [Ray](https://github.com/raysan5) |
|
| 122 | [shaders_raymarching](shaders/shaders_raymarching.c) | <img src="shaders/shaders_raymarching.png" alt="shaders_raymarching" width="80"> | ⭐️⭐️⭐️⭐️ | 2.0 | 4.2 | [Ray](https://github.com/raysan5) |
|
||||||
| 122 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | <img src="shaders/shaders_texture_drawing.png" alt="shaders_texture_drawing" width="80"> | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/ciessielski) |
|
| 123 | [shaders_texture_drawing](shaders/shaders_texture_drawing.c) | <img src="shaders/shaders_texture_drawing.png" alt="shaders_texture_drawing" width="80"> | ⭐️⭐️☆☆ | 2.0 | 3.7 | [Michał Ciesielski](https://github.com/ciessielski) |
|
||||||
| 123 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | <img src="shaders/shaders_texture_outline.png" alt="shaders_texture_outline" width="80"> | ⭐️⭐️⭐️☆ | 4.0 | 4.0 | [Samuel Skiff](https://github.com/GoldenThumbs) |
|
| 124 | [shaders_texture_outline](shaders/shaders_texture_outline.c) | <img src="shaders/shaders_texture_outline.png" alt="shaders_texture_outline" width="80"> | ⭐️⭐️⭐️☆ | 4.0 | 4.0 | [Samuel Skiff](https://github.com/GoldenThumbs) |
|
||||||
| 124 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | <img src="shaders/shaders_texture_waves.png" alt="shaders_texture_waves" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) |
|
| 125 | [shaders_texture_waves](shaders/shaders_texture_waves.c) | <img src="shaders/shaders_texture_waves.png" alt="shaders_texture_waves" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Anata](https://github.com/anatagawa) |
|
||||||
| 125 | [shaders_julia_set](shaders/shaders_julia_set.c) | <img src="shaders/shaders_julia_set.png" alt="shaders_julia_set" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 4.0 | [Josh Colclough](https://github.com/joshcol9232) |
|
| 126 | [shaders_julia_set](shaders/shaders_julia_set.c) | <img src="shaders/shaders_julia_set.png" alt="shaders_julia_set" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 4.0 | [Josh Colclough](https://github.com/joshcol9232) |
|
||||||
| 126 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | <img src="shaders/shaders_eratosthenes.png" alt="shaders_eratosthenes" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 4.0 | [ProfJski](https://github.com/ProfJski) |
|
| 127 | [shaders_eratosthenes](shaders/shaders_eratosthenes.c) | <img src="shaders/shaders_eratosthenes.png" alt="shaders_eratosthenes" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 4.0 | [ProfJski](https://github.com/ProfJski) |
|
||||||
| 127 | [shaders_fog](shaders/shaders_fog.c) | <img src="shaders/shaders_fog.png" alt="shaders_fog" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
|
| 128 | [shaders_fog](shaders/shaders_fog.c) | <img src="shaders/shaders_fog.png" alt="shaders_fog" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
|
||||||
| 128 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | <img src="shaders/shaders_simple_mask.png" alt="shaders_simple_mask" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
|
| 129 | [shaders_simple_mask](shaders/shaders_simple_mask.c) | <img src="shaders/shaders_simple_mask.png" alt="shaders_simple_mask" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
|
||||||
| 129 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | <img src="shaders/shaders_hot_reloading.png" alt="shaders_hot_reloading" width="80"> | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 130 | [shaders_hot_reloading](shaders/shaders_hot_reloading.c) | <img src="shaders/shaders_hot_reloading.png" alt="shaders_hot_reloading" width="80"> | ⭐️⭐️⭐️☆ | 3.0 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 130 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | <img src="shaders/shaders_mesh_instancing.png" alt="shaders_mesh_instancing" width="80"> | ⭐️⭐️⭐️⭐️ | 3.7 | 4.2 | [seanpringle](https://github.com/seanpringle) |
|
| 131 | [shaders_mesh_instancing](shaders/shaders_mesh_instancing.c) | <img src="shaders/shaders_mesh_instancing.png" alt="shaders_mesh_instancing" width="80"> | ⭐️⭐️⭐️⭐️ | 3.7 | 4.2 | [seanpringle](https://github.com/seanpringle) |
|
||||||
| 131 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | <img src="shaders/shaders_multi_sample2d.png" alt="shaders_multi_sample2d" width="80"> | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 132 | [shaders_multi_sample2d](shaders/shaders_multi_sample2d.c) | <img src="shaders/shaders_multi_sample2d.png" alt="shaders_multi_sample2d" width="80"> | ⭐️⭐️☆☆ | 3.5 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 132 | [shaders_spotlight](shaders/shaders_spotlight.c) | <img src="shaders/shaders_spotlight.png" alt="shaders_spotlight" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
|
| 133 | [shaders_spotlight](shaders/shaders_spotlight.c) | <img src="shaders/shaders_spotlight.png" alt="shaders_spotlight" width="80"> | ⭐️⭐️☆☆ | 2.5 | 3.7 | [Chris Camacho](https://github.com/chriscamacho) |
|
||||||
| 133 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | <img src="shaders/shaders_deferred_render.png" alt="shaders_deferred_render" width="80"> | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) |
|
| 134 | [shaders_deferred_render](shaders/shaders_deferred_render.c) | <img src="shaders/shaders_deferred_render.png" alt="shaders_deferred_render" width="80"> | ⭐️⭐️⭐️⭐️ | 4.5 | 4.5 | [Justin Andreas Lacoste](https://github.com/27justin) |
|
||||||
| 134 | [shaders_hybrid_render](shaders/shaders_hybrid_render.c) | <img src="shaders/shaders_hybrid_render.png" alt="shaders_hybrid_render" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 4.2 | [Buğra Alptekin Sarı](https://github.com/BugraAlptekinSari) |
|
| 135 | [shaders_hybrid_render](shaders/shaders_hybrid_render.c) | <img src="shaders/shaders_hybrid_render.png" alt="shaders_hybrid_render" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 4.2 | [Buğra Alptekin Sarı](https://github.com/BugraAlptekinSari) |
|
||||||
| 135 | [shaders_texture_tiling](shaders/shaders_texture_tiling.c) | <img src="shaders/shaders_texture_tiling.png" alt="shaders_texture_tiling" width="80"> | ⭐️⭐️☆☆ | 4.5 | 4.5 | [Luis Almeida](https://github.com/luis605) |
|
| 136 | [shaders_texture_tiling](shaders/shaders_texture_tiling.c) | <img src="shaders/shaders_texture_tiling.png" alt="shaders_texture_tiling" width="80"> | ⭐️⭐️☆☆ | 4.5 | 4.5 | [Luis Almeida](https://github.com/luis605) |
|
||||||
| 136 | [shaders_shadowmap](shaders/shaders_shadowmap.c) | <img src="shaders/shaders_shadowmap.png" alt="shaders_shadowmap" width="80"> | ⭐️⭐️⭐️⭐️ | 5.0 | 5.0 | [TheManTheMythTheGameDev](https://github.com/TheManTheMythTheGameDev) |
|
| 137 | [shaders_shadowmap](shaders/shaders_shadowmap.c) | <img src="shaders/shaders_shadowmap.png" alt="shaders_shadowmap" width="80"> | ⭐️⭐️⭐️⭐️ | 5.0 | 5.0 | [TheManTheMythTheGameDev](https://github.com/TheManTheMythTheGameDev) |
|
||||||
| 137 | [shaders_vertex_displacement](shaders/shaders_vertex_displacement.c) | <img src="shaders/shaders_vertex_displacement.png" alt="shaders_vertex_displacement" width="80"> | ⭐️⭐️⭐️☆ | 5.0 | 4.5 | [Alex ZH](https://github.com/ZzzhHe) |
|
| 138 | [shaders_vertex_displacement](shaders/shaders_vertex_displacement.c) | <img src="shaders/shaders_vertex_displacement.png" alt="shaders_vertex_displacement" width="80"> | ⭐️⭐️⭐️☆ | 5.0 | 4.5 | [Alex ZH](https://github.com/ZzzhHe) |
|
||||||
| 138 | [shaders_write_depth](shaders/shaders_write_depth.c) | <img src="shaders/shaders_write_depth.png" alt="shaders_write_depth" width="80"> | ⭐️⭐️☆☆ | 4.2 | 4.2 | [Buğra Alptekin Sarı](https://github.com/BugraAlptekinSari) |
|
| 139 | [shaders_write_depth](shaders/shaders_write_depth.c) | <img src="shaders/shaders_write_depth.png" alt="shaders_write_depth" width="80"> | ⭐️⭐️☆☆ | 4.2 | 4.2 | [Buğra Alptekin Sarı](https://github.com/BugraAlptekinSari) |
|
||||||
| 139 | [shaders_basic_pbr](shaders/shaders_basic_pbr.c) | <img src="shaders/shaders_basic_pbr.png" alt="shaders_basic_pbr" width="80"> | ⭐️⭐️⭐️⭐️ | 5.0 | 5.1-dev | [Afan OLOVCIC](https://github.com/_DevDad) |
|
| 140 | [shaders_basic_pbr](shaders/shaders_basic_pbr.c) | <img src="shaders/shaders_basic_pbr.png" alt="shaders_basic_pbr" width="80"> | ⭐️⭐️⭐️⭐️ | 5.0 | 5.1-dev | [Afan OLOVCIC](https://github.com/_DevDad) |
|
||||||
| 140 | [shaders_lightmap](shaders/shaders_lightmap.c) | <img src="shaders/shaders_lightmap.png" alt="shaders_lightmap" width="80"> | ⭐️⭐️⭐️☆ | 4.5 | 4.5 | [Jussi Viitala](https://github.com/nullstare) |
|
| 141 | [shaders_lightmap](shaders/shaders_lightmap.c) | <img src="shaders/shaders_lightmap.png" alt="shaders_lightmap" width="80"> | ⭐️⭐️⭐️☆ | 4.5 | 4.5 | [Jussi Viitala](https://github.com/nullstare) |
|
||||||
| 141 | [shaders_rounded_rectangle](shaders/shaders_rounded_rectangle.c) | <img src="shaders/shaders_rounded_rectangle.png" alt="shaders_rounded_rectangle" width=80> | ⭐️⭐️⭐️☆ | 5.5 | 5.5 | [Anstro Pleuton](https://github.com/anstropleuton) |
|
| 142 | [shaders_rounded_rectangle](shaders/shaders_rounded_rectangle.c) | <img src="shaders/shaders_rounded_rectangle.png" alt="shaders_rounded_rectangle" width=80> | ⭐️⭐️⭐️☆ | 5.5 | 5.5 | [Anstro Pleuton](https://github.com/anstropleuton) |
|
||||||
| 142 | [shaders_view_depth](shaders/shaders_view_depth.c) | <img src="shaders/shaders_view_depth.png" alt="shaders_view_depth" width="80"> | ⭐️⭐️⭐️☆ | 5.6-dev | 5.6-dev | [Luís Almeida](https://github.com/luis605) |
|
| 143 | [shaders_view_depth](shaders/shaders_view_depth.c) | <img src="shaders/shaders_view_depth.png" alt="shaders_view_depth" width="80"> | ⭐️⭐️⭐️☆ | 5.6-dev | 5.6-dev | [Luís Almeida](https://github.com/luis605) |
|
||||||
|
|
||||||
### category: audio
|
### category: audio
|
||||||
|
|
||||||
@ -209,26 +209,26 @@ Examples using raylib audio functionality, including sound/music loading and pla
|
|||||||
|
|
||||||
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
||||||
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
||||||
| 142 | [audio_module_playing](audio/audio_module_playing.c) | <img src="audio/audio_module_playing.png" alt="audio_module_playing" width="80"> | ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 144 | [audio_module_playing](audio/audio_module_playing.c) | <img src="audio/audio_module_playing.png" alt="audio_module_playing" width="80"> | ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 143 | [audio_music_stream](audio/audio_music_stream.c) | <img src="audio/audio_music_stream.png" alt="audio_music_stream" width="80"> | ⭐️☆☆☆ | 1.3 | 4.2 | [Ray](https://github.com/raysan5) |
|
| 145 | [audio_music_stream](audio/audio_music_stream.c) | <img src="audio/audio_music_stream.png" alt="audio_music_stream" width="80"> | ⭐️☆☆☆ | 1.3 | 4.2 | [Ray](https://github.com/raysan5) |
|
||||||
| 144 | [audio_raw_stream](audio/audio_raw_stream.c) | <img src="audio/audio_raw_stream.png" alt="audio_raw_stream" width="80"> | ⭐️⭐️⭐️☆ | 1.6 | 4.2 | [Ray](https://github.com/raysan5) |
|
| 146 | [audio_raw_stream](audio/audio_raw_stream.c) | <img src="audio/audio_raw_stream.png" alt="audio_raw_stream" width="80"> | ⭐️⭐️⭐️☆ | 1.6 | 4.2 | [Ray](https://github.com/raysan5) |
|
||||||
| 145 | [audio_sound_loading](audio/audio_sound_loading.c) | <img src="audio/audio_sound_loading.png" alt="audio_sound_loading" width="80"> | ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) |
|
| 147 | [audio_sound_loading](audio/audio_sound_loading.c) | <img src="audio/audio_sound_loading.png" alt="audio_sound_loading" width="80"> | ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) |
|
||||||
| 146 | [audio_mixed_processor](audio/audio_mixed_processor.c) | <img src="audio/audio_mixed_processor.png" alt="audio_mixed_processor" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 4.2 | [hkc](https://github.com/hatkidchan) |
|
| 148 | [audio_mixed_processor](audio/audio_mixed_processor.c) | <img src="audio/audio_mixed_processor.png" alt="audio_mixed_processor" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 4.2 | [hkc](https://github.com/hatkidchan) |
|
||||||
| 147 | [audio_stream_effects](audio/audio_stream_effects.c) | <img src="audio/audio_stream_effects.png" alt="audio_stream_effects" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 5.0 | [Ray](https://github.com/raysan5) |
|
| 149 | [audio_stream_effects](audio/audio_stream_effects.c) | <img src="audio/audio_stream_effects.png" alt="audio_stream_effects" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 5.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 148 | [audio_sound_multi](audio/audio_sound_multi.c) | <img src="audio/audio_sound_multi.png" alt="audio_sound_multi" width="80"> | ⭐️⭐️☆☆ | 4.6 | 4.6 | [Jeffery Myers](https://github.com/JeffM2501) |
|
| 150 [audio_sound_multi](audio/audio_sound_multi.c) | <img src="audio/audio_sound_multi.png" alt="audio_sound_multi" width="80"> | ⭐️⭐️☆☆ | 4.6 | 4.6 | [Jeffery Myers](https://github.com/JeffM2501) |
|
||||||
| 149 | [audio_sound_positioning](audio/audio_sound_positioning.c) | <img src="audio/audio_sound_positioning.png" alt="audio_sound_positioning" width="80"> | ⭐️⭐️☆☆ | 5.5 | 5.5 | [Le Juez Victor](https://github.com/Bigfoot71) |
|
| 151 | [audio_sound_positioning](audio/audio_sound_positioning.c) | <img src="audio/audio_sound_positioning.png" alt="audio_sound_positioning" width="80"> | ⭐️⭐️☆☆ | 5.5 | 5.5 | [Le Juez Victor](https://github.com/Bigfoot71) |
|
||||||
|
|
||||||
### category: others
|
### category: others
|
||||||
|
|
||||||
Examples showing raylib misc functionality that does not fit in other categories, like standalone modules usage or examples integrating external libraries.
|
Ex150amples showing raylib misc functionality that does not fit in other categories, like standalone modules usage or examples integrating external libraries.
|
||||||
|
|
||||||
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|
||||||
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
|
||||||
| 150 | [rlgl_standalone](others/rlgl_standalone.c) | <img src="others/rlgl_standalone.png" alt="rlgl_standalone" width="80"> | ⭐️⭐️⭐️⭐️ | 1.6 | 4.0 | [Ray](https://github.com/raysan5) |
|
| 152 | [rlgl_standalone](others/rlgl_standalone.c) | <img src="others/rlgl_standalone.png" alt="rlgl_standalone" width="80"> | ⭐️⭐️⭐️⭐️ | 1.6 | 4.0 | [Ray](https://github.com/raysan5) |
|
||||||
| 151 | [rlgl_compute_shader](others/rlgl_compute_shader.c) | <img src="others/rlgl_compute_shader.png" alt="rlgl_compute_shader" width="80"> | ⭐️⭐️⭐️⭐️ | 4.0 | 4.0 | [Teddy Astie](https://github.com/tsnake41) |
|
| 153 | [rlgl_compute_shader](others/rlgl_compute_shader.c) | <img src="others/rlgl_compute_shader.png" alt="rlgl_compute_shader" width="80"> | ⭐️⭐️⭐️⭐️ | 4.0 | 4.0 | [Teddy Astie](https://github.com/tsnake41) |
|
||||||
| 152 | [easings_testbed](others/easings_testbed.c) | <img src="others/easings_testbed.png" alt="easings_testbed" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
|
| 154 | [easings_testbed](others/easings_testbed.c) | <img src="others/easings_testbed.png" alt="easings_testbed" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
|
||||||
| 153 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | <img src="others/raylib_opengl_interop.png" alt="raylib_opengl_interop" width="80"> | ⭐️⭐️⭐️⭐️ | 3.8 | 4.0 | [Stephan Soller](https://github.com/arkanis) |
|
| 155 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | <img src="others/raylib_opengl_interop.png" alt="raylib_opengl_interop" width="80"> | ⭐️⭐️⭐️⭐️ | 3.8 | 4.0 | [Stephan Soller](https://github.com/arkanis) |
|
||||||
| 154 | [embedded_files_loading](others/embedded_files_loading.c) | <img src="others/embedded_files_loading.png" alt="embedded_files_loading" width="80"> | ⭐️⭐️☆☆ | 3.0 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
|
| 156 | [embedded_files_loading](others/embedded_files_loading.c) | <img src="others/embedded_files_loading.png" alt="embedded_files_loading" width="80"> | ⭐️⭐️☆☆ | 3.0 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
|
||||||
| 155 | [raymath_vector_angle](others/raymath_vector_angle.c) | <img src="others/raymath_vector_angle.png" alt="raymath_vector_angle" width="80"> | ⭐️⭐️☆☆ | 1.0 | 4.6 | [Ray](https://github.com/raysan5) |
|
| 157 | [raymath_vector_angle](others/raymath_vector_angle.c) | <img src="others/raymath_vector_angle.png" alt="raymath_vector_angle" width="80"> | ⭐️⭐️☆☆ | 1.0 | 4.6 | [Ray](https://github.com/raysan5) |
|
||||||
|
|
||||||
As always contributions are welcome, feel free to send new examples! Here is an [examples template](examples_template.c) to start with!
|
As always contributions are welcome, feel free to send new examples! Here is an [examples template](examples_template.c) to start with!
|
||||||
|
@ -61,7 +61,9 @@ int main(void)
|
|||||||
{
|
{
|
||||||
// Update
|
// Update
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
#ifndef PLATFORM_WEB // NOTE: On non web platforms the PollInputEvents just works before the inputs checks
|
||||||
PollInputEvents(); // Poll input events (SUPPORT_CUSTOM_FRAME_CONTROL)
|
PollInputEvents(); // Poll input events (SUPPORT_CUSTOM_FRAME_CONTROL)
|
||||||
|
#endif
|
||||||
|
|
||||||
if (IsKeyPressed(KEY_SPACE)) pause = !pause;
|
if (IsKeyPressed(KEY_SPACE)) pause = !pause;
|
||||||
|
|
||||||
@ -76,6 +78,10 @@ int main(void)
|
|||||||
if (position >= GetScreenWidth()) position = 0;
|
if (position >= GetScreenWidth()) position = 0;
|
||||||
timeCounter += deltaTime; // We count time (seconds)
|
timeCounter += deltaTime; // We count time (seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef PLATFORM_WEB // NOTE: On web platform for some reason the PollInputEvents only works after the inputs check, so just call it after check all your inputs (on web)
|
||||||
|
PollInputEvents(); // Poll input events (SUPPORT_CUSTOM_FRAME_CONTROL)
|
||||||
|
#endif
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
attribute vec3 vertexPosition;
|
attribute vec3 vertexPosition;
|
||||||
attribute vec2 vertexTexCoord;
|
attribute vec2 vertexTexCoord;
|
||||||
attribute vec3 vertexNormal;
|
attribute vec3 vertexNormal;
|
||||||
attribute vec3 vertexTangent;
|
attribute vec4 vertexTangent;
|
||||||
attribute vec4 vertexColor;
|
attribute vec4 vertexColor;
|
||||||
|
|
||||||
// Input uniform values
|
// Input uniform values
|
||||||
@ -52,7 +52,7 @@ mat3 transpose(mat3 m)
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// Compute binormal from vertex normal and tangent
|
// Compute binormal from vertex normal and tangent
|
||||||
vec3 vertexBinormal = cross(vertexNormal, vertexTangent);
|
vec3 vertexBinormal = cross(vertexNormal, vertexTangent.xyz) * vertexTangent.w;
|
||||||
|
|
||||||
// Compute fragment normal based on normal transformations
|
// Compute fragment normal based on normal transformations
|
||||||
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
|
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
|
||||||
@ -62,7 +62,7 @@ void main()
|
|||||||
|
|
||||||
fragTexCoord = vertexTexCoord*2.0;
|
fragTexCoord = vertexTexCoord*2.0;
|
||||||
fragNormal = normalize(normalMatrix*vertexNormal);
|
fragNormal = normalize(normalMatrix*vertexNormal);
|
||||||
vec3 fragTangent = normalize(normalMatrix*vertexTangent);
|
vec3 fragTangent = normalize(normalMatrix*vertexTangent.xyz);
|
||||||
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal);
|
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal);
|
||||||
vec3 fragBinormal = normalize(normalMatrix*vertexBinormal);
|
vec3 fragBinormal = normalize(normalMatrix*vertexBinormal);
|
||||||
fragBinormal = cross(fragNormal, fragTangent);
|
fragBinormal = cross(fragNormal, fragTangent);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
attribute vec3 vertexPosition;
|
attribute vec3 vertexPosition;
|
||||||
attribute vec2 vertexTexCoord;
|
attribute vec2 vertexTexCoord;
|
||||||
attribute vec3 vertexNormal;
|
attribute vec3 vertexNormal;
|
||||||
attribute vec3 vertexTangent;
|
attribute vec4 vertexTangent;
|
||||||
attribute vec4 vertexColor;
|
attribute vec4 vertexColor;
|
||||||
|
|
||||||
// Input uniform values
|
// Input uniform values
|
||||||
@ -52,7 +52,7 @@ mat3 transpose(mat3 m)
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// Compute binormal from vertex normal and tangent
|
// Compute binormal from vertex normal and tangent
|
||||||
vec3 vertexBinormal = cross(vertexNormal, vertexTangent);
|
vec3 vertexBinormal = cross(vertexNormal, vertexTangent.xyz) * vertexTangent.w;
|
||||||
|
|
||||||
// Compute fragment normal based on normal transformations
|
// Compute fragment normal based on normal transformations
|
||||||
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
|
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
|
||||||
@ -62,7 +62,7 @@ void main()
|
|||||||
|
|
||||||
fragTexCoord = vertexTexCoord*2.0;
|
fragTexCoord = vertexTexCoord*2.0;
|
||||||
fragNormal = normalize(normalMatrix*vertexNormal);
|
fragNormal = normalize(normalMatrix*vertexNormal);
|
||||||
vec3 fragTangent = normalize(normalMatrix*vertexTangent);
|
vec3 fragTangent = normalize(normalMatrix*vertexTangent.xyz);
|
||||||
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal);
|
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal);
|
||||||
vec3 fragBinormal = normalize(normalMatrix*vertexBinormal);
|
vec3 fragBinormal = normalize(normalMatrix*vertexBinormal);
|
||||||
fragBinormal = cross(fragNormal, fragTangent);
|
fragBinormal = cross(fragNormal, fragTangent);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
in vec3 vertexPosition;
|
in vec3 vertexPosition;
|
||||||
in vec2 vertexTexCoord;
|
in vec2 vertexTexCoord;
|
||||||
in vec3 vertexNormal;
|
in vec3 vertexNormal;
|
||||||
in vec3 vertexTangent;
|
in vec4 vertexTangent;
|
||||||
in vec4 vertexColor;
|
in vec4 vertexColor;
|
||||||
|
|
||||||
// Input uniform values
|
// Input uniform values
|
||||||
@ -26,7 +26,7 @@ const float normalOffset = 0.1;
|
|||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// Compute binormal from vertex normal and tangent
|
// Compute binormal from vertex normal and tangent
|
||||||
vec3 vertexBinormal = cross(vertexNormal, vertexTangent);
|
vec3 vertexBinormal = cross(vertexNormal, vertexTangent.xyz) * vertexTangent.w;
|
||||||
|
|
||||||
// Compute fragment normal based on normal transformations
|
// Compute fragment normal based on normal transformations
|
||||||
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
|
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
|
||||||
@ -36,7 +36,7 @@ void main()
|
|||||||
|
|
||||||
fragTexCoord = vertexTexCoord*2.0;
|
fragTexCoord = vertexTexCoord*2.0;
|
||||||
fragNormal = normalize(normalMatrix*vertexNormal);
|
fragNormal = normalize(normalMatrix*vertexNormal);
|
||||||
vec3 fragTangent = normalize(normalMatrix*vertexTangent);
|
vec3 fragTangent = normalize(normalMatrix*vertexTangent.xyz);
|
||||||
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal);
|
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal)*fragNormal);
|
||||||
vec3 fragBinormal = normalize(normalMatrix*vertexBinormal);
|
vec3 fragBinormal = normalize(normalMatrix*vertexBinormal);
|
||||||
fragBinormal = cross(fragNormal, fragTangent);
|
fragBinormal = cross(fragNormal, fragTangent);
|
||||||
|
@ -125,6 +125,8 @@ int main()
|
|||||||
SetShaderValue(shader, GetShaderLocation(shader, "ambient"), &ambientIntensity, SHADER_UNIFORM_FLOAT);
|
SetShaderValue(shader, GetShaderLocation(shader, "ambient"), &ambientIntensity, SHADER_UNIFORM_FLOAT);
|
||||||
|
|
||||||
// Get location for shader parameters that can be modified in real time
|
// Get location for shader parameters that can be modified in real time
|
||||||
|
int metallicValueLoc = GetShaderLocation(shader, "metallicValue");
|
||||||
|
int roughnessValueLoc = GetShaderLocation(shader, "roughnessValue");
|
||||||
int emissiveIntensityLoc = GetShaderLocation(shader, "emissivePower");
|
int emissiveIntensityLoc = GetShaderLocation(shader, "emissivePower");
|
||||||
int emissiveColorLoc = GetShaderLocation(shader, "emissiveColor");
|
int emissiveColorLoc = GetShaderLocation(shader, "emissiveColor");
|
||||||
int textureTilingLoc = GetShaderLocation(shader, "tiling");
|
int textureTilingLoc = GetShaderLocation(shader, "tiling");
|
||||||
@ -141,7 +143,7 @@ int main()
|
|||||||
|
|
||||||
// Setup materials[0].maps default parameters
|
// Setup materials[0].maps default parameters
|
||||||
car.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
|
car.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
|
||||||
car.materials[0].maps[MATERIAL_MAP_METALNESS].value = 0.0f;
|
car.materials[0].maps[MATERIAL_MAP_METALNESS].value = 1.0f;
|
||||||
car.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.0f;
|
car.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.0f;
|
||||||
car.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
|
car.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
|
||||||
car.materials[0].maps[MATERIAL_MAP_EMISSION].color = (Color){ 255, 162, 0, 255 };
|
car.materials[0].maps[MATERIAL_MAP_EMISSION].color = (Color){ 255, 162, 0, 255 };
|
||||||
@ -163,8 +165,8 @@ int main()
|
|||||||
floor.materials[0].shader = shader;
|
floor.materials[0].shader = shader;
|
||||||
|
|
||||||
floor.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
|
floor.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
|
||||||
floor.materials[0].maps[MATERIAL_MAP_METALNESS].value = 0.0f;
|
floor.materials[0].maps[MATERIAL_MAP_METALNESS].value = 0.8f;
|
||||||
floor.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.0f;
|
floor.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.1f;
|
||||||
floor.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
|
floor.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
|
||||||
floor.materials[0].maps[MATERIAL_MAP_EMISSION].color = BLACK;
|
floor.materials[0].maps[MATERIAL_MAP_EMISSION].color = BLACK;
|
||||||
|
|
||||||
@ -229,6 +231,10 @@ int main()
|
|||||||
Vector4 floorEmissiveColor = ColorNormalize(floor.materials[0].maps[MATERIAL_MAP_EMISSION].color);
|
Vector4 floorEmissiveColor = ColorNormalize(floor.materials[0].maps[MATERIAL_MAP_EMISSION].color);
|
||||||
SetShaderValue(shader, emissiveColorLoc, &floorEmissiveColor, SHADER_UNIFORM_VEC4);
|
SetShaderValue(shader, emissiveColorLoc, &floorEmissiveColor, SHADER_UNIFORM_VEC4);
|
||||||
|
|
||||||
|
// Set floor metallic and roughness values
|
||||||
|
SetShaderValue(shader, metallicValueLoc, &floor.materials[0].maps[MATERIAL_MAP_METALNESS].value, SHADER_UNIFORM_FLOAT);
|
||||||
|
SetShaderValue(shader, roughnessValueLoc, &floor.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value, SHADER_UNIFORM_FLOAT);
|
||||||
|
|
||||||
DrawModel(floor, (Vector3){ 0.0f, 0.0f, 0.0f }, 5.0f, WHITE); // Draw floor model
|
DrawModel(floor, (Vector3){ 0.0f, 0.0f, 0.0f }, 5.0f, WHITE); // Draw floor model
|
||||||
|
|
||||||
// Set old car model texture tiling, emissive color and emissive intensity parameters on shader
|
// Set old car model texture tiling, emissive color and emissive intensity parameters on shader
|
||||||
@ -238,6 +244,10 @@ int main()
|
|||||||
float emissiveIntensity = 0.01f;
|
float emissiveIntensity = 0.01f;
|
||||||
SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, SHADER_UNIFORM_FLOAT);
|
SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, SHADER_UNIFORM_FLOAT);
|
||||||
|
|
||||||
|
// Set old car metallic and roughness values
|
||||||
|
SetShaderValue(shader, metallicValueLoc, &car.materials[0].maps[MATERIAL_MAP_METALNESS].value, SHADER_UNIFORM_FLOAT);
|
||||||
|
SetShaderValue(shader, roughnessValueLoc, &car.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value, SHADER_UNIFORM_FLOAT);
|
||||||
|
|
||||||
DrawModel(car, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.25f, WHITE); // Draw car model
|
DrawModel(car, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.25f, WHITE); // Draw car model
|
||||||
|
|
||||||
// Draw spheres to show the lights positions
|
// Draw spheres to show the lights positions
|
||||||
|
@ -52,6 +52,8 @@ int main(void)
|
|||||||
DrawCircle(screenWidth/5, 120, 35, DARKBLUE);
|
DrawCircle(screenWidth/5, 120, 35, DARKBLUE);
|
||||||
DrawCircleGradient(screenWidth/5, 220, 60, GREEN, SKYBLUE);
|
DrawCircleGradient(screenWidth/5, 220, 60, GREEN, SKYBLUE);
|
||||||
DrawCircleLines(screenWidth/5, 340, 80, DARKBLUE);
|
DrawCircleLines(screenWidth/5, 340, 80, DARKBLUE);
|
||||||
|
DrawEllipse(screenWidth/5, 120, 25, 20, YELLOW);
|
||||||
|
DrawEllipseLines(screenWidth/5, 120, 30, 25, YELLOW);
|
||||||
|
|
||||||
// Rectangle shapes and lines
|
// Rectangle shapes and lines
|
||||||
DrawRectangle(screenWidth/4*2 - 60, 100, 120, 60, RED);
|
DrawRectangle(screenWidth/4*2 - 60, 100, 120, 60, RED);
|
||||||
|
185
libs/raylib/examples/shapes/shapes_digital_clock.c
Normal file
185
libs/raylib/examples/shapes/shapes_digital_clock.c
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
/*******************************************************************************************
|
||||||
|
*
|
||||||
|
* raylib [shapes] example - fancy clock using basic shapes
|
||||||
|
*
|
||||||
|
* Example complexity rating: [★★☆☆] 2/4
|
||||||
|
*
|
||||||
|
* Example originally created with raylib 5.5, last time updated with raylib 5.5
|
||||||
|
*
|
||||||
|
* Example contributed by Hamza RAHAL (@hmz-rhl) 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) 2025 Hamza RAHAL (@hmz-rhl)
|
||||||
|
*
|
||||||
|
********************************************************************************************/
|
||||||
|
|
||||||
|
#include "raylib.h"
|
||||||
|
|
||||||
|
#include <math.h> // Required for: cosf(), sinf()
|
||||||
|
#include <time.h> // Required for: time(), localtime()
|
||||||
|
|
||||||
|
#define DIGIT_SIZE 30
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Types and Structures Definition
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
typedef enum {
|
||||||
|
MODE_NORMAL = 0,
|
||||||
|
MODE_HANDS_FREE,
|
||||||
|
} ClockMode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int value;
|
||||||
|
Vector2 origin;
|
||||||
|
float angle;
|
||||||
|
int length;
|
||||||
|
int thickness;
|
||||||
|
Color color;
|
||||||
|
} ClockHand;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ClockMode mode;
|
||||||
|
ClockHand second;
|
||||||
|
ClockHand minute;
|
||||||
|
ClockHand hour;
|
||||||
|
} Clock;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Module Functions Declaration
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
static void UpdateClock(Clock *clock); // Update clock time
|
||||||
|
static void DrawClock(Clock clock, Vector2 centerPos); // Draw clock at desired position
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
// Program main entry point
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Initialization
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
const int screenWidth = 800;
|
||||||
|
const int screenHeight = 450;
|
||||||
|
|
||||||
|
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - digital clock");
|
||||||
|
|
||||||
|
// Initialize clock
|
||||||
|
Clock myClock = {
|
||||||
|
.mode = MODE_NORMAL,
|
||||||
|
|
||||||
|
.second.angle = 45,
|
||||||
|
.second.length = 140,
|
||||||
|
.second.thickness = 3,
|
||||||
|
.second.color = BEIGE,
|
||||||
|
|
||||||
|
.minute.angle = 10,
|
||||||
|
.minute.length = 130,
|
||||||
|
.minute.thickness = 7,
|
||||||
|
.minute.color = DARKGRAY,
|
||||||
|
|
||||||
|
.hour.angle = 0,
|
||||||
|
.hour.length = 100,
|
||||||
|
.hour.thickness = 7,
|
||||||
|
.hour.color = BLACK,
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
if (IsKeyPressed(KEY_SPACE))
|
||||||
|
{
|
||||||
|
if (myClock.mode == MODE_HANDS_FREE) myClock.mode = MODE_NORMAL;
|
||||||
|
else if (myClock.mode == MODE_NORMAL) myClock.mode = MODE_HANDS_FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateClock(&myClock);
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
BeginDrawing();
|
||||||
|
|
||||||
|
ClearBackground(RAYWHITE);
|
||||||
|
|
||||||
|
DrawCircle(400, 225, 5, BLACK); // Clock center dot
|
||||||
|
|
||||||
|
DrawClock(myClock, (Vector2){ 400, 225 }); // Clock in selected mode
|
||||||
|
|
||||||
|
DrawText("Press [SPACE] to switch clock mode", 10, 10, 20, DARKGRAY);
|
||||||
|
|
||||||
|
EndDrawing();
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-Initialization
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
CloseWindow(); // Close window and OpenGL context
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Module Functions Definition
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Update clock time
|
||||||
|
static void UpdateClock(Clock *clock)
|
||||||
|
{
|
||||||
|
time_t rawtime;
|
||||||
|
struct tm * timeinfo;
|
||||||
|
|
||||||
|
time(&rawtime);
|
||||||
|
timeinfo = localtime(&rawtime);
|
||||||
|
|
||||||
|
// Updating time data
|
||||||
|
clock->second.value = timeinfo->tm_sec;
|
||||||
|
clock->minute.value = timeinfo->tm_min;
|
||||||
|
clock->hour.value = timeinfo->tm_hour;
|
||||||
|
|
||||||
|
clock->hour.angle = (timeinfo->tm_hour%12)*180.0/6.0f;
|
||||||
|
clock->hour.angle += (timeinfo->tm_min%60)*30/60.0f;
|
||||||
|
clock->hour.angle -= 90;
|
||||||
|
|
||||||
|
clock->minute.angle = (timeinfo->tm_min%60)*6.0f;
|
||||||
|
clock->minute.angle += (timeinfo->tm_sec%60)*6/60.0f;
|
||||||
|
clock->minute.angle -= 90;
|
||||||
|
|
||||||
|
clock->second.angle = (timeinfo->tm_sec%60)*6.0f;
|
||||||
|
clock->second.angle -= 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw clock
|
||||||
|
static void DrawClock(Clock clock, Vector2 centerPosition)
|
||||||
|
{
|
||||||
|
if (clock.mode == MODE_HANDS_FREE)
|
||||||
|
{
|
||||||
|
DrawCircleLinesV(centerPosition, clock.minute.length, LIGHTGRAY);
|
||||||
|
|
||||||
|
DrawText(TextFormat("%i", clock.second.value), centerPosition.x + (clock.second.length - 10)*cosf(clock.second.angle*(float)(PI/180)) - DIGIT_SIZE/2, centerPosition.y + clock.second.length*sinf(clock.second.angle*(float)(PI/180)) - DIGIT_SIZE/2, DIGIT_SIZE, GRAY);
|
||||||
|
|
||||||
|
DrawText(TextFormat("%i", clock.minute.value), clock.minute.origin.x + clock.minute.length*cosf(clock.minute.angle*(float)(PI/180)) - DIGIT_SIZE/2, centerPosition.y + clock.minute.length*sinf(clock.minute.angle*(float)(PI/180)) - DIGIT_SIZE/2, DIGIT_SIZE, RED);
|
||||||
|
|
||||||
|
DrawText(TextFormat("%i", clock.hour.value), centerPosition.x + clock.hour.length*cosf(clock.hour.angle*(float)(PI/180)) - DIGIT_SIZE/2, centerPosition.y + clock.hour.length*sinf(clock.hour.angle*(float)(PI/180)) - DIGIT_SIZE/2, DIGIT_SIZE, GOLD);
|
||||||
|
}
|
||||||
|
else if (clock.mode == MODE_NORMAL)
|
||||||
|
{
|
||||||
|
// Draw hand seconds
|
||||||
|
DrawRectanglePro((Rectangle){ centerPosition.x, centerPosition.y, clock.second.length, clock.second.thickness },
|
||||||
|
(Vector2){ 0.0f, clock.second.thickness/2.0f }, clock.second.angle, clock.second.color);
|
||||||
|
|
||||||
|
// Draw hand minutes
|
||||||
|
DrawRectanglePro((Rectangle){ centerPosition.x, centerPosition.y, clock.minute.length, clock.minute.thickness },
|
||||||
|
(Vector2){ 0.0f, clock.minute.thickness/2.0f }, clock.minute.angle, clock.minute.color);
|
||||||
|
|
||||||
|
// Draw hand hours
|
||||||
|
DrawRectanglePro((Rectangle){ centerPosition.x, centerPosition.y, clock.hour.length, clock.hour.thickness },
|
||||||
|
(Vector2){ 0.0f, clock.hour.thickness/2.0f }, clock.hour.angle, clock.hour.color);
|
||||||
|
}
|
||||||
|
}
|
BIN
libs/raylib/examples/shapes/shapes_digital_clock.png
Normal file
BIN
libs/raylib/examples/shapes/shapes_digital_clock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
@ -108,7 +108,7 @@ int main(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Draw provided text with laoded font, containing all required codepoint glyphs
|
// Draw provided text with loaded font, containing all required codepoint glyphs
|
||||||
DrawTextEx(font, text, (Vector2) { 160, 110 }, 48, 5, BLACK);
|
DrawTextEx(font, text, (Vector2) { 160, 110 }, 48, 5, BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2300,7 +2300,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GamepadAxis",
|
"name": "GamepadAxis",
|
||||||
"description": "Gamepad axis",
|
"description": "Gamepad axes",
|
||||||
"values": [
|
"values": [
|
||||||
{
|
{
|
||||||
"name": "GAMEPAD_AXIS_LEFT_X",
|
"name": "GAMEPAD_AXIS_LEFT_X",
|
||||||
@ -3139,7 +3139,7 @@
|
|||||||
"name": "fileName"
|
"name": "fileName"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "char *",
|
"type": "const char *",
|
||||||
"name": "text"
|
"name": "text"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -4409,7 +4409,7 @@
|
|||||||
"name": "fileName"
|
"name": "fileName"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "char *",
|
"type": "const char *",
|
||||||
"name": "text"
|
"name": "text"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -4684,7 +4684,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "EncodeDataBase64",
|
"name": "EncodeDataBase64",
|
||||||
"description": "Encode data to Base64 string, memory must be MemFree()",
|
"description": "Encode data to Base64 string (includes NULL terminator), memory must be MemFree()",
|
||||||
"returnType": "char *",
|
"returnType": "char *",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
@ -4703,12 +4703,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "DecodeDataBase64",
|
"name": "DecodeDataBase64",
|
||||||
"description": "Decode Base64 string data, memory must be MemFree()",
|
"description": "Decode Base64 string (expected NULL terminated), memory must be MemFree()",
|
||||||
"returnType": "unsigned char *",
|
"returnType": "unsigned char *",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
"type": "const unsigned char *",
|
"type": "const char *",
|
||||||
"name": "data"
|
"name": "text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "int *",
|
"type": "int *",
|
||||||
@ -5017,7 +5017,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GetGamepadAxisCount",
|
"name": "GetGamepadAxisCount",
|
||||||
"description": "Get gamepad axis count for a gamepad",
|
"description": "Get axis count for a gamepad",
|
||||||
"returnType": "int",
|
"returnType": "int",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
@ -5028,7 +5028,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "GetGamepadAxisMovement",
|
"name": "GetGamepadAxisMovement",
|
||||||
"description": "Get axis movement value for a gamepad axis",
|
"description": "Get movement value for a gamepad axis",
|
||||||
"returnType": "float",
|
"returnType": "float",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
@ -5702,6 +5702,29 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "DrawEllipseV",
|
||||||
|
"description": "Draw ellipse (Vector version)",
|
||||||
|
"returnType": "void",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"type": "Vector2",
|
||||||
|
"name": "center"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "float",
|
||||||
|
"name": "radiusH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "float",
|
||||||
|
"name": "radiusV"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Color",
|
||||||
|
"name": "color"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "DrawEllipseLines",
|
"name": "DrawEllipseLines",
|
||||||
"description": "Draw ellipse outline",
|
"description": "Draw ellipse outline",
|
||||||
@ -5729,6 +5752,29 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "DrawEllipseLinesV",
|
||||||
|
"description": "Draw ellipse outline (Vector version)",
|
||||||
|
"returnType": "void",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"type": "Vector2",
|
||||||
|
"name": "center"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "float",
|
||||||
|
"name": "radiusH"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "float",
|
||||||
|
"name": "radiusV"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Color",
|
||||||
|
"name": "color"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "DrawRing",
|
"name": "DrawRing",
|
||||||
"description": "Draw ring",
|
"description": "Draw ring",
|
||||||
@ -5964,11 +6010,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Color",
|
"type": "Color",
|
||||||
"name": "topRight"
|
"name": "bottomRight"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Color",
|
"type": "Color",
|
||||||
"name": "bottomRight"
|
"name": "topRight"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -8256,7 +8302,7 @@
|
|||||||
"name": "dst"
|
"name": "dst"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Vector2 *",
|
"type": "const Vector2 *",
|
||||||
"name": "points"
|
"name": "points"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -8279,7 +8325,7 @@
|
|||||||
"name": "dst"
|
"name": "dst"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Vector2 *",
|
"type": "const Vector2 *",
|
||||||
"name": "points"
|
"name": "points"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -8483,7 +8529,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "UpdateTexture",
|
"name": "UpdateTexture",
|
||||||
"description": "Update GPU texture with new data",
|
"description": "Update GPU texture with new data (pixels should be able to fill texture)",
|
||||||
"returnType": "void",
|
"returnType": "void",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
@ -8498,7 +8544,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "UpdateTextureRec",
|
"name": "UpdateTextureRec",
|
||||||
"description": "Update GPU texture rectangle with new data",
|
"description": "Update GPU texture rectangle with new data (pixels and rec should fit in texture)",
|
||||||
"returnType": "void",
|
"returnType": "void",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
@ -11465,7 +11511,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "UpdateSound",
|
"name": "UpdateSound",
|
||||||
"description": "Update sound buffer with new data",
|
"description": "Update sound buffer with new data (data and frame count should fit in sound)",
|
||||||
"returnType": "void",
|
"returnType": "void",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
|
@ -2300,7 +2300,7 @@ return {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "GamepadAxis",
|
name = "GamepadAxis",
|
||||||
description = "Gamepad axis",
|
description = "Gamepad axes",
|
||||||
values = {
|
values = {
|
||||||
{
|
{
|
||||||
name = "GAMEPAD_AXIS_LEFT_X",
|
name = "GAMEPAD_AXIS_LEFT_X",
|
||||||
@ -3108,7 +3108,7 @@ return {
|
|||||||
returnType = "bool",
|
returnType = "bool",
|
||||||
params = {
|
params = {
|
||||||
{type = "const char *", name = "fileName"},
|
{type = "const char *", name = "fileName"},
|
||||||
{type = "char *", name = "text"}
|
{type = "const char *", name = "text"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -4006,7 +4006,7 @@ return {
|
|||||||
returnType = "bool",
|
returnType = "bool",
|
||||||
params = {
|
params = {
|
||||||
{type = "const char *", name = "fileName"},
|
{type = "const char *", name = "fileName"},
|
||||||
{type = "char *", name = "text"}
|
{type = "const char *", name = "text"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -4198,7 +4198,7 @@ return {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "EncodeDataBase64",
|
name = "EncodeDataBase64",
|
||||||
description = "Encode data to Base64 string, memory must be MemFree()",
|
description = "Encode data to Base64 string (includes NULL terminator), memory must be MemFree()",
|
||||||
returnType = "char *",
|
returnType = "char *",
|
||||||
params = {
|
params = {
|
||||||
{type = "const unsigned char *", name = "data"},
|
{type = "const unsigned char *", name = "data"},
|
||||||
@ -4208,10 +4208,10 @@ return {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "DecodeDataBase64",
|
name = "DecodeDataBase64",
|
||||||
description = "Decode Base64 string data, memory must be MemFree()",
|
description = "Decode Base64 string (expected NULL terminated), memory must be MemFree()",
|
||||||
returnType = "unsigned char *",
|
returnType = "unsigned char *",
|
||||||
params = {
|
params = {
|
||||||
{type = "const unsigned char *", name = "data"},
|
{type = "const char *", name = "text"},
|
||||||
{type = "int *", name = "outputSize"}
|
{type = "int *", name = "outputSize"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -4426,7 +4426,7 @@ return {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "GetGamepadAxisCount",
|
name = "GetGamepadAxisCount",
|
||||||
description = "Get gamepad axis count for a gamepad",
|
description = "Get axis count for a gamepad",
|
||||||
returnType = "int",
|
returnType = "int",
|
||||||
params = {
|
params = {
|
||||||
{type = "int", name = "gamepad"}
|
{type = "int", name = "gamepad"}
|
||||||
@ -4434,7 +4434,7 @@ return {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "GetGamepadAxisMovement",
|
name = "GetGamepadAxisMovement",
|
||||||
description = "Get axis movement value for a gamepad axis",
|
description = "Get movement value for a gamepad axis",
|
||||||
returnType = "float",
|
returnType = "float",
|
||||||
params = {
|
params = {
|
||||||
{type = "int", name = "gamepad"},
|
{type = "int", name = "gamepad"},
|
||||||
@ -4838,6 +4838,17 @@ return {
|
|||||||
{type = "Color", name = "color"}
|
{type = "Color", name = "color"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name = "DrawEllipseV",
|
||||||
|
description = "Draw ellipse (Vector version)",
|
||||||
|
returnType = "void",
|
||||||
|
params = {
|
||||||
|
{type = "Vector2", name = "center"},
|
||||||
|
{type = "float", name = "radiusH"},
|
||||||
|
{type = "float", name = "radiusV"},
|
||||||
|
{type = "Color", name = "color"}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name = "DrawEllipseLines",
|
name = "DrawEllipseLines",
|
||||||
description = "Draw ellipse outline",
|
description = "Draw ellipse outline",
|
||||||
@ -4850,6 +4861,17 @@ return {
|
|||||||
{type = "Color", name = "color"}
|
{type = "Color", name = "color"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name = "DrawEllipseLinesV",
|
||||||
|
description = "Draw ellipse outline (Vector version)",
|
||||||
|
returnType = "void",
|
||||||
|
params = {
|
||||||
|
{type = "Vector2", name = "center"},
|
||||||
|
{type = "float", name = "radiusH"},
|
||||||
|
{type = "float", name = "radiusV"},
|
||||||
|
{type = "Color", name = "color"}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name = "DrawRing",
|
name = "DrawRing",
|
||||||
description = "Draw ring",
|
description = "Draw ring",
|
||||||
@ -4954,8 +4976,8 @@ return {
|
|||||||
{type = "Rectangle", name = "rec"},
|
{type = "Rectangle", name = "rec"},
|
||||||
{type = "Color", name = "topLeft"},
|
{type = "Color", name = "topLeft"},
|
||||||
{type = "Color", name = "bottomLeft"},
|
{type = "Color", name = "bottomLeft"},
|
||||||
{type = "Color", name = "topRight"},
|
{type = "Color", name = "bottomRight"},
|
||||||
{type = "Color", name = "bottomRight"}
|
{type = "Color", name = "topRight"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -6119,7 +6141,7 @@ return {
|
|||||||
returnType = "void",
|
returnType = "void",
|
||||||
params = {
|
params = {
|
||||||
{type = "Image *", name = "dst"},
|
{type = "Image *", name = "dst"},
|
||||||
{type = "Vector2 *", name = "points"},
|
{type = "const Vector2 *", name = "points"},
|
||||||
{type = "int", name = "pointCount"},
|
{type = "int", name = "pointCount"},
|
||||||
{type = "Color", name = "color"}
|
{type = "Color", name = "color"}
|
||||||
}
|
}
|
||||||
@ -6130,7 +6152,7 @@ return {
|
|||||||
returnType = "void",
|
returnType = "void",
|
||||||
params = {
|
params = {
|
||||||
{type = "Image *", name = "dst"},
|
{type = "Image *", name = "dst"},
|
||||||
{type = "Vector2 *", name = "points"},
|
{type = "const Vector2 *", name = "points"},
|
||||||
{type = "int", name = "pointCount"},
|
{type = "int", name = "pointCount"},
|
||||||
{type = "Color", name = "color"}
|
{type = "Color", name = "color"}
|
||||||
}
|
}
|
||||||
@ -6242,7 +6264,7 @@ return {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "UpdateTexture",
|
name = "UpdateTexture",
|
||||||
description = "Update GPU texture with new data",
|
description = "Update GPU texture with new data (pixels should be able to fill texture)",
|
||||||
returnType = "void",
|
returnType = "void",
|
||||||
params = {
|
params = {
|
||||||
{type = "Texture2D", name = "texture"},
|
{type = "Texture2D", name = "texture"},
|
||||||
@ -6251,7 +6273,7 @@ return {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "UpdateTextureRec",
|
name = "UpdateTextureRec",
|
||||||
description = "Update GPU texture rectangle with new data",
|
description = "Update GPU texture rectangle with new data (pixels and rec should fit in texture)",
|
||||||
returnType = "void",
|
returnType = "void",
|
||||||
params = {
|
params = {
|
||||||
{type = "Texture2D", name = "texture"},
|
{type = "Texture2D", name = "texture"},
|
||||||
@ -7850,7 +7872,7 @@ return {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "UpdateSound",
|
name = "UpdateSound",
|
||||||
description = "Update sound buffer with new data",
|
description = "Update sound buffer with new data (data and frame count should fit in sound)",
|
||||||
returnType = "void",
|
returnType = "void",
|
||||||
params = {
|
params = {
|
||||||
{type = "Sound", name = "sound"},
|
{type = "Sound", name = "sound"},
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -486,7 +486,7 @@
|
|||||||
<Value name="GAMEPAD_BUTTON_LEFT_THUMB" integer="16" desc="Gamepad joystick pressed button left" />
|
<Value name="GAMEPAD_BUTTON_LEFT_THUMB" integer="16" desc="Gamepad joystick pressed button left" />
|
||||||
<Value name="GAMEPAD_BUTTON_RIGHT_THUMB" integer="17" desc="Gamepad joystick pressed button right" />
|
<Value name="GAMEPAD_BUTTON_RIGHT_THUMB" integer="17" desc="Gamepad joystick pressed button right" />
|
||||||
</Enum>
|
</Enum>
|
||||||
<Enum name="GamepadAxis" valueCount="6" desc="Gamepad axis">
|
<Enum name="GamepadAxis" valueCount="6" desc="Gamepad axes">
|
||||||
<Value name="GAMEPAD_AXIS_LEFT_X" integer="0" desc="Gamepad left stick X axis" />
|
<Value name="GAMEPAD_AXIS_LEFT_X" integer="0" desc="Gamepad left stick X axis" />
|
||||||
<Value name="GAMEPAD_AXIS_LEFT_Y" integer="1" desc="Gamepad left stick Y axis" />
|
<Value name="GAMEPAD_AXIS_LEFT_Y" integer="1" desc="Gamepad left stick Y axis" />
|
||||||
<Value name="GAMEPAD_AXIS_RIGHT_X" integer="2" desc="Gamepad right stick X axis" />
|
<Value name="GAMEPAD_AXIS_RIGHT_X" integer="2" desc="Gamepad right stick X axis" />
|
||||||
@ -672,14 +672,14 @@
|
|||||||
</Callback>
|
</Callback>
|
||||||
<Callback name="SaveFileTextCallback" retType="bool" paramCount="2" desc="FileIO: Save text data">
|
<Callback name="SaveFileTextCallback" retType="bool" paramCount="2" desc="FileIO: Save text data">
|
||||||
<Param type="const char *" name="fileName" desc="" />
|
<Param type="const char *" name="fileName" desc="" />
|
||||||
<Param type="char *" name="text" desc="" />
|
<Param type="const char *" name="text" desc="" />
|
||||||
</Callback>
|
</Callback>
|
||||||
<Callback name="AudioCallback" retType="void" paramCount="2" desc="">
|
<Callback name="AudioCallback" retType="void" paramCount="2" desc="">
|
||||||
<Param type="void *" name="bufferData" desc="" />
|
<Param type="void *" name="bufferData" desc="" />
|
||||||
<Param type="unsigned int" name="frames" desc="" />
|
<Param type="unsigned int" name="frames" desc="" />
|
||||||
</Callback>
|
</Callback>
|
||||||
</Callbacks>
|
</Callbacks>
|
||||||
<Functions count="582">
|
<Functions count="584">
|
||||||
<Function name="InitWindow" retType="void" paramCount="3" desc="Initialize window and OpenGL context">
|
<Function name="InitWindow" retType="void" paramCount="3" desc="Initialize window and OpenGL context">
|
||||||
<Param type="int" name="width" desc="" />
|
<Param type="int" name="width" desc="" />
|
||||||
<Param type="int" name="height" desc="" />
|
<Param type="int" name="height" desc="" />
|
||||||
@ -1046,7 +1046,7 @@
|
|||||||
</Function>
|
</Function>
|
||||||
<Function name="SaveFileText" retType="bool" paramCount="2" desc="Save text data to file (write), string must be '\0' terminated, returns true on success">
|
<Function name="SaveFileText" retType="bool" paramCount="2" desc="Save text data to file (write), string must be '\0' terminated, returns true on success">
|
||||||
<Param type="const char *" name="fileName" desc="" />
|
<Param type="const char *" name="fileName" desc="" />
|
||||||
<Param type="char *" name="text" desc="" />
|
<Param type="const char *" name="text" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="FileExists" retType="bool" paramCount="1" desc="Check if file exists">
|
<Function name="FileExists" retType="bool" paramCount="1" desc="Check if file exists">
|
||||||
<Param type="const char *" name="fileName" desc="" />
|
<Param type="const char *" name="fileName" desc="" />
|
||||||
@ -1123,13 +1123,13 @@
|
|||||||
<Param type="int" name="compDataSize" desc="" />
|
<Param type="int" name="compDataSize" desc="" />
|
||||||
<Param type="int *" name="dataSize" desc="" />
|
<Param type="int *" name="dataSize" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="EncodeDataBase64" retType="char *" paramCount="3" desc="Encode data to Base64 string, memory must be MemFree()">
|
<Function name="EncodeDataBase64" retType="char *" paramCount="3" desc="Encode data to Base64 string (includes NULL terminator), memory must be MemFree()">
|
||||||
<Param type="const unsigned char *" name="data" desc="" />
|
<Param type="const unsigned char *" name="data" desc="" />
|
||||||
<Param type="int" name="dataSize" desc="" />
|
<Param type="int" name="dataSize" desc="" />
|
||||||
<Param type="int *" name="outputSize" desc="" />
|
<Param type="int *" name="outputSize" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="DecodeDataBase64" retType="unsigned char *" paramCount="2" desc="Decode Base64 string data, memory must be MemFree()">
|
<Function name="DecodeDataBase64" retType="unsigned char *" paramCount="2" desc="Decode Base64 string (expected NULL terminated), memory must be MemFree()">
|
||||||
<Param type="const unsigned char *" name="data" desc="" />
|
<Param type="const char *" name="text" desc="" />
|
||||||
<Param type="int *" name="outputSize" desc="" />
|
<Param type="int *" name="outputSize" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="ComputeCRC32" retType="unsigned int" paramCount="2" desc="Compute CRC32 hash code">
|
<Function name="ComputeCRC32" retType="unsigned int" paramCount="2" desc="Compute CRC32 hash code">
|
||||||
@ -1216,10 +1216,10 @@
|
|||||||
</Function>
|
</Function>
|
||||||
<Function name="GetGamepadButtonPressed" retType="int" paramCount="0" desc="Get the last gamepad button pressed">
|
<Function name="GetGamepadButtonPressed" retType="int" paramCount="0" desc="Get the last gamepad button pressed">
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="GetGamepadAxisCount" retType="int" paramCount="1" desc="Get gamepad axis count for a gamepad">
|
<Function name="GetGamepadAxisCount" retType="int" paramCount="1" desc="Get axis count for a gamepad">
|
||||||
<Param type="int" name="gamepad" desc="" />
|
<Param type="int" name="gamepad" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="GetGamepadAxisMovement" retType="float" paramCount="2" desc="Get axis movement value for a gamepad axis">
|
<Function name="GetGamepadAxisMovement" retType="float" paramCount="2" desc="Get movement value for a gamepad axis">
|
||||||
<Param type="int" name="gamepad" desc="" />
|
<Param type="int" name="gamepad" desc="" />
|
||||||
<Param type="int" name="axis" desc="" />
|
<Param type="int" name="axis" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
@ -1409,6 +1409,12 @@
|
|||||||
<Param type="float" name="radiusV" desc="" />
|
<Param type="float" name="radiusV" desc="" />
|
||||||
<Param type="Color" name="color" desc="" />
|
<Param type="Color" name="color" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
|
<Function name="DrawEllipseV" retType="void" paramCount="4" desc="Draw ellipse (Vector version)">
|
||||||
|
<Param type="Vector2" name="center" desc="" />
|
||||||
|
<Param type="float" name="radiusH" desc="" />
|
||||||
|
<Param type="float" name="radiusV" desc="" />
|
||||||
|
<Param type="Color" name="color" desc="" />
|
||||||
|
</Function>
|
||||||
<Function name="DrawEllipseLines" retType="void" paramCount="5" desc="Draw ellipse outline">
|
<Function name="DrawEllipseLines" retType="void" paramCount="5" desc="Draw ellipse outline">
|
||||||
<Param type="int" name="centerX" desc="" />
|
<Param type="int" name="centerX" desc="" />
|
||||||
<Param type="int" name="centerY" desc="" />
|
<Param type="int" name="centerY" desc="" />
|
||||||
@ -1416,6 +1422,12 @@
|
|||||||
<Param type="float" name="radiusV" desc="" />
|
<Param type="float" name="radiusV" desc="" />
|
||||||
<Param type="Color" name="color" desc="" />
|
<Param type="Color" name="color" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
|
<Function name="DrawEllipseLinesV" retType="void" paramCount="4" desc="Draw ellipse outline (Vector version)">
|
||||||
|
<Param type="Vector2" name="center" desc="" />
|
||||||
|
<Param type="float" name="radiusH" desc="" />
|
||||||
|
<Param type="float" name="radiusV" desc="" />
|
||||||
|
<Param type="Color" name="color" desc="" />
|
||||||
|
</Function>
|
||||||
<Function name="DrawRing" retType="void" paramCount="7" desc="Draw ring">
|
<Function name="DrawRing" retType="void" paramCount="7" desc="Draw ring">
|
||||||
<Param type="Vector2" name="center" desc="" />
|
<Param type="Vector2" name="center" desc="" />
|
||||||
<Param type="float" name="innerRadius" desc="" />
|
<Param type="float" name="innerRadius" desc="" />
|
||||||
@ -1476,8 +1488,8 @@
|
|||||||
<Param type="Rectangle" name="rec" desc="" />
|
<Param type="Rectangle" name="rec" desc="" />
|
||||||
<Param type="Color" name="topLeft" desc="" />
|
<Param type="Color" name="topLeft" desc="" />
|
||||||
<Param type="Color" name="bottomLeft" desc="" />
|
<Param type="Color" name="bottomLeft" desc="" />
|
||||||
<Param type="Color" name="topRight" desc="" />
|
|
||||||
<Param type="Color" name="bottomRight" desc="" />
|
<Param type="Color" name="bottomRight" desc="" />
|
||||||
|
<Param type="Color" name="topRight" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="DrawRectangleLines" retType="void" paramCount="5" desc="Draw rectangle outline">
|
<Function name="DrawRectangleLines" retType="void" paramCount="5" desc="Draw rectangle outline">
|
||||||
<Param type="int" name="posX" desc="" />
|
<Param type="int" name="posX" desc="" />
|
||||||
@ -2078,13 +2090,13 @@
|
|||||||
</Function>
|
</Function>
|
||||||
<Function name="ImageDrawTriangleFan" retType="void" paramCount="4" desc="Draw a triangle fan defined by points within an image (first vertex is the center)">
|
<Function name="ImageDrawTriangleFan" retType="void" paramCount="4" desc="Draw a triangle fan defined by points within an image (first vertex is the center)">
|
||||||
<Param type="Image *" name="dst" desc="" />
|
<Param type="Image *" name="dst" desc="" />
|
||||||
<Param type="Vector2 *" name="points" desc="" />
|
<Param type="const Vector2 *" name="points" desc="" />
|
||||||
<Param type="int" name="pointCount" desc="" />
|
<Param type="int" name="pointCount" desc="" />
|
||||||
<Param type="Color" name="color" desc="" />
|
<Param type="Color" name="color" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="ImageDrawTriangleStrip" retType="void" paramCount="4" desc="Draw a triangle strip defined by points within an image">
|
<Function name="ImageDrawTriangleStrip" retType="void" paramCount="4" desc="Draw a triangle strip defined by points within an image">
|
||||||
<Param type="Image *" name="dst" desc="" />
|
<Param type="Image *" name="dst" desc="" />
|
||||||
<Param type="Vector2 *" name="points" desc="" />
|
<Param type="const Vector2 *" name="points" desc="" />
|
||||||
<Param type="int" name="pointCount" desc="" />
|
<Param type="int" name="pointCount" desc="" />
|
||||||
<Param type="Color" name="color" desc="" />
|
<Param type="Color" name="color" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
@ -2138,11 +2150,11 @@
|
|||||||
<Function name="UnloadRenderTexture" retType="void" paramCount="1" desc="Unload render texture from GPU memory (VRAM)">
|
<Function name="UnloadRenderTexture" retType="void" paramCount="1" desc="Unload render texture from GPU memory (VRAM)">
|
||||||
<Param type="RenderTexture2D" name="target" desc="" />
|
<Param type="RenderTexture2D" name="target" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="UpdateTexture" retType="void" paramCount="2" desc="Update GPU texture with new data">
|
<Function name="UpdateTexture" retType="void" paramCount="2" desc="Update GPU texture with new data (pixels should be able to fill texture)">
|
||||||
<Param type="Texture2D" name="texture" desc="" />
|
<Param type="Texture2D" name="texture" desc="" />
|
||||||
<Param type="const void *" name="pixels" desc="" />
|
<Param type="const void *" name="pixels" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="UpdateTextureRec" retType="void" paramCount="3" desc="Update GPU texture rectangle with new data">
|
<Function name="UpdateTextureRec" retType="void" paramCount="3" desc="Update GPU texture rectangle with new data (pixels and rec should fit in texture)">
|
||||||
<Param type="Texture2D" name="texture" desc="" />
|
<Param type="Texture2D" name="texture" desc="" />
|
||||||
<Param type="Rectangle" name="rec" desc="" />
|
<Param type="Rectangle" name="rec" desc="" />
|
||||||
<Param type="const void *" name="pixels" desc="" />
|
<Param type="const void *" name="pixels" desc="" />
|
||||||
@ -2928,7 +2940,7 @@
|
|||||||
<Function name="IsSoundValid" retType="bool" paramCount="1" desc="Checks if a sound is valid (data loaded and buffers initialized)">
|
<Function name="IsSoundValid" retType="bool" paramCount="1" desc="Checks if a sound is valid (data loaded and buffers initialized)">
|
||||||
<Param type="Sound" name="sound" desc="" />
|
<Param type="Sound" name="sound" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="UpdateSound" retType="void" paramCount="3" desc="Update sound buffer with new data">
|
<Function name="UpdateSound" retType="void" paramCount="3" desc="Update sound buffer with new data (data and frame count should fit in sound)">
|
||||||
<Param type="Sound" name="sound" desc="" />
|
<Param type="Sound" name="sound" desc="" />
|
||||||
<Param type="const void *" name="data" desc="" />
|
<Param type="const void *" name="data" desc="" />
|
||||||
<Param type="int" name="sampleCount" desc="" />
|
<Param type="int" name="sampleCount" desc="" />
|
||||||
|
@ -440,8 +440,8 @@ RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color c
|
|||||||
RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image
|
RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image
|
||||||
RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
|
RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
|
||||||
RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image
|
RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image
|
||||||
RLAPI void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
|
RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
|
||||||
RLAPI void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
|
RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
|
||||||
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
|
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
|
||||||
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
|
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
|
||||||
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
|
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
|
||||||
|
@ -868,7 +868,7 @@ clean: clean_shell_$(PLATFORM_SHELL)
|
|||||||
@echo "removed all generated files!"
|
@echo "removed all generated files!"
|
||||||
|
|
||||||
clean_shell_sh:
|
clean_shell_sh:
|
||||||
rm -fv *.o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).a $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).bc $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).so* raygui.c $(RAYLIB_RELEASE_PATH)/*-protocol.h $(RAYLIB_RELEASE_PATH)/*-protocol-code.h
|
rm -fv *.o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).a $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).web.a $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).so* raygui.c $(RAYLIB_RELEASE_PATH)/*-protocol.h $(RAYLIB_RELEASE_PATH)/*-protocol-code.h
|
||||||
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
|
ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
|
||||||
rm -fv $(NATIVE_APP_GLUE)/android_native_app_glue.o
|
rm -fv $(NATIVE_APP_GLUE)/android_native_app_glue.o
|
||||||
endif
|
endif
|
||||||
@ -879,6 +879,7 @@ clean_shell_cmd:
|
|||||||
del *.o /s
|
del *.o /s
|
||||||
cd $(RAYLIB_RELEASE_PATH) & \
|
cd $(RAYLIB_RELEASE_PATH) & \
|
||||||
del lib$(RAYLIB_LIB_NAME).a /s & \
|
del lib$(RAYLIB_LIB_NAME).a /s & \
|
||||||
|
del lib$(RAYLIB_LIB_NAME).web.a /s & \
|
||||||
del lib$(RAYLIB_LIB_NAME)dll.a /s & \
|
del lib$(RAYLIB_LIB_NAME)dll.a /s & \
|
||||||
del $(RAYLIB_LIB_NAME).dll /s & \
|
del $(RAYLIB_LIB_NAME).dll /s & \
|
||||||
del raygui.c /s & \
|
del raygui.c /s & \
|
||||||
|
@ -104,7 +104,7 @@
|
|||||||
#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
|
#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
|
||||||
#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
|
#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
|
||||||
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
|
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
|
||||||
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
|
#define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad)
|
||||||
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
|
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
|
||||||
#define MAX_GAMEPAD_VIBRATION_TIME 2.0f // Maximum vibration time in seconds
|
#define MAX_GAMEPAD_VIBRATION_TIME 2.0f // Maximum vibration time in seconds
|
||||||
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
|
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
|
||||||
@ -189,7 +189,7 @@
|
|||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: rtextures - Configuration Flags
|
// Module: rtextures - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Selecte desired fileformats to be supported for image data loading
|
// Selected desired fileformats to be supported for image data loading
|
||||||
#define SUPPORT_FILEFORMAT_PNG 1
|
#define SUPPORT_FILEFORMAT_PNG 1
|
||||||
//#define SUPPORT_FILEFORMAT_BMP 1
|
//#define SUPPORT_FILEFORMAT_BMP 1
|
||||||
//#define SUPPORT_FILEFORMAT_TGA 1
|
//#define SUPPORT_FILEFORMAT_TGA 1
|
||||||
|
4841
libs/raylib/src/external/RGFW.h
vendored
4841
libs/raylib/src/external/RGFW.h
vendored
File diff suppressed because it is too large
Load Diff
420
libs/raylib/src/external/dr_flac.h
vendored
420
libs/raylib/src/external/dr_flac.h
vendored
@ -1,121 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||||
dr_flac - v0.12.42 - 2023-11-02
|
dr_flac - v0.13.0 - TBD
|
||||||
|
|
||||||
David Reid - mackron@gmail.com
|
David Reid - mackron@gmail.com
|
||||||
|
|
||||||
GitHub: https://github.com/mackron/dr_libs
|
GitHub: https://github.com/mackron/dr_libs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
RELEASE NOTES - v0.12.0
|
|
||||||
=======================
|
|
||||||
Version 0.12.0 has breaking API changes including changes to the existing API and the removal of deprecated APIs.
|
|
||||||
|
|
||||||
|
|
||||||
Improved Client-Defined Memory Allocation
|
|
||||||
-----------------------------------------
|
|
||||||
The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The
|
|
||||||
existing system of DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE are still in place and will be used by default when no custom
|
|
||||||
allocation callbacks are specified.
|
|
||||||
|
|
||||||
To use the new system, you pass in a pointer to a drflac_allocation_callbacks object to drflac_open() and family, like this:
|
|
||||||
|
|
||||||
void* my_malloc(size_t sz, void* pUserData)
|
|
||||||
{
|
|
||||||
return malloc(sz);
|
|
||||||
}
|
|
||||||
void* my_realloc(void* p, size_t sz, void* pUserData)
|
|
||||||
{
|
|
||||||
return realloc(p, sz);
|
|
||||||
}
|
|
||||||
void my_free(void* p, void* pUserData)
|
|
||||||
{
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
drflac_allocation_callbacks allocationCallbacks;
|
|
||||||
allocationCallbacks.pUserData = &myData;
|
|
||||||
allocationCallbacks.onMalloc = my_malloc;
|
|
||||||
allocationCallbacks.onRealloc = my_realloc;
|
|
||||||
allocationCallbacks.onFree = my_free;
|
|
||||||
drflac* pFlac = drflac_open_file("my_file.flac", &allocationCallbacks);
|
|
||||||
|
|
||||||
The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines.
|
|
||||||
|
|
||||||
Passing in null for the allocation callbacks object will cause dr_flac to use defaults which is the same as DRFLAC_MALLOC,
|
|
||||||
DRFLAC_REALLOC and DRFLAC_FREE and the equivalent of how it worked in previous versions.
|
|
||||||
|
|
||||||
Every API that opens a drflac object now takes this extra parameter. These include the following:
|
|
||||||
|
|
||||||
drflac_open()
|
|
||||||
drflac_open_relaxed()
|
|
||||||
drflac_open_with_metadata()
|
|
||||||
drflac_open_with_metadata_relaxed()
|
|
||||||
drflac_open_file()
|
|
||||||
drflac_open_file_with_metadata()
|
|
||||||
drflac_open_memory()
|
|
||||||
drflac_open_memory_with_metadata()
|
|
||||||
drflac_open_and_read_pcm_frames_s32()
|
|
||||||
drflac_open_and_read_pcm_frames_s16()
|
|
||||||
drflac_open_and_read_pcm_frames_f32()
|
|
||||||
drflac_open_file_and_read_pcm_frames_s32()
|
|
||||||
drflac_open_file_and_read_pcm_frames_s16()
|
|
||||||
drflac_open_file_and_read_pcm_frames_f32()
|
|
||||||
drflac_open_memory_and_read_pcm_frames_s32()
|
|
||||||
drflac_open_memory_and_read_pcm_frames_s16()
|
|
||||||
drflac_open_memory_and_read_pcm_frames_f32()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Optimizations
|
|
||||||
-------------
|
|
||||||
Seeking performance has been greatly improved. A new binary search based seeking algorithm has been introduced which significantly
|
|
||||||
improves performance over the brute force method which was used when no seek table was present. Seek table based seeking also takes
|
|
||||||
advantage of the new binary search seeking system to further improve performance there as well. Note that this depends on CRC which
|
|
||||||
means it will be disabled when DR_FLAC_NO_CRC is used.
|
|
||||||
|
|
||||||
The SSE4.1 pipeline has been cleaned up and optimized. You should see some improvements with decoding speed of 24-bit files in
|
|
||||||
particular. 16-bit streams should also see some improvement.
|
|
||||||
|
|
||||||
drflac_read_pcm_frames_s16() has been optimized. Previously this sat on top of drflac_read_pcm_frames_s32() and performed it's s32
|
|
||||||
to s16 conversion in a second pass. This is now all done in a single pass. This includes SSE2 and ARM NEON optimized paths.
|
|
||||||
|
|
||||||
A minor optimization has been implemented for drflac_read_pcm_frames_s32(). This will now use an SSE2 optimized pipeline for stereo
|
|
||||||
channel reconstruction which is the last part of the decoding process.
|
|
||||||
|
|
||||||
The ARM build has seen a few improvements. The CLZ (count leading zeroes) and REV (byte swap) instructions are now used when
|
|
||||||
compiling with GCC and Clang which is achieved using inline assembly. The CLZ instruction requires ARM architecture version 5 at
|
|
||||||
compile time and the REV instruction requires ARM architecture version 6.
|
|
||||||
|
|
||||||
An ARM NEON optimized pipeline has been implemented. To enable this you'll need to add -mfpu=neon to the command line when compiling.
|
|
||||||
|
|
||||||
|
|
||||||
Removed APIs
|
|
||||||
------------
|
|
||||||
The following APIs were deprecated in version 0.11.0 and have been completely removed in version 0.12.0:
|
|
||||||
|
|
||||||
drflac_read_s32() -> drflac_read_pcm_frames_s32()
|
|
||||||
drflac_read_s16() -> drflac_read_pcm_frames_s16()
|
|
||||||
drflac_read_f32() -> drflac_read_pcm_frames_f32()
|
|
||||||
drflac_seek_to_sample() -> drflac_seek_to_pcm_frame()
|
|
||||||
drflac_open_and_decode_s32() -> drflac_open_and_read_pcm_frames_s32()
|
|
||||||
drflac_open_and_decode_s16() -> drflac_open_and_read_pcm_frames_s16()
|
|
||||||
drflac_open_and_decode_f32() -> drflac_open_and_read_pcm_frames_f32()
|
|
||||||
drflac_open_and_decode_file_s32() -> drflac_open_file_and_read_pcm_frames_s32()
|
|
||||||
drflac_open_and_decode_file_s16() -> drflac_open_file_and_read_pcm_frames_s16()
|
|
||||||
drflac_open_and_decode_file_f32() -> drflac_open_file_and_read_pcm_frames_f32()
|
|
||||||
drflac_open_and_decode_memory_s32() -> drflac_open_memory_and_read_pcm_frames_s32()
|
|
||||||
drflac_open_and_decode_memory_s16() -> drflac_open_memory_and_read_pcm_frames_s16()
|
|
||||||
drflac_open_and_decode_memory_f32() -> drflac_open_memroy_and_read_pcm_frames_f32()
|
|
||||||
|
|
||||||
Prior versions of dr_flac operated on a per-sample basis whereas now it operates on PCM frames. The removed APIs all relate
|
|
||||||
to the old per-sample APIs. You now need to use the "pcm_frame" versions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
@ -234,8 +125,8 @@ extern "C" {
|
|||||||
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
|
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
|
||||||
|
|
||||||
#define DRFLAC_VERSION_MAJOR 0
|
#define DRFLAC_VERSION_MAJOR 0
|
||||||
#define DRFLAC_VERSION_MINOR 12
|
#define DRFLAC_VERSION_MINOR 13
|
||||||
#define DRFLAC_VERSION_REVISION 42
|
#define DRFLAC_VERSION_REVISION 0
|
||||||
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
|
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
|
||||||
|
|
||||||
#include <stddef.h> /* For size_t. */
|
#include <stddef.h> /* For size_t. */
|
||||||
@ -348,11 +239,11 @@ but also more memory. In my testing there is diminishing returns after about 4KB
|
|||||||
#define DRFLAC_64BIT
|
#define DRFLAC_64BIT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__x86_64__) || defined(_M_X64)
|
#if defined(__x86_64__) || (defined(_M_X64) && !defined(_M_ARM64EC))
|
||||||
#define DRFLAC_X64
|
#define DRFLAC_X64
|
||||||
#elif defined(__i386) || defined(_M_IX86)
|
#elif defined(__i386) || defined(_M_IX86)
|
||||||
#define DRFLAC_X86
|
#define DRFLAC_X86
|
||||||
#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
|
#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
|
||||||
#define DRFLAC_ARM
|
#define DRFLAC_ARM
|
||||||
#endif
|
#endif
|
||||||
/* End Architecture Detection */
|
/* End Architecture Detection */
|
||||||
@ -406,8 +297,9 @@ typedef enum
|
|||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
drflac_seek_origin_start,
|
DRFLAC_SEEK_SET,
|
||||||
drflac_seek_origin_current
|
DRFLAC_SEEK_CUR,
|
||||||
|
DRFLAC_SEEK_END
|
||||||
} drflac_seek_origin;
|
} drflac_seek_origin;
|
||||||
|
|
||||||
/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */
|
/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */
|
||||||
@ -547,7 +439,7 @@ offset (in)
|
|||||||
The number of bytes to move, relative to the origin. Will never be negative.
|
The number of bytes to move, relative to the origin. Will never be negative.
|
||||||
|
|
||||||
origin (in)
|
origin (in)
|
||||||
The origin of the seek - the current position or the start of the stream.
|
The origin of the seek - the current position, the start of the stream, or the end of the stream.
|
||||||
|
|
||||||
|
|
||||||
Return Value
|
Return Value
|
||||||
@ -557,14 +449,32 @@ Whether or not the seek was successful.
|
|||||||
|
|
||||||
Remarks
|
Remarks
|
||||||
-------
|
-------
|
||||||
The offset will never be negative. Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be
|
Seeking relative to the start and the current position must always be supported. If seeking from the end of the stream is not supported, return DRFLAC_FALSE.
|
||||||
either drflac_seek_origin_start or drflac_seek_origin_current.
|
|
||||||
|
|
||||||
When seeking to a PCM frame using drflac_seek_to_pcm_frame(), dr_flac may call this with an offset beyond the end of the FLAC stream. This needs to be detected
|
When seeking to a PCM frame using drflac_seek_to_pcm_frame(), dr_flac may call this with an offset beyond the end of the FLAC stream. This needs to be detected
|
||||||
and handled by returning DRFLAC_FALSE.
|
and handled by returning DRFLAC_FALSE.
|
||||||
*/
|
*/
|
||||||
typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
|
typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Callback for when the current position in the stream needs to be retrieved.
|
||||||
|
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
pUserData (in)
|
||||||
|
The user data that was passed to drflac_open() and family.
|
||||||
|
|
||||||
|
pCursor (out)
|
||||||
|
A pointer to a variable to receive the current position in the stream.
|
||||||
|
|
||||||
|
|
||||||
|
Return Value
|
||||||
|
------------
|
||||||
|
Whether or not the operation was successful.
|
||||||
|
*/
|
||||||
|
typedef drflac_bool32 (* drflac_tell_proc)(void* pUserData, drflac_int64* pCursor);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback for when a metadata block is read.
|
Callback for when a metadata block is read.
|
||||||
|
|
||||||
@ -603,6 +513,9 @@ typedef struct
|
|||||||
/* The function to call when the current read position needs to be moved. */
|
/* The function to call when the current read position needs to be moved. */
|
||||||
drflac_seek_proc onSeek;
|
drflac_seek_proc onSeek;
|
||||||
|
|
||||||
|
/* The function to call when the current read position needs to be retrieved. */
|
||||||
|
drflac_tell_proc onTell;
|
||||||
|
|
||||||
/* The user data to pass around to onRead and onSeek. */
|
/* The user data to pass around to onRead and onSeek. */
|
||||||
void* pUserData;
|
void* pUserData;
|
||||||
|
|
||||||
@ -828,7 +741,7 @@ drflac_open_memory()
|
|||||||
drflac_open_with_metadata()
|
drflac_open_with_metadata()
|
||||||
drflac_close()
|
drflac_close()
|
||||||
*/
|
*/
|
||||||
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Opens a FLAC stream with relaxed validation of the header block.
|
Opens a FLAC stream with relaxed validation of the header block.
|
||||||
@ -869,7 +782,7 @@ force your `onRead` callback to return 0, which dr_flac will use as an indicator
|
|||||||
|
|
||||||
Use `drflac_open_with_metadata_relaxed()` if you need access to metadata.
|
Use `drflac_open_with_metadata_relaxed()` if you need access to metadata.
|
||||||
*/
|
*/
|
||||||
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.).
|
Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.).
|
||||||
@ -926,7 +839,7 @@ drflac_open_memory_with_metadata()
|
|||||||
drflac_open()
|
drflac_open()
|
||||||
drflac_close()
|
drflac_close()
|
||||||
*/
|
*/
|
||||||
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The same as drflac_open_with_metadata(), except attempts to open the stream even when a header block is not present.
|
The same as drflac_open_with_metadata(), except attempts to open the stream even when a header block is not present.
|
||||||
@ -936,7 +849,7 @@ See Also
|
|||||||
drflac_open_with_metadata()
|
drflac_open_with_metadata()
|
||||||
drflac_open_relaxed()
|
drflac_open_relaxed()
|
||||||
*/
|
*/
|
||||||
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Closes the given FLAC decoder.
|
Closes the given FLAC decoder.
|
||||||
@ -1234,13 +1147,13 @@ read samples into a dynamically sized buffer on the heap until no samples are le
|
|||||||
|
|
||||||
Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
|
Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
|
||||||
*/
|
*/
|
||||||
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
|
||||||
/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
|
/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
|
||||||
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
|
||||||
/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
|
/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
|
||||||
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
|
||||||
#ifndef DR_FLAC_NO_STDIO
|
#ifndef DR_FLAC_NO_STDIO
|
||||||
/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */
|
/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */
|
||||||
@ -2960,25 +2873,25 @@ static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFro
|
|||||||
*/
|
*/
|
||||||
if (offsetFromStart > 0x7FFFFFFF) {
|
if (offsetFromStart > 0x7FFFFFFF) {
|
||||||
drflac_uint64 bytesRemaining = offsetFromStart;
|
drflac_uint64 bytesRemaining = offsetFromStart;
|
||||||
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
|
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_SET)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
bytesRemaining -= 0x7FFFFFFF;
|
bytesRemaining -= 0x7FFFFFFF;
|
||||||
|
|
||||||
while (bytesRemaining > 0x7FFFFFFF) {
|
while (bytesRemaining > 0x7FFFFFFF) {
|
||||||
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
|
if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_CUR)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
bytesRemaining -= 0x7FFFFFFF;
|
bytesRemaining -= 0x7FFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytesRemaining > 0) {
|
if (bytesRemaining > 0) {
|
||||||
if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) {
|
if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, DRFLAC_SEEK_CUR)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) {
|
if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, DRFLAC_SEEK_SET)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5393,6 +5306,12 @@ static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe
|
|||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Default to 0 for the LPC order. It's important that we always set this to 0 for non LPC
|
||||||
|
and FIXED subframes because we'll be using it in a generic validation check later.
|
||||||
|
*/
|
||||||
|
pSubframe->lpcOrder = 0;
|
||||||
|
|
||||||
type = (header & 0x7E) >> 1;
|
type = (header & 0x7E) >> 1;
|
||||||
if (type == 0) {
|
if (type == 0) {
|
||||||
pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
|
pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
|
||||||
@ -5465,6 +5384,18 @@ static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame,
|
|||||||
|
|
||||||
pSubframe->pSamplesS32 = pDecodedSamplesOut;
|
pSubframe->pSamplesS32 = pDecodedSamplesOut;
|
||||||
|
|
||||||
|
/*
|
||||||
|
pDecodedSamplesOut will be pointing to a buffer that was allocated with enough memory to store
|
||||||
|
maxBlockSizeInPCMFrames samples (as specified in the FLAC header). We need to guard against an
|
||||||
|
overflow here. At a higher level we are checking maxBlockSizeInPCMFrames from the header, but
|
||||||
|
here we need to do an additional check to ensure this frame's block size fully encompasses any
|
||||||
|
warmup samples which is determined by the LPC order. For non LPC and FIXED subframes, the LPC
|
||||||
|
order will be have been set to 0 in drflac__read_subframe_header().
|
||||||
|
*/
|
||||||
|
if (frame->header.blockSizeInPCMFrames < pSubframe->lpcOrder) {
|
||||||
|
return DRFLAC_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
switch (pSubframe->subframeType)
|
switch (pSubframe->subframeType)
|
||||||
{
|
{
|
||||||
case DRFLAC_SUBFRAME_CONSTANT:
|
case DRFLAC_SUBFRAME_CONSTANT:
|
||||||
@ -6312,6 +6243,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
drflac_read_proc onRead;
|
drflac_read_proc onRead;
|
||||||
drflac_seek_proc onSeek;
|
drflac_seek_proc onSeek;
|
||||||
|
drflac_tell_proc onTell;
|
||||||
drflac_meta_proc onMeta;
|
drflac_meta_proc onMeta;
|
||||||
drflac_container container;
|
drflac_container container;
|
||||||
void* pUserData;
|
void* pUserData;
|
||||||
@ -6479,7 +6411,7 @@ static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbac
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks)
|
static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that
|
We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that
|
||||||
@ -6489,6 +6421,8 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
|||||||
drflac_uint64 seektablePos = 0;
|
drflac_uint64 seektablePos = 0;
|
||||||
drflac_uint32 seektableSize = 0;
|
drflac_uint32 seektableSize = 0;
|
||||||
|
|
||||||
|
(void)onTell;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
drflac_metadata metadata;
|
drflac_metadata metadata;
|
||||||
drflac_uint8 isLastBlock = 0;
|
drflac_uint8 isLastBlock = 0;
|
||||||
@ -6840,7 +6774,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
|||||||
metadata.data.padding.unused = 0;
|
metadata.data.padding.unused = 0;
|
||||||
|
|
||||||
/* Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. */
|
/* Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. */
|
||||||
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
|
if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
|
||||||
isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
|
isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
|
||||||
} else {
|
} else {
|
||||||
onMeta(pUserDataMD, &metadata);
|
onMeta(pUserDataMD, &metadata);
|
||||||
@ -6852,7 +6786,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
|||||||
{
|
{
|
||||||
/* Invalid chunk. Just skip over this one. */
|
/* Invalid chunk. Just skip over this one. */
|
||||||
if (onMeta) {
|
if (onMeta) {
|
||||||
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
|
if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
|
||||||
isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
|
isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6886,7 +6820,7 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
|
|||||||
|
|
||||||
/* If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. */
|
/* If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. */
|
||||||
if (onMeta == NULL && blockSize > 0) {
|
if (onMeta == NULL && blockSize > 0) {
|
||||||
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
|
if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) {
|
||||||
isLastBlock = DRFLAC_TRUE;
|
isLastBlock = DRFLAC_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7220,6 +7154,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
drflac_read_proc onRead; /* The original onRead callback from drflac_open() and family. */
|
drflac_read_proc onRead; /* The original onRead callback from drflac_open() and family. */
|
||||||
drflac_seek_proc onSeek; /* The original onSeek callback from drflac_open() and family. */
|
drflac_seek_proc onSeek; /* The original onSeek callback from drflac_open() and family. */
|
||||||
|
drflac_tell_proc onTell; /* The original onTell callback from drflac_open() and family. */
|
||||||
void* pUserData; /* The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. */
|
void* pUserData; /* The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. */
|
||||||
drflac_uint64 currentBytePos; /* The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. */
|
drflac_uint64 currentBytePos; /* The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. */
|
||||||
drflac_uint64 firstBytePos; /* The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. */
|
drflac_uint64 firstBytePos; /* The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. */
|
||||||
@ -7241,32 +7176,32 @@ static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut,
|
|||||||
|
|
||||||
static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin)
|
static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin)
|
||||||
{
|
{
|
||||||
if (origin == drflac_seek_origin_start) {
|
if (origin == DRFLAC_SEEK_SET) {
|
||||||
if (offset <= 0x7FFFFFFF) {
|
if (offset <= 0x7FFFFFFF) {
|
||||||
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) {
|
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, DRFLAC_SEEK_SET)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
oggbs->currentBytePos = offset;
|
oggbs->currentBytePos = offset;
|
||||||
|
|
||||||
return DRFLAC_TRUE;
|
return DRFLAC_TRUE;
|
||||||
} else {
|
} else {
|
||||||
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
|
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_SET)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
oggbs->currentBytePos = offset;
|
oggbs->currentBytePos = offset;
|
||||||
|
|
||||||
return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current);
|
return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, DRFLAC_SEEK_CUR);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (offset > 0x7FFFFFFF) {
|
while (offset > 0x7FFFFFFF) {
|
||||||
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
|
if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_CUR)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
oggbs->currentBytePos += 0x7FFFFFFF;
|
oggbs->currentBytePos += 0x7FFFFFFF;
|
||||||
offset -= 0x7FFFFFFF;
|
offset -= 0x7FFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { /* <-- Safe cast thanks to the loop above. */
|
if (!oggbs->onSeek(oggbs->pUserData, (int)offset, DRFLAC_SEEK_CUR)) { /* <-- Safe cast thanks to the loop above. */
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
oggbs->currentBytePos += offset;
|
oggbs->currentBytePos += offset;
|
||||||
@ -7298,7 +7233,7 @@ static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_og
|
|||||||
|
|
||||||
if (header.serialNumber != oggbs->serialNumber) {
|
if (header.serialNumber != oggbs->serialNumber) {
|
||||||
/* It's not a FLAC page. Skip it. */
|
/* It's not a FLAC page. Skip it. */
|
||||||
if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) {
|
if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, DRFLAC_SEEK_CUR)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -7384,7 +7319,7 @@ static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
|
|||||||
At this point we will have found either the packet or the end of the page. If were at the end of the page we'll
|
At this point we will have found either the packet or the end of the page. If were at the end of the page we'll
|
||||||
want to load the next page and keep searching for the end of the packet.
|
want to load the next page and keep searching for the end of the packet.
|
||||||
*/
|
*/
|
||||||
drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current);
|
drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, DRFLAC_SEEK_CUR);
|
||||||
oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
|
oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
|
||||||
|
|
||||||
if (atEndOfPage) {
|
if (atEndOfPage) {
|
||||||
@ -7462,8 +7397,8 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see
|
|||||||
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
|
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
|
||||||
|
|
||||||
/* Seeking is always forward which makes things a lot simpler. */
|
/* Seeking is always forward which makes things a lot simpler. */
|
||||||
if (origin == drflac_seek_origin_start) {
|
if (origin == DRFLAC_SEEK_SET) {
|
||||||
if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) {
|
if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, DRFLAC_SEEK_SET)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7471,11 +7406,8 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see
|
|||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current);
|
return drflac__on_seek_ogg(pUserData, offset, DRFLAC_SEEK_CUR);
|
||||||
}
|
} else if (origin == DRFLAC_SEEK_CUR) {
|
||||||
|
|
||||||
DRFLAC_ASSERT(origin == drflac_seek_origin_current);
|
|
||||||
|
|
||||||
while (bytesSeeked < offset) {
|
while (bytesSeeked < offset) {
|
||||||
int bytesRemainingToSeek = offset - bytesSeeked;
|
int bytesRemainingToSeek = offset - bytesSeeked;
|
||||||
DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
|
DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
|
||||||
@ -7499,10 +7431,25 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see
|
|||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (origin == DRFLAC_SEEK_END) {
|
||||||
|
/* Seeking to the end is not supported. */
|
||||||
|
return DRFLAC_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
return DRFLAC_TRUE;
|
return DRFLAC_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static drflac_bool32 drflac__on_tell_ogg(void* pUserData, drflac_int64* pCursor)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Not implemented for Ogg containers because we don't currently track the byte position of the logical bitstream. To support this, we'll need
|
||||||
|
to track the position in drflac__on_read_ogg and drflac__on_seek_ogg.
|
||||||
|
*/
|
||||||
|
(void)pUserData;
|
||||||
|
(void)pCursor;
|
||||||
|
return DRFLAC_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
|
static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
|
||||||
{
|
{
|
||||||
@ -7525,7 +7472,7 @@ static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64
|
|||||||
runningGranulePosition = 0;
|
runningGranulePosition = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
|
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
|
||||||
drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
|
drflac_oggbs__seek_physical(oggbs, originalBytePos, DRFLAC_SEEK_SET);
|
||||||
return DRFLAC_FALSE; /* Never did find that sample... */
|
return DRFLAC_FALSE; /* Never did find that sample... */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7559,7 +7506,7 @@ static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64
|
|||||||
a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until
|
a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until
|
||||||
we find the one containing the target sample.
|
we find the one containing the target sample.
|
||||||
*/
|
*/
|
||||||
if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) {
|
if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, DRFLAC_SEEK_SET)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
|
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
|
||||||
@ -7726,7 +7673,7 @@ static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_r
|
|||||||
The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to
|
The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to
|
||||||
be handling it in a generic way based on the serial number and packet types.
|
be handling it in a generic way based on the serial number and packet types.
|
||||||
*/
|
*/
|
||||||
if (!onSeek(pUserData, 2, drflac_seek_origin_current)) {
|
if (!onSeek(pUserData, 2, DRFLAC_SEEK_CUR)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7783,18 +7730,18 @@ static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_r
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Not a FLAC header. Skip it. */
|
/* Not a FLAC header. Skip it. */
|
||||||
if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
|
if (!onSeek(pUserData, bytesRemainingInPage, DRFLAC_SEEK_CUR)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Not a FLAC header. Seek past the entire page and move on to the next. */
|
/* Not a FLAC header. Seek past the entire page and move on to the next. */
|
||||||
if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
|
if (!onSeek(pUserData, bytesRemainingInPage, DRFLAC_SEEK_CUR)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) {
|
if (!onSeek(pUserData, pageBodySize, DRFLAC_SEEK_CUR)) {
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7819,18 +7766,19 @@ static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_r
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD)
|
static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD)
|
||||||
{
|
{
|
||||||
drflac_bool32 relaxed;
|
drflac_bool32 relaxed;
|
||||||
drflac_uint8 id[4];
|
drflac_uint8 id[4];
|
||||||
|
|
||||||
if (pInit == NULL || onRead == NULL || onSeek == NULL) {
|
if (pInit == NULL || onRead == NULL || onSeek == NULL) { /* <-- onTell is optional. */
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit));
|
DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit));
|
||||||
pInit->onRead = onRead;
|
pInit->onRead = onRead;
|
||||||
pInit->onSeek = onSeek;
|
pInit->onSeek = onSeek;
|
||||||
|
pInit->onTell = onTell;
|
||||||
pInit->onMeta = onMeta;
|
pInit->onMeta = onMeta;
|
||||||
pInit->container = container;
|
pInit->container = container;
|
||||||
pInit->pUserData = pUserData;
|
pInit->pUserData = pUserData;
|
||||||
@ -7838,6 +7786,7 @@ static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_p
|
|||||||
|
|
||||||
pInit->bs.onRead = onRead;
|
pInit->bs.onRead = onRead;
|
||||||
pInit->bs.onSeek = onSeek;
|
pInit->bs.onSeek = onSeek;
|
||||||
|
pInit->bs.onTell = onTell;
|
||||||
pInit->bs.pUserData = pUserData;
|
pInit->bs.pUserData = pUserData;
|
||||||
drflac__reset_cache(&pInit->bs);
|
drflac__reset_cache(&pInit->bs);
|
||||||
|
|
||||||
@ -7870,7 +7819,7 @@ static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_p
|
|||||||
headerSize += 10;
|
headerSize += 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) {
|
if (!onSeek(pUserData, headerSize, DRFLAC_SEEK_CUR)) {
|
||||||
return DRFLAC_FALSE; /* Failed to seek past the tag. */
|
return DRFLAC_FALSE; /* Failed to seek past the tag. */
|
||||||
}
|
}
|
||||||
pInit->runningFilePos += headerSize;
|
pInit->runningFilePos += headerSize;
|
||||||
@ -7922,7 +7871,7 @@ static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
|
static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
drflac_init_info init;
|
drflac_init_info init;
|
||||||
drflac_uint32 allocationSize;
|
drflac_uint32 allocationSize;
|
||||||
@ -7940,7 +7889,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
|||||||
/* CPU support first. */
|
/* CPU support first. */
|
||||||
drflac__init_cpu_caps();
|
drflac__init_cpu_caps();
|
||||||
|
|
||||||
if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) {
|
if (!drflac__init_private(&init, onRead, onSeek, onTell, onMeta, container, pUserData, pUserDataMD)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7996,6 +7945,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
|||||||
DRFLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs));
|
DRFLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs));
|
||||||
pOggbs->onRead = onRead;
|
pOggbs->onRead = onRead;
|
||||||
pOggbs->onSeek = onSeek;
|
pOggbs->onSeek = onSeek;
|
||||||
|
pOggbs->onTell = onTell;
|
||||||
pOggbs->pUserData = pUserData;
|
pOggbs->pUserData = pUserData;
|
||||||
pOggbs->currentBytePos = init.oggFirstBytePos;
|
pOggbs->currentBytePos = init.oggFirstBytePos;
|
||||||
pOggbs->firstBytePos = init.oggFirstBytePos;
|
pOggbs->firstBytePos = init.oggFirstBytePos;
|
||||||
@ -8016,17 +7966,19 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
|||||||
if (init.hasMetadataBlocks) {
|
if (init.hasMetadataBlocks) {
|
||||||
drflac_read_proc onReadOverride = onRead;
|
drflac_read_proc onReadOverride = onRead;
|
||||||
drflac_seek_proc onSeekOverride = onSeek;
|
drflac_seek_proc onSeekOverride = onSeek;
|
||||||
|
drflac_tell_proc onTellOverride = onTell;
|
||||||
void* pUserDataOverride = pUserData;
|
void* pUserDataOverride = pUserData;
|
||||||
|
|
||||||
#ifndef DR_FLAC_NO_OGG
|
#ifndef DR_FLAC_NO_OGG
|
||||||
if (init.container == drflac_container_ogg) {
|
if (init.container == drflac_container_ogg) {
|
||||||
onReadOverride = drflac__on_read_ogg;
|
onReadOverride = drflac__on_read_ogg;
|
||||||
onSeekOverride = drflac__on_seek_ogg;
|
onSeekOverride = drflac__on_seek_ogg;
|
||||||
|
onTellOverride = drflac__on_tell_ogg;
|
||||||
pUserDataOverride = (void*)pOggbs;
|
pUserDataOverride = (void*)pOggbs;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) {
|
if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onTellOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) {
|
||||||
#ifndef DR_FLAC_NO_OGG
|
#ifndef DR_FLAC_NO_OGG
|
||||||
drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
|
drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
|
||||||
#endif
|
#endif
|
||||||
@ -8061,6 +8013,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
|||||||
/* The Ogg bistream needs to be layered on top of the original bitstream. */
|
/* The Ogg bistream needs to be layered on top of the original bitstream. */
|
||||||
pFlac->bs.onRead = drflac__on_read_ogg;
|
pFlac->bs.onRead = drflac__on_read_ogg;
|
||||||
pFlac->bs.onSeek = drflac__on_seek_ogg;
|
pFlac->bs.onSeek = drflac__on_seek_ogg;
|
||||||
|
pFlac->bs.onTell = drflac__on_tell_ogg;
|
||||||
pFlac->bs.pUserData = (void*)pInternalOggbs;
|
pFlac->bs.pUserData = (void*)pInternalOggbs;
|
||||||
pFlac->_oggbs = (void*)pInternalOggbs;
|
pFlac->_oggbs = (void*)pInternalOggbs;
|
||||||
}
|
}
|
||||||
@ -8087,7 +8040,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
|||||||
DRFLAC_ASSERT(pFlac->bs.onRead != NULL);
|
DRFLAC_ASSERT(pFlac->bs.onRead != NULL);
|
||||||
|
|
||||||
/* Seek to the seektable, then just read directly into our seektable buffer. */
|
/* Seek to the seektable, then just read directly into our seektable buffer. */
|
||||||
if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) {
|
if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, DRFLAC_SEEK_SET)) {
|
||||||
drflac_uint32 iSeekpoint;
|
drflac_uint32 iSeekpoint;
|
||||||
|
|
||||||
for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) {
|
for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) {
|
||||||
@ -8105,7 +8058,7 @@ static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We need to seek back to where we were. If this fails it's a critical error. */
|
/* We need to seek back to where we were. If this fails it's a critical error. */
|
||||||
if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) {
|
if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, DRFLAC_SEEK_SET)) {
|
||||||
drflac__free_from_callbacks(pFlac, &allocationCallbacks);
|
drflac__free_from_callbacks(pFlac, &allocationCallbacks);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -8276,7 +8229,7 @@ static drflac_result drflac_result_from_errno(int e)
|
|||||||
#ifdef ENOSYS
|
#ifdef ENOSYS
|
||||||
case ENOSYS: return DRFLAC_NOT_IMPLEMENTED;
|
case ENOSYS: return DRFLAC_NOT_IMPLEMENTED;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENOTEMPTY
|
#if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST /* In AIX, ENOTEMPTY and EEXIST use the same value. */
|
||||||
case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY;
|
case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ELOOP
|
#ifdef ELOOP
|
||||||
@ -8727,11 +8680,41 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt
|
|||||||
|
|
||||||
static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
|
static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
|
||||||
{
|
{
|
||||||
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
|
int whence = SEEK_SET;
|
||||||
|
if (origin == DRFLAC_SEEK_CUR) {
|
||||||
return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
|
whence = SEEK_CUR;
|
||||||
|
} else if (origin == DRFLAC_SEEK_END) {
|
||||||
|
whence = SEEK_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fseek((FILE*)pUserData, offset, whence) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static drflac_bool32 drflac__on_tell_stdio(void* pUserData, drflac_int64* pCursor)
|
||||||
|
{
|
||||||
|
FILE* pFileStdio = (FILE*)pUserData;
|
||||||
|
drflac_int64 result;
|
||||||
|
|
||||||
|
/* These were all validated at a higher level. */
|
||||||
|
DRFLAC_ASSERT(pFileStdio != NULL);
|
||||||
|
DRFLAC_ASSERT(pCursor != NULL);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||||
|
result = _ftelli64(pFileStdio);
|
||||||
|
#else
|
||||||
|
result = ftell(pFileStdio);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
result = ftell(pFileStdio);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*pCursor = result;
|
||||||
|
|
||||||
|
return DRFLAC_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
|
DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
@ -8742,7 +8725,7 @@ DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocati
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
|
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, (void*)pFile, pAllocationCallbacks);
|
||||||
if (pFlac == NULL) {
|
if (pFlac == NULL) {
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -8761,7 +8744,7 @@ DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_all
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
|
pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, (void*)pFile, pAllocationCallbacks);
|
||||||
if (pFlac == NULL) {
|
if (pFlac == NULL) {
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -8780,7 +8763,7 @@ DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
|
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
|
||||||
if (pFlac == NULL) {
|
if (pFlac == NULL) {
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
return pFlac;
|
return pFlac;
|
||||||
@ -8799,7 +8782,7 @@ DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, dr
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
|
pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
|
||||||
if (pFlac == NULL) {
|
if (pFlac == NULL) {
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
return pFlac;
|
return pFlac;
|
||||||
@ -8834,28 +8817,45 @@ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t by
|
|||||||
static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
|
static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
|
||||||
{
|
{
|
||||||
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
|
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
|
||||||
|
drflac_int64 newCursor;
|
||||||
|
|
||||||
DRFLAC_ASSERT(memoryStream != NULL);
|
DRFLAC_ASSERT(memoryStream != NULL);
|
||||||
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
|
|
||||||
|
|
||||||
if (offset > (drflac_int64)memoryStream->dataSize) {
|
newCursor = memoryStream->currentReadPos;
|
||||||
|
|
||||||
|
if (origin == DRFLAC_SEEK_SET) {
|
||||||
|
newCursor = 0;
|
||||||
|
} else if (origin == DRFLAC_SEEK_CUR) {
|
||||||
|
newCursor = (drflac_int64)memoryStream->currentReadPos;
|
||||||
|
} else if (origin == DRFLAC_SEEK_END) {
|
||||||
|
newCursor = (drflac_int64)memoryStream->dataSize;
|
||||||
|
} else {
|
||||||
|
DRFLAC_ASSERT(!"Invalid seek origin");
|
||||||
return DRFLAC_FALSE;
|
return DRFLAC_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (origin == drflac_seek_origin_current) {
|
newCursor += offset;
|
||||||
if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) {
|
|
||||||
memoryStream->currentReadPos += offset;
|
if (newCursor < 0) {
|
||||||
} else {
|
return DRFLAC_FALSE; /* Trying to seek prior to the start of the buffer. */
|
||||||
return DRFLAC_FALSE; /* Trying to seek too far forward. */
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((drflac_uint32)offset <= memoryStream->dataSize) {
|
|
||||||
memoryStream->currentReadPos = offset;
|
|
||||||
} else {
|
|
||||||
return DRFLAC_FALSE; /* Trying to seek too far forward. */
|
|
||||||
}
|
}
|
||||||
|
if ((size_t)newCursor > memoryStream->dataSize) {
|
||||||
|
return DRFLAC_FALSE; /* Trying to seek beyond the end of the buffer. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memoryStream->currentReadPos = (size_t)newCursor;
|
||||||
|
|
||||||
|
return DRFLAC_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static drflac_bool32 drflac__on_tell_memory(void* pUserData, drflac_int64* pCursor)
|
||||||
|
{
|
||||||
|
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
|
||||||
|
|
||||||
|
DRFLAC_ASSERT(memoryStream != NULL);
|
||||||
|
DRFLAC_ASSERT(pCursor != NULL);
|
||||||
|
|
||||||
|
*pCursor = (drflac_int64)memoryStream->currentReadPos;
|
||||||
return DRFLAC_TRUE;
|
return DRFLAC_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8867,7 +8867,7 @@ DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const
|
|||||||
memoryStream.data = (const drflac_uint8*)pData;
|
memoryStream.data = (const drflac_uint8*)pData;
|
||||||
memoryStream.dataSize = dataSize;
|
memoryStream.dataSize = dataSize;
|
||||||
memoryStream.currentReadPos = 0;
|
memoryStream.currentReadPos = 0;
|
||||||
pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks);
|
pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, drflac__on_tell_memory, &memoryStream, pAllocationCallbacks);
|
||||||
if (pFlac == NULL) {
|
if (pFlac == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -8898,7 +8898,7 @@ DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t da
|
|||||||
memoryStream.data = (const drflac_uint8*)pData;
|
memoryStream.data = (const drflac_uint8*)pData;
|
||||||
memoryStream.dataSize = dataSize;
|
memoryStream.dataSize = dataSize;
|
||||||
memoryStream.currentReadPos = 0;
|
memoryStream.currentReadPos = 0;
|
||||||
pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
|
pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, drflac__on_tell_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
|
||||||
if (pFlac == NULL) {
|
if (pFlac == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -8923,22 +8923,22 @@ DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t da
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
|
return drflac_open_with_metadata_private(onRead, onSeek, onTell, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
|
||||||
}
|
}
|
||||||
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks);
|
return drflac_open_with_metadata_private(onRead, onSeek, onTell, NULL, container, pUserData, pUserData, pAllocationCallbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
|
return drflac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
|
||||||
}
|
}
|
||||||
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
|
return drflac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
DRFLAC_API void drflac_close(drflac* pFlac)
|
DRFLAC_API void drflac_close(drflac* pFlac)
|
||||||
@ -11770,7 +11770,7 @@ DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32)
|
|||||||
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16)
|
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16)
|
||||||
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float)
|
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float)
|
||||||
|
|
||||||
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
drflac* pFlac;
|
drflac* pFlac;
|
||||||
|
|
||||||
@ -11784,7 +11784,7 @@ DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc on
|
|||||||
*totalPCMFrameCountOut = 0;
|
*totalPCMFrameCountOut = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
|
pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks);
|
||||||
if (pFlac == NULL) {
|
if (pFlac == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -11792,7 +11792,7 @@ DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc on
|
|||||||
return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
|
return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
drflac* pFlac;
|
drflac* pFlac;
|
||||||
|
|
||||||
@ -11806,7 +11806,7 @@ DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc on
|
|||||||
*totalPCMFrameCountOut = 0;
|
*totalPCMFrameCountOut = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
|
pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks);
|
||||||
if (pFlac == NULL) {
|
if (pFlac == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -11814,7 +11814,7 @@ DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc on
|
|||||||
return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
|
return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
drflac* pFlac;
|
drflac* pFlac;
|
||||||
|
|
||||||
@ -11828,7 +11828,7 @@ DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, d
|
|||||||
*totalPCMFrameCountOut = 0;
|
*totalPCMFrameCountOut = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
|
pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks);
|
||||||
if (pFlac == NULL) {
|
if (pFlac == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -12077,6 +12077,26 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat
|
|||||||
/*
|
/*
|
||||||
REVISION HISTORY
|
REVISION HISTORY
|
||||||
================
|
================
|
||||||
|
v0.13.0 - TBD
|
||||||
|
- API CHANGE: Seek origin enums have been renamed to match the naming convention used by other dr_libs libraries:
|
||||||
|
- drflac_seek_origin_start -> DRFLAC_SEEK_SET
|
||||||
|
- drflac_seek_origin_current -> DRFLAC_SEEK_CUR
|
||||||
|
- DRFLAC_SEEK_END (new)
|
||||||
|
- API CHANGE: A new seek origin has been added to allow seeking from the end of the file. If you implement your own `onSeek` callback, you should now detect and handle `DRFLAC_SEEK_END`. If seeking to the end is not supported, return `DRFLAC_FALSE`. If you only use `*_open_file()` or `*_open_memory()`, you need not change anything.
|
||||||
|
- API CHANGE: An `onTell` callback has been added to the following functions:
|
||||||
|
- drflac_open()
|
||||||
|
- drflac_open_relaxed()
|
||||||
|
- drflac_open_with_metadata()
|
||||||
|
- drflac_open_with_metadata_relaxed()
|
||||||
|
- drflac_open_and_read_pcm_frames_s32()
|
||||||
|
- drflac_open_and_read_pcm_frames_s16()
|
||||||
|
- drflac_open_and_read_pcm_frames_f32()
|
||||||
|
- Fix compilation for AIX OS.
|
||||||
|
|
||||||
|
v0.12.43 - 2024-12-17
|
||||||
|
- Fix a possible buffer overflow during decoding.
|
||||||
|
- Improve detection of ARM64EC
|
||||||
|
|
||||||
v0.12.42 - 2023-11-02
|
v0.12.42 - 2023-11-02
|
||||||
- Fix build for ARMv6-M.
|
- Fix build for ARMv6-M.
|
||||||
- Fix a compilation warning with GCC.
|
- Fix a compilation warning with GCC.
|
||||||
|
857
libs/raylib/src/external/dr_mp3.h
vendored
857
libs/raylib/src/external/dr_mp3.h
vendored
File diff suppressed because it is too large
Load Diff
430
libs/raylib/src/external/dr_wav.h
vendored
430
libs/raylib/src/external/dr_wav.h
vendored
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
|
WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||||
dr_wav - v0.13.16 - 2024-02-27
|
dr_wav - v0.14.0 - TBD
|
||||||
|
|
||||||
David Reid - mackron@gmail.com
|
David Reid - mackron@gmail.com
|
||||||
|
|
||||||
@ -146,8 +146,8 @@ extern "C" {
|
|||||||
#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x)
|
#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x)
|
||||||
|
|
||||||
#define DRWAV_VERSION_MAJOR 0
|
#define DRWAV_VERSION_MAJOR 0
|
||||||
#define DRWAV_VERSION_MINOR 13
|
#define DRWAV_VERSION_MINOR 14
|
||||||
#define DRWAV_VERSION_REVISION 16
|
#define DRWAV_VERSION_REVISION 0
|
||||||
#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
|
#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
|
||||||
|
|
||||||
#include <stddef.h> /* For size_t. */
|
#include <stddef.h> /* For size_t. */
|
||||||
@ -176,7 +176,7 @@ typedef unsigned int drwav_uint32;
|
|||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
|
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) || defined(__powerpc64__)
|
||||||
typedef drwav_uint64 drwav_uintptr;
|
typedef drwav_uint64 drwav_uintptr;
|
||||||
#else
|
#else
|
||||||
typedef drwav_uint32 drwav_uintptr;
|
typedef drwav_uint32 drwav_uintptr;
|
||||||
@ -305,8 +305,9 @@ typedef struct
|
|||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
drwav_seek_origin_start,
|
DRWAV_SEEK_SET,
|
||||||
drwav_seek_origin_current
|
DRWAV_SEEK_CUR,
|
||||||
|
DRWAV_SEEK_END
|
||||||
} drwav_seek_origin;
|
} drwav_seek_origin;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -415,11 +416,21 @@ origin [in] The origin of the seek - the current position or the start of the
|
|||||||
|
|
||||||
Returns whether or not the seek was successful.
|
Returns whether or not the seek was successful.
|
||||||
|
|
||||||
Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either drwav_seek_origin_start or
|
Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either DRWAV_SEEK_SET or
|
||||||
drwav_seek_origin_current.
|
DRWAV_SEEK_CUR.
|
||||||
*/
|
*/
|
||||||
typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
|
typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Callback for when the current position in the stream needs to be retrieved.
|
||||||
|
|
||||||
|
pUserData [in] The user data that was passed to drwav_init() and family.
|
||||||
|
pCursor [out] A pointer to a variable to receive the current position in the stream.
|
||||||
|
|
||||||
|
Returns whether or not the operation was successful.
|
||||||
|
*/
|
||||||
|
typedef drwav_bool32 (* drwav_tell_proc)(void* pUserData, drwav_int64* pCursor);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback for when drwav_init_ex() finds a chunk.
|
Callback for when drwav_init_ex() finds a chunk.
|
||||||
|
|
||||||
@ -514,6 +525,11 @@ typedef enum
|
|||||||
drwav_metadata_type_list_info_genre = 1 << 15,
|
drwav_metadata_type_list_info_genre = 1 << 15,
|
||||||
drwav_metadata_type_list_info_album = 1 << 16,
|
drwav_metadata_type_list_info_album = 1 << 16,
|
||||||
drwav_metadata_type_list_info_tracknumber = 1 << 17,
|
drwav_metadata_type_list_info_tracknumber = 1 << 17,
|
||||||
|
drwav_metadata_type_list_info_location = 1 << 18,
|
||||||
|
drwav_metadata_type_list_info_organization = 1 << 19,
|
||||||
|
drwav_metadata_type_list_info_keywords = 1 << 20,
|
||||||
|
drwav_metadata_type_list_info_medium = 1 << 21,
|
||||||
|
drwav_metadata_type_list_info_description = 1 << 22,
|
||||||
|
|
||||||
/* Other type constants for convenience. */
|
/* Other type constants for convenience. */
|
||||||
drwav_metadata_type_list_all_info_strings = drwav_metadata_type_list_info_software
|
drwav_metadata_type_list_all_info_strings = drwav_metadata_type_list_info_software
|
||||||
@ -524,7 +540,12 @@ typedef enum
|
|||||||
| drwav_metadata_type_list_info_date
|
| drwav_metadata_type_list_info_date
|
||||||
| drwav_metadata_type_list_info_genre
|
| drwav_metadata_type_list_info_genre
|
||||||
| drwav_metadata_type_list_info_album
|
| drwav_metadata_type_list_info_album
|
||||||
| drwav_metadata_type_list_info_tracknumber,
|
| drwav_metadata_type_list_info_tracknumber
|
||||||
|
| drwav_metadata_type_list_info_location
|
||||||
|
| drwav_metadata_type_list_info_organization
|
||||||
|
| drwav_metadata_type_list_info_keywords
|
||||||
|
| drwav_metadata_type_list_info_medium
|
||||||
|
| drwav_metadata_type_list_info_description,
|
||||||
|
|
||||||
drwav_metadata_type_list_all_adtl = drwav_metadata_type_list_label
|
drwav_metadata_type_list_all_adtl = drwav_metadata_type_list_label
|
||||||
| drwav_metadata_type_list_note
|
| drwav_metadata_type_list_note
|
||||||
@ -555,11 +576,11 @@ typedef struct
|
|||||||
/* See drwav_smpl_loop_type. */
|
/* See drwav_smpl_loop_type. */
|
||||||
drwav_uint32 type;
|
drwav_uint32 type;
|
||||||
|
|
||||||
/* The byte offset of the first sample to be played in the loop. */
|
/* The offset of the first sample to be played in the loop. */
|
||||||
drwav_uint32 firstSampleByteOffset;
|
drwav_uint32 firstSampleOffset;
|
||||||
|
|
||||||
/* The byte offset into the audio data of the last sample to be played in the loop. */
|
/* The offset into the audio data of the last sample to be played in the loop. */
|
||||||
drwav_uint32 lastSampleByteOffset;
|
drwav_uint32 lastSampleOffset;
|
||||||
|
|
||||||
/* A value to represent that playback should occur at a point between samples. This value ranges from 0 to UINT32_MAX. Where a value of 0 means no fraction, and a value of (UINT32_MAX / 2) would mean half a sample. */
|
/* A value to represent that playback should occur at a point between samples. This value ranges from 0 to UINT32_MAX. Where a value of 0 means no fraction, and a value of (UINT32_MAX / 2) would mean half a sample. */
|
||||||
drwav_uint32 sampleFraction;
|
drwav_uint32 sampleFraction;
|
||||||
@ -637,8 +658,8 @@ typedef struct
|
|||||||
/* Set to 0 for uncompressed formats. Else the last byte in compressed wave data where decompression can begin to find the value of the corresponding sample value. */
|
/* Set to 0 for uncompressed formats. Else the last byte in compressed wave data where decompression can begin to find the value of the corresponding sample value. */
|
||||||
drwav_uint32 blockStart;
|
drwav_uint32 blockStart;
|
||||||
|
|
||||||
/* For uncompressed formats this is the byte offset of the cue point into the audio data. For compressed formats this is relative to the block specified with blockStart. */
|
/* For uncompressed formats this is the offset of the cue point into the audio data. For compressed formats this is relative to the block specified with blockStart. */
|
||||||
drwav_uint32 sampleByteOffset;
|
drwav_uint32 sampleOffset;
|
||||||
} drwav_cue_point;
|
} drwav_cue_point;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -846,6 +867,9 @@ typedef struct
|
|||||||
/* A pointer to the function to call when the wav file needs to be seeked. */
|
/* A pointer to the function to call when the wav file needs to be seeked. */
|
||||||
drwav_seek_proc onSeek;
|
drwav_seek_proc onSeek;
|
||||||
|
|
||||||
|
/* A pointer to the function to call when the position of the stream needs to be retrieved. */
|
||||||
|
drwav_tell_proc onTell;
|
||||||
|
|
||||||
/* The user data to pass to callbacks. */
|
/* The user data to pass to callbacks. */
|
||||||
void* pUserData;
|
void* pUserData;
|
||||||
|
|
||||||
@ -968,9 +992,9 @@ after the function returns.
|
|||||||
|
|
||||||
See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
|
See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
|
||||||
*/
|
*/
|
||||||
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
|
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||||
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
|
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, drwav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||||
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
|
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Initializes a pre-allocated drwav object for writing.
|
Initializes a pre-allocated drwav object for writing.
|
||||||
@ -1273,9 +1297,9 @@ Opens and reads an entire wav file in a single operation.
|
|||||||
|
|
||||||
The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
|
The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
|
||||||
*/
|
*/
|
||||||
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||||
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||||
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
|
||||||
#ifndef DR_WAV_NO_STDIO
|
#ifndef DR_WAV_NO_STDIO
|
||||||
/*
|
/*
|
||||||
Opens and decodes an entire wav file in a single operation.
|
Opens and decodes an entire wav file in a single operation.
|
||||||
@ -1384,7 +1408,7 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
|
|||||||
#define DRWAV_MAX_SIMD_VECTOR_SIZE 32
|
#define DRWAV_MAX_SIMD_VECTOR_SIZE 32
|
||||||
|
|
||||||
/* Architecture Detection */
|
/* Architecture Detection */
|
||||||
#if defined(__x86_64__) || defined(_M_X64)
|
#if defined(__x86_64__) || (defined(_M_X64) && !defined(_M_ARM64EC))
|
||||||
#define DRWAV_X64
|
#define DRWAV_X64
|
||||||
#elif defined(__i386) || defined(_M_IX86)
|
#elif defined(__i386) || defined(_M_IX86)
|
||||||
#define DRWAV_X86
|
#define DRWAV_X86
|
||||||
@ -1962,12 +1986,12 @@ DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uin
|
|||||||
drwav_uint64 bytesRemainingToSeek = offset;
|
drwav_uint64 bytesRemainingToSeek = offset;
|
||||||
while (bytesRemainingToSeek > 0) {
|
while (bytesRemainingToSeek > 0) {
|
||||||
if (bytesRemainingToSeek > 0x7FFFFFFF) {
|
if (bytesRemainingToSeek > 0x7FFFFFFF) {
|
||||||
if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
|
if (!onSeek(pUserData, 0x7FFFFFFF, DRWAV_SEEK_CUR)) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
bytesRemainingToSeek -= 0x7FFFFFFF;
|
bytesRemainingToSeek -= 0x7FFFFFFF;
|
||||||
} else {
|
} else {
|
||||||
if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
|
if (!onSeek(pUserData, (int)bytesRemainingToSeek, DRWAV_SEEK_CUR)) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
bytesRemainingToSeek = 0;
|
bytesRemainingToSeek = 0;
|
||||||
@ -1980,21 +2004,21 @@ DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uin
|
|||||||
DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
|
DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
|
||||||
{
|
{
|
||||||
if (offset <= 0x7FFFFFFF) {
|
if (offset <= 0x7FFFFFFF) {
|
||||||
return onSeek(pUserData, (int)offset, drwav_seek_origin_start);
|
return onSeek(pUserData, (int)offset, DRWAV_SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Larger than 32-bit seek. */
|
/* Larger than 32-bit seek. */
|
||||||
if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) {
|
if (!onSeek(pUserData, 0x7FFFFFFF, DRWAV_SEEK_SET)) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
offset -= 0x7FFFFFFF;
|
offset -= 0x7FFFFFFF;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (offset <= 0x7FFFFFFF) {
|
if (offset <= 0x7FFFFFFF) {
|
||||||
return onSeek(pUserData, (int)offset, drwav_seek_origin_current);
|
return onSeek(pUserData, (int)offset, DRWAV_SEEK_CUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
|
if (!onSeek(pUserData, 0x7FFFFFFF, DRWAV_SEEK_CUR)) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
offset -= 0x7FFFFFFF;
|
offset -= 0x7FFFFFFF;
|
||||||
@ -2028,7 +2052,7 @@ DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserDat
|
|||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (origin == drwav_seek_origin_start) {
|
if (origin == DRWAV_SEEK_SET) {
|
||||||
*pCursor = offset;
|
*pCursor = offset;
|
||||||
} else {
|
} else {
|
||||||
*pCursor += offset;
|
*pCursor += offset;
|
||||||
@ -2191,8 +2215,8 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_pars
|
|||||||
if (bytesJustRead == sizeof(smplLoopData)) {
|
if (bytesJustRead == sizeof(smplLoopData)) {
|
||||||
pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0);
|
pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0);
|
||||||
pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4);
|
pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4);
|
||||||
pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8);
|
pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleOffset = drwav_bytes_to_u32(smplLoopData + 8);
|
||||||
pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12);
|
pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleOffset = drwav_bytes_to_u32(smplLoopData + 12);
|
||||||
pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16);
|
pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16);
|
||||||
pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20);
|
pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20);
|
||||||
} else {
|
} else {
|
||||||
@ -2254,7 +2278,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parse
|
|||||||
pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11];
|
pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11];
|
||||||
pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12);
|
pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12);
|
||||||
pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16);
|
pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16);
|
||||||
pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20);
|
pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset = drwav_bytes_to_u32(cuePointData + 20);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2698,7 +2722,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
|||||||
drwav_uint8 buffer[4];
|
drwav_uint8 buffer[4];
|
||||||
size_t bytesJustRead;
|
size_t bytesJustRead;
|
||||||
|
|
||||||
if (!pParser->onSeek(pParser->pReadSeekUserData, 28, drwav_seek_origin_current)) {
|
if (!pParser->onSeek(pParser->pReadSeekUserData, 28, DRWAV_SEEK_CUR)) {
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
bytesRead += 28;
|
bytesRead += 28;
|
||||||
@ -2811,7 +2835,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
|||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
allocSizeNeeded += drwav__strlen(buffer) + 1;
|
allocSizeNeeded += drwav__strlen(buffer) + 1;
|
||||||
allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES; /* Coding history. */
|
allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES + 1; /* Coding history. */
|
||||||
|
|
||||||
drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1);
|
drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1);
|
||||||
|
|
||||||
@ -2916,6 +2940,16 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
|||||||
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_album);
|
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_album);
|
||||||
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) {
|
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) {
|
||||||
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_tracknumber);
|
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_tracknumber);
|
||||||
|
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_location, "IARL")) {
|
||||||
|
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_location);
|
||||||
|
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_organization, "ICMS")) {
|
||||||
|
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_organization);
|
||||||
|
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_keywords, "IKEY")) {
|
||||||
|
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_keywords);
|
||||||
|
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_medium, "IMED")) {
|
||||||
|
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_medium);
|
||||||
|
} else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_description, "ISBJ")) {
|
||||||
|
subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_description);
|
||||||
} else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) {
|
} else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) {
|
||||||
subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType);
|
subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType);
|
||||||
}
|
}
|
||||||
@ -2926,14 +2960,14 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
|||||||
if (subchunkBytesRead < subchunkDataSize) {
|
if (subchunkBytesRead < subchunkDataSize) {
|
||||||
drwav_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead;
|
drwav_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead;
|
||||||
|
|
||||||
if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, drwav_seek_origin_current)) {
|
if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, DRWAV_SEEK_CUR)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bytesRead += bytesToSeek;
|
bytesRead += bytesToSeek;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((subchunkDataSize % 2) == 1) {
|
if ((subchunkDataSize % 2) == 1) {
|
||||||
if (!pParser->onSeek(pParser->pReadSeekUserData, 1, drwav_seek_origin_current)) {
|
if (!pParser->onSeek(pParser->pReadSeekUserData, 1, DRWAV_SEEK_CUR)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bytesRead += 1;
|
bytesRead += 1;
|
||||||
@ -2985,16 +3019,17 @@ DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
|
DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pReadSeekTellUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
if (pWav == NULL || onRead == NULL || onSeek == NULL) {
|
if (pWav == NULL || onRead == NULL || onSeek == NULL) { /* <-- onTell is optional. */
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
|
DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
|
||||||
pWav->onRead = onRead;
|
pWav->onRead = onRead;
|
||||||
pWav->onSeek = onSeek;
|
pWav->onSeek = onSeek;
|
||||||
pWav->pUserData = pReadSeekUserData;
|
pWav->onTell = onTell;
|
||||||
|
pWav->pUserData = pReadSeekTellUserData;
|
||||||
pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
|
pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
|
||||||
|
|
||||||
if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
|
if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
|
||||||
@ -3311,7 +3346,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||||||
fmt.channelMask = drwav_bytes_to_u32_ex(fmtext + 2, pWav->container);
|
fmt.channelMask = drwav_bytes_to_u32_ex(fmtext + 2, pWav->container);
|
||||||
drwav_bytes_to_guid(fmtext + 6, fmt.subFormat);
|
drwav_bytes_to_guid(fmtext + 6, fmt.subFormat);
|
||||||
} else {
|
} else {
|
||||||
if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, drwav_seek_origin_current) == DRWAV_FALSE) {
|
if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, DRWAV_SEEK_CUR) == DRWAV_FALSE) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3321,7 +3356,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */
|
/* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */
|
||||||
if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current) == DRWAV_FALSE) {
|
if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), DRWAV_SEEK_CUR) == DRWAV_FALSE) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
cursor += (header.sizeInBytes - bytesReadSoFar);
|
cursor += (header.sizeInBytes - bytesReadSoFar);
|
||||||
@ -3471,6 +3506,9 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||||||
I haven't been able to figure out how to get correct decoding for IMA ADPCM. Until this is figured out
|
I haven't been able to figure out how to get correct decoding for IMA ADPCM. Until this is figured out
|
||||||
we'll need to abort when we encounter such an encoding. Advice welcome!
|
we'll need to abort when we encounter such an encoding. Advice welcome!
|
||||||
*/
|
*/
|
||||||
|
(void)compressionFormat;
|
||||||
|
(void)sampleSizeInBits;
|
||||||
|
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
} else {
|
} else {
|
||||||
return DRWAV_FALSE; /* Unknown or unsupported compression format. Need to abort. */
|
return DRWAV_FALSE; /* Unknown or unsupported compression format. Need to abort. */
|
||||||
@ -3533,20 +3571,46 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need to seek forward by the offset. */
|
/* The position of the audio data starts at an offset. */
|
||||||
offset = drwav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container);
|
offset = drwav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container);
|
||||||
|
pWav->dataChunkDataPos = cursor + offset;
|
||||||
|
|
||||||
|
/* The data chunk size needs to be reduced by the offset or else seeking will break. */
|
||||||
|
dataChunkSize = chunkSize;
|
||||||
|
if (dataChunkSize > offset) {
|
||||||
|
dataChunkSize -= offset;
|
||||||
|
} else {
|
||||||
|
dataChunkSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sequential) {
|
||||||
|
if (foundChunk_fmt) { /* <-- Name is misleading, but will be set to true if the COMM chunk has been parsed. */
|
||||||
|
/*
|
||||||
|
Getting here means we're opening in sequential mode and we've found the SSND (data) and COMM (fmt) chunks. We need
|
||||||
|
to get out of the loop here or else we'll end up going past the data chunk and will have no way of getting back to
|
||||||
|
it since we're not allowed to seek backwards.
|
||||||
|
|
||||||
|
One subtle detail here is that there is an offset with the SSND chunk. We need to make sure we seek past this offset
|
||||||
|
so we're left sitting on the first byte of actual audio data.
|
||||||
|
*/
|
||||||
if (drwav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == DRWAV_FALSE) {
|
if (drwav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == DRWAV_FALSE) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
cursor += offset;
|
cursor += offset;
|
||||||
|
|
||||||
pWav->dataChunkDataPos = cursor;
|
break;
|
||||||
dataChunkSize = chunkSize;
|
|
||||||
|
|
||||||
/* If we're running in sequential mode, or we're not reading metadata, we have enough now that we can get out of the loop. */
|
|
||||||
if (sequential || !isProcessingMetadata) {
|
|
||||||
break; /* No need to keep reading beyond the data chunk. */
|
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
|
Getting here means the COMM chunk was not found. In sequential mode, if we haven't yet found the COMM chunk
|
||||||
|
we'll need to abort because we can't be doing a backwards seek back to the SSND chunk in order to read the
|
||||||
|
data. For this reason, this configuration of AIFF files are not supported with sequential mode.
|
||||||
|
*/
|
||||||
|
return DRWAV_FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chunkSize += header.paddingSize; /* <-- Make sure we seek past the padding. */
|
||||||
|
chunkSize -= sizeof(offsetAndBlockSizeData); /* <-- This was read earlier. */
|
||||||
|
|
||||||
if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) {
|
if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3557,7 +3621,6 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Getting here means it's not a chunk that we care about internally, but might need to be handled as metadata by the caller. */
|
/* Getting here means it's not a chunk that we care about internally, but might need to be handled as metadata by the caller. */
|
||||||
if (isProcessingMetadata) {
|
if (isProcessingMetadata) {
|
||||||
drwav__metadata_process_chunk(&metadataParser, &header, drwav_metadata_type_all_including_unknown);
|
drwav__metadata_process_chunk(&metadataParser, &header, drwav_metadata_type_all_including_unknown);
|
||||||
@ -3647,8 +3710,26 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||||||
pWav->metadataCount = metadataParser.metadataCount;
|
pWav->metadataCount = metadataParser.metadataCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/* At this point we should be sitting on the first byte of the raw audio data. */
|
It's possible for the size reported in the data chunk to be greater than that of the file. We
|
||||||
|
need to do a validation check here to make sure we don't exceed the file size. To skip this
|
||||||
|
check, set the onTell callback to NULL.
|
||||||
|
*/
|
||||||
|
if (pWav->onTell != NULL && pWav->onSeek != NULL) {
|
||||||
|
if (pWav->onSeek(pWav->pUserData, 0, DRWAV_SEEK_END) == DRWAV_TRUE) {
|
||||||
|
drwav_int64 fileSize;
|
||||||
|
if (pWav->onTell(pWav->pUserData, &fileSize)) {
|
||||||
|
if (dataChunkSize + pWav->dataChunkDataPos > (drwav_uint64)fileSize) {
|
||||||
|
dataChunkSize = (drwav_uint64)fileSize - pWav->dataChunkDataPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
Failed to seek to the end of the file. It might not be supported by the backend so in
|
||||||
|
this case we cannot perform the validation check.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
I've seen a WAV file in the wild where a RIFF-ecapsulated file has the size of it's "RIFF" and
|
I've seen a WAV file in the wild where a RIFF-ecapsulated file has the size of it's "RIFF" and
|
||||||
@ -3670,6 +3751,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* At this point we want to be sitting on the first byte of the raw audio data. */
|
||||||
if (drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData) == DRWAV_FALSE) {
|
if (drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData) == DRWAV_FALSE) {
|
||||||
drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
|
drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
@ -3680,8 +3762,26 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||||||
pWav->sampleRate = fmt.sampleRate;
|
pWav->sampleRate = fmt.sampleRate;
|
||||||
pWav->channels = fmt.channels;
|
pWav->channels = fmt.channels;
|
||||||
pWav->bitsPerSample = fmt.bitsPerSample;
|
pWav->bitsPerSample = fmt.bitsPerSample;
|
||||||
pWav->bytesRemaining = dataChunkSize;
|
|
||||||
pWav->translatedFormatTag = translatedFormatTag;
|
pWav->translatedFormatTag = translatedFormatTag;
|
||||||
|
|
||||||
|
/*
|
||||||
|
I've had a report where files would start glitching after seeking. The reason for this is the data
|
||||||
|
chunk is not a clean multiple of the PCM frame size in bytes. Where this becomes a problem is when
|
||||||
|
seeking, because the number of bytes remaining in the data chunk is used to calculate the current
|
||||||
|
byte position. If this byte position is not aligned to the number of bytes in a PCM frame, it will
|
||||||
|
result in the seek not being cleanly positioned at the start of the PCM frame thereby resulting in
|
||||||
|
all decoded frames after that being corrupted.
|
||||||
|
|
||||||
|
To address this, we need to round the data chunk size down to the nearest multiple of the frame size.
|
||||||
|
*/
|
||||||
|
if (!drwav__is_compressed_format_tag(translatedFormatTag)) {
|
||||||
|
drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
|
||||||
|
if (bytesPerFrame > 0) {
|
||||||
|
dataChunkSize -= (dataChunkSize % bytesPerFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pWav->bytesRemaining = dataChunkSize;
|
||||||
pWav->dataChunkDataSize = dataChunkSize;
|
pWav->dataChunkDataSize = dataChunkSize;
|
||||||
|
|
||||||
if (sampleCountFromFactChunk != 0) {
|
if (sampleCountFromFactChunk != 0) {
|
||||||
@ -3764,23 +3864,23 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||||||
return DRWAV_TRUE;
|
return DRWAV_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
|
DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks);
|
return drwav_init_ex(pWav, onRead, onSeek, onTell, NULL, pUserData, NULL, 0, pAllocationCallbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
|
DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, drwav_chunk_proc onChunk, void* pReadSeekTellUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) {
|
if (!drwav_preinit(pWav, onRead, onSeek, onTell, pReadSeekTellUserData, pAllocationCallbacks)) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
|
return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
|
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
if (!drwav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
|
if (!drwav_preinit(pWav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3995,8 +4095,8 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata*
|
|||||||
for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) {
|
for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) {
|
||||||
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId);
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId);
|
||||||
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type);
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type);
|
||||||
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleByteOffset);
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleOffset);
|
||||||
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleByteOffset);
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleOffset);
|
||||||
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction);
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction);
|
||||||
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount);
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount);
|
||||||
}
|
}
|
||||||
@ -4036,7 +4136,7 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata*
|
|||||||
bytesWritten += drwav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4);
|
bytesWritten += drwav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4);
|
||||||
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart);
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart);
|
||||||
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart);
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart);
|
||||||
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset);
|
bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleOffset);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -4151,6 +4251,11 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata*
|
|||||||
case drwav_metadata_type_list_info_genre: pID = "IGNR"; break;
|
case drwav_metadata_type_list_info_genre: pID = "IGNR"; break;
|
||||||
case drwav_metadata_type_list_info_album: pID = "IPRD"; break;
|
case drwav_metadata_type_list_info_album: pID = "IPRD"; break;
|
||||||
case drwav_metadata_type_list_info_tracknumber: pID = "ITRK"; break;
|
case drwav_metadata_type_list_info_tracknumber: pID = "ITRK"; break;
|
||||||
|
case drwav_metadata_type_list_info_location: pID = "IARL"; break;
|
||||||
|
case drwav_metadata_type_list_info_organization: pID = "ICMS"; break;
|
||||||
|
case drwav_metadata_type_list_info_keywords: pID = "IKEY"; break;
|
||||||
|
case drwav_metadata_type_list_info_medium: pID = "IMED"; break;
|
||||||
|
case drwav_metadata_type_list_info_description: pID = "ISBJ"; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4434,7 +4539,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_d
|
|||||||
|
|
||||||
/* "RIFF" chunk. */
|
/* "RIFF" chunk. */
|
||||||
if (pFormat->container == drwav_container_riff) {
|
if (pFormat->container == drwav_container_riff) {
|
||||||
drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize; /* +28 = "WAVE" + [sizeof "fmt " chunk] */
|
drwav_uint32 chunkSizeRIFF = 36 + (drwav_uint32)initialDataChunkSize; /* +36 = "WAVE" + [sizeof "fmt " chunk] + [data chunk header] */
|
||||||
runningPos += drwav__write(pWav, "RIFF", 4);
|
runningPos += drwav__write(pWav, "RIFF", 4);
|
||||||
runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
|
runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
|
||||||
runningPos += drwav__write(pWav, "WAVE", 4);
|
runningPos += drwav__write(pWav, "WAVE", 4);
|
||||||
@ -4704,7 +4809,7 @@ DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e)
|
|||||||
#ifdef ENOSYS
|
#ifdef ENOSYS
|
||||||
case ENOSYS: return DRWAV_NOT_IMPLEMENTED;
|
case ENOSYS: return DRWAV_NOT_IMPLEMENTED;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENOTEMPTY
|
#if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST /* In AIX, ENOTEMPTY and EEXIST use the same value. */
|
||||||
case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY;
|
case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY;
|
||||||
#endif
|
#endif
|
||||||
#ifdef ELOOP
|
#ifdef ELOOP
|
||||||
@ -5161,7 +5266,38 @@ DRWAV_PRIVATE size_t drwav__on_write_stdio(void* pUserData, const void* pData, s
|
|||||||
|
|
||||||
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
|
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
|
||||||
{
|
{
|
||||||
return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
|
int whence = SEEK_SET;
|
||||||
|
if (origin == DRWAV_SEEK_CUR) {
|
||||||
|
whence = SEEK_CUR;
|
||||||
|
} else if (origin == DRWAV_SEEK_END) {
|
||||||
|
whence = SEEK_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fseek((FILE*)pUserData, offset, whence) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRWAV_PRIVATE drwav_bool32 drwav__on_tell_stdio(void* pUserData, drwav_int64* pCursor)
|
||||||
|
{
|
||||||
|
FILE* pFileStdio = (FILE*)pUserData;
|
||||||
|
drwav_int64 result;
|
||||||
|
|
||||||
|
/* These were all validated at a higher level. */
|
||||||
|
DRWAV_ASSERT(pFileStdio != NULL);
|
||||||
|
DRWAV_ASSERT(pCursor != NULL);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||||
|
result = _ftelli64(pFileStdio);
|
||||||
|
#else
|
||||||
|
result = ftell(pFileStdio);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
result = ftell(pFileStdio);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*pCursor = result;
|
||||||
|
|
||||||
|
return DRWAV_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
|
DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||||
@ -5174,7 +5310,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFi
|
|||||||
{
|
{
|
||||||
drwav_bool32 result;
|
drwav_bool32 result;
|
||||||
|
|
||||||
result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
|
result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, drwav__on_tell_stdio, (void*)pFile, pAllocationCallbacks);
|
||||||
if (result != DRWAV_TRUE) {
|
if (result != DRWAV_TRUE) {
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
return result;
|
return result;
|
||||||
@ -5352,29 +5488,34 @@ DRWAV_PRIVATE size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, si
|
|||||||
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
|
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
|
||||||
{
|
{
|
||||||
drwav* pWav = (drwav*)pUserData;
|
drwav* pWav = (drwav*)pUserData;
|
||||||
|
drwav_int64 newCursor;
|
||||||
|
|
||||||
DRWAV_ASSERT(pWav != NULL);
|
DRWAV_ASSERT(pWav != NULL);
|
||||||
|
|
||||||
if (origin == drwav_seek_origin_current) {
|
newCursor = pWav->memoryStream.currentReadPos;
|
||||||
if (offset > 0) {
|
|
||||||
if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) {
|
if (origin == DRWAV_SEEK_SET) {
|
||||||
return DRWAV_FALSE; /* Trying to seek too far forward. */
|
newCursor = 0;
|
||||||
}
|
} else if (origin == DRWAV_SEEK_CUR) {
|
||||||
|
newCursor = (drwav_int64)pWav->memoryStream.currentReadPos;
|
||||||
|
} else if (origin == DRWAV_SEEK_END) {
|
||||||
|
newCursor = (drwav_int64)pWav->memoryStream.dataSize;
|
||||||
} else {
|
} else {
|
||||||
if (pWav->memoryStream.currentReadPos < (size_t)-offset) {
|
DRWAV_ASSERT(!"Invalid seek origin");
|
||||||
return DRWAV_FALSE; /* Trying to seek too far backwards. */
|
return DRWAV_FALSE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This will never underflow thanks to the clamps above. */
|
newCursor += offset;
|
||||||
pWav->memoryStream.currentReadPos += offset;
|
|
||||||
} else {
|
if (newCursor < 0) {
|
||||||
if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) {
|
return DRWAV_FALSE; /* Trying to seek prior to the start of the buffer. */
|
||||||
pWav->memoryStream.currentReadPos = offset;
|
|
||||||
} else {
|
|
||||||
return DRWAV_FALSE; /* Trying to seek too far forward. */
|
|
||||||
}
|
}
|
||||||
|
if ((size_t)newCursor > pWav->memoryStream.dataSize) {
|
||||||
|
return DRWAV_FALSE; /* Trying to seek beyond the end of the buffer. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pWav->memoryStream.currentReadPos = (size_t)newCursor;
|
||||||
|
|
||||||
return DRWAV_TRUE;
|
return DRWAV_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5421,29 +5562,45 @@ DRWAV_PRIVATE size_t drwav__on_write_memory(void* pUserData, const void* pDataIn
|
|||||||
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
|
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
|
||||||
{
|
{
|
||||||
drwav* pWav = (drwav*)pUserData;
|
drwav* pWav = (drwav*)pUserData;
|
||||||
|
drwav_int64 newCursor;
|
||||||
|
|
||||||
DRWAV_ASSERT(pWav != NULL);
|
DRWAV_ASSERT(pWav != NULL);
|
||||||
|
|
||||||
if (origin == drwav_seek_origin_current) {
|
newCursor = pWav->memoryStreamWrite.currentWritePos;
|
||||||
if (offset > 0) {
|
|
||||||
if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) {
|
if (origin == DRWAV_SEEK_SET) {
|
||||||
offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); /* Trying to seek too far forward. */
|
newCursor = 0;
|
||||||
}
|
} else if (origin == DRWAV_SEEK_CUR) {
|
||||||
|
newCursor = (drwav_int64)pWav->memoryStreamWrite.currentWritePos;
|
||||||
|
} else if (origin == DRWAV_SEEK_END) {
|
||||||
|
newCursor = (drwav_int64)pWav->memoryStreamWrite.dataSize;
|
||||||
} else {
|
} else {
|
||||||
if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) {
|
DRWAV_ASSERT(!"Invalid seek origin");
|
||||||
offset = -(int)pWav->memoryStreamWrite.currentWritePos; /* Trying to seek too far backwards. */
|
return DRWAV_INVALID_ARGS;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This will never underflow thanks to the clamps above. */
|
newCursor += offset;
|
||||||
pWav->memoryStreamWrite.currentWritePos += offset;
|
|
||||||
} else {
|
if (newCursor < 0) {
|
||||||
if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) {
|
return DRWAV_FALSE; /* Trying to seek prior to the start of the buffer. */
|
||||||
pWav->memoryStreamWrite.currentWritePos = offset;
|
|
||||||
} else {
|
|
||||||
pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; /* Trying to seek too far forward. */
|
|
||||||
}
|
}
|
||||||
|
if ((size_t)newCursor > pWav->memoryStreamWrite.dataSize) {
|
||||||
|
return DRWAV_FALSE; /* Trying to seek beyond the end of the buffer. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pWav->memoryStreamWrite.currentWritePos = (size_t)newCursor;
|
||||||
|
|
||||||
|
return DRWAV_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRWAV_PRIVATE drwav_bool32 drwav__on_tell_memory(void* pUserData, drwav_int64* pCursor)
|
||||||
|
{
|
||||||
|
drwav* pWav = (drwav*)pUserData;
|
||||||
|
|
||||||
|
DRWAV_ASSERT(pWav != NULL);
|
||||||
|
DRWAV_ASSERT(pCursor != NULL);
|
||||||
|
|
||||||
|
*pCursor = (drwav_int64)pWav->memoryStream.currentReadPos;
|
||||||
return DRWAV_TRUE;
|
return DRWAV_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5458,7 +5615,7 @@ DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_
|
|||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
|
if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, drwav__on_tell_memory, pWav, pAllocationCallbacks)) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5475,7 +5632,7 @@ DRWAV_API drwav_bool32 drwav_init_memory_with_metadata(drwav* pWav, const void*
|
|||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
|
if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, drwav__on_tell_memory, pWav, pAllocationCallbacks)) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5565,25 +5722,25 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav)
|
|||||||
if (pWav->onSeek && !pWav->isSequentialWrite) {
|
if (pWav->onSeek && !pWav->isSequentialWrite) {
|
||||||
if (pWav->container == drwav_container_riff) {
|
if (pWav->container == drwav_container_riff) {
|
||||||
/* The "RIFF" chunk size. */
|
/* The "RIFF" chunk size. */
|
||||||
if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) {
|
if (pWav->onSeek(pWav->pUserData, 4, DRWAV_SEEK_SET)) {
|
||||||
drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
|
drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
|
||||||
drwav__write_u32ne_to_le(pWav, riffChunkSize);
|
drwav__write_u32ne_to_le(pWav, riffChunkSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The "data" chunk size. */
|
/* The "data" chunk size. */
|
||||||
if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, drwav_seek_origin_start)) {
|
if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, DRWAV_SEEK_SET)) {
|
||||||
drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
|
drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
|
||||||
drwav__write_u32ne_to_le(pWav, dataChunkSize);
|
drwav__write_u32ne_to_le(pWav, dataChunkSize);
|
||||||
}
|
}
|
||||||
} else if (pWav->container == drwav_container_w64) {
|
} else if (pWav->container == drwav_container_w64) {
|
||||||
/* The "RIFF" chunk size. */
|
/* The "RIFF" chunk size. */
|
||||||
if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
|
if (pWav->onSeek(pWav->pUserData, 16, DRWAV_SEEK_SET)) {
|
||||||
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
|
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
|
||||||
drwav__write_u64ne_to_le(pWav, riffChunkSize);
|
drwav__write_u64ne_to_le(pWav, riffChunkSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The "data" chunk size. */
|
/* The "data" chunk size. */
|
||||||
if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, drwav_seek_origin_start)) {
|
if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, DRWAV_SEEK_SET)) {
|
||||||
drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
|
drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
|
||||||
drwav__write_u64ne_to_le(pWav, dataChunkSize);
|
drwav__write_u64ne_to_le(pWav, dataChunkSize);
|
||||||
}
|
}
|
||||||
@ -5592,13 +5749,13 @@ DRWAV_API drwav_result drwav_uninit(drwav* pWav)
|
|||||||
int ds64BodyPos = 12 + 8;
|
int ds64BodyPos = 12 + 8;
|
||||||
|
|
||||||
/* The "RIFF" chunk size. */
|
/* The "RIFF" chunk size. */
|
||||||
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) {
|
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, DRWAV_SEEK_SET)) {
|
||||||
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
|
drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
|
||||||
drwav__write_u64ne_to_le(pWav, riffChunkSize);
|
drwav__write_u64ne_to_le(pWav, riffChunkSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The "data" chunk size. */
|
/* The "data" chunk size. */
|
||||||
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) {
|
if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, DRWAV_SEEK_SET)) {
|
||||||
drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
|
drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
|
||||||
drwav__write_u64ne_to_le(pWav, dataChunkSize);
|
drwav__write_u64ne_to_le(pWav, dataChunkSize);
|
||||||
}
|
}
|
||||||
@ -5663,7 +5820,7 @@ DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOu
|
|||||||
bytesToSeek = 0x7FFFFFFF;
|
bytesToSeek = 0x7FFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) {
|
if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, DRWAV_SEEK_CUR) == DRWAV_FALSE) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5810,7 +5967,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav)
|
|||||||
return DRWAV_FALSE; /* No seeking in write mode. */
|
return DRWAV_FALSE; /* No seeking in write mode. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) {
|
if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, DRWAV_SEEK_SET)) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5928,7 +6085,7 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF
|
|||||||
|
|
||||||
while (offset > 0) {
|
while (offset > 0) {
|
||||||
int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
|
int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
|
||||||
if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) {
|
if (!pWav->onSeek(pWav->pUserData, offset32, DRWAV_SEEK_CUR)) {
|
||||||
return DRWAV_FALSE;
|
return DRWAV_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6101,6 +6258,13 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav
|
|||||||
{
|
{
|
||||||
drwav_uint64 totalFramesRead = 0;
|
drwav_uint64 totalFramesRead = 0;
|
||||||
|
|
||||||
|
static drwav_int32 adaptationTable[] = {
|
||||||
|
230, 230, 230, 230, 307, 409, 512, 614,
|
||||||
|
768, 614, 512, 409, 307, 230, 230, 230
|
||||||
|
};
|
||||||
|
static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 };
|
||||||
|
static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 };
|
||||||
|
|
||||||
DRWAV_ASSERT(pWav != NULL);
|
DRWAV_ASSERT(pWav != NULL);
|
||||||
DRWAV_ASSERT(framesToRead > 0);
|
DRWAV_ASSERT(framesToRead > 0);
|
||||||
|
|
||||||
@ -6126,6 +6290,11 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav
|
|||||||
pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0];
|
pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0];
|
||||||
pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1];
|
pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1];
|
||||||
pWav->msadpcm.cachedFrameCount = 2;
|
pWav->msadpcm.cachedFrameCount = 2;
|
||||||
|
|
||||||
|
/* The predictor is used as an index into coeff1Table so we'll need to validate to ensure it never overflows. */
|
||||||
|
if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table)) {
|
||||||
|
return totalFramesRead; /* Invalid file. */
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Stereo. */
|
/* Stereo. */
|
||||||
drwav_uint8 header[14];
|
drwav_uint8 header[14];
|
||||||
@ -6148,6 +6317,11 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav
|
|||||||
pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1];
|
pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1];
|
||||||
pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1];
|
pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1];
|
||||||
pWav->msadpcm.cachedFrameCount = 2;
|
pWav->msadpcm.cachedFrameCount = 2;
|
||||||
|
|
||||||
|
/* The predictor is used as an index into coeff1Table so we'll need to validate to ensure it never overflows. */
|
||||||
|
if (pWav->msadpcm.predictor[0] >= drwav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= drwav_countof(coeff2Table)) {
|
||||||
|
return totalFramesRead; /* Invalid file. */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6181,13 +6355,6 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav
|
|||||||
if (pWav->msadpcm.bytesRemainingInBlock == 0) {
|
if (pWav->msadpcm.bytesRemainingInBlock == 0) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
static drwav_int32 adaptationTable[] = {
|
|
||||||
230, 230, 230, 230, 307, 409, 512, 614,
|
|
||||||
768, 614, 512, 409, 307, 230, 230, 230
|
|
||||||
};
|
|
||||||
static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 };
|
|
||||||
static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 };
|
|
||||||
|
|
||||||
drwav_uint8 nibbles;
|
drwav_uint8 nibbles;
|
||||||
drwav_int32 nibble0;
|
drwav_int32 nibble0;
|
||||||
drwav_int32 nibble1;
|
drwav_int32 nibble1;
|
||||||
@ -6320,7 +6487,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin
|
|||||||
pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
|
pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
|
||||||
|
|
||||||
if (header[2] >= drwav_countof(stepTable)) {
|
if (header[2] >= drwav_countof(stepTable)) {
|
||||||
pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
|
pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, DRWAV_SEEK_CUR);
|
||||||
pWav->ima.bytesRemainingInBlock = 0;
|
pWav->ima.bytesRemainingInBlock = 0;
|
||||||
return totalFramesRead; /* Invalid data. */
|
return totalFramesRead; /* Invalid data. */
|
||||||
}
|
}
|
||||||
@ -6338,7 +6505,7 @@ DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uin
|
|||||||
pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
|
pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
|
||||||
|
|
||||||
if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) {
|
if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) {
|
||||||
pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
|
pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, DRWAV_SEEK_CUR);
|
||||||
pWav->ima.bytesRemainingInBlock = 0;
|
pWav->ima.bytesRemainingInBlock = 0;
|
||||||
return totalFramesRead; /* Invalid data. */
|
return totalFramesRead; /* Invalid data. */
|
||||||
}
|
}
|
||||||
@ -8006,7 +8173,7 @@ DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, uns
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
drwav wav;
|
drwav wav;
|
||||||
|
|
||||||
@ -8020,14 +8187,14 @@ DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead
|
|||||||
*totalFrameCountOut = 0;
|
*totalFrameCountOut = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
|
if (!drwav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
|
return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
drwav wav;
|
drwav wav;
|
||||||
|
|
||||||
@ -8041,14 +8208,14 @@ DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwa
|
|||||||
*totalFrameCountOut = 0;
|
*totalFrameCountOut = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
|
if (!drwav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
|
return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||||
{
|
{
|
||||||
drwav wav;
|
drwav wav;
|
||||||
|
|
||||||
@ -8062,7 +8229,7 @@ DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead
|
|||||||
*totalFrameCountOut = 0;
|
*totalFrameCountOut = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
|
if (!drwav_init(&wav, onRead, onSeek, onTell, pUserData, pAllocationCallbacks)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8350,6 +8517,27 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
|
|||||||
/*
|
/*
|
||||||
REVISION HISTORY
|
REVISION HISTORY
|
||||||
================
|
================
|
||||||
|
v0.14.0 - TBD
|
||||||
|
- API CHANGE: Seek origin enums have been renamed to the following:
|
||||||
|
- drwav_seek_origin_start -> DRWAV_SEEK_SET
|
||||||
|
- drwav_seek_origin_current -> DRWAV_SEEK_CUR
|
||||||
|
- DRWAV_SEEK_END (new)
|
||||||
|
- API CHANGE: A new seek origin has been added to allow seeking from the end of the file. If you implement your own `onSeek` callback, you must now handle `DRWAV_SEEK_END`. If you only use `*_init_file()` or `*_init_memory()`, you need not change anything.
|
||||||
|
- API CHANGE: An `onTell` callback has been added to the following functions:
|
||||||
|
- drwav_init()
|
||||||
|
- drwav_init_ex()
|
||||||
|
- drwav_init_with_metadata()
|
||||||
|
- drwav_open_and_read_pcm_frames_s16()
|
||||||
|
- drwav_open_and_read_pcm_frames_f32()
|
||||||
|
- drwav_open_and_read_pcm_frames_s32()
|
||||||
|
- API CHANGE: The `firstSampleByteOffset`, `lastSampleByteOffset` and `sampleByteOffset` members of `drwav_cue_point` have been renamed to `firstSampleOffset`, `lastSampleOffset` and `sampleOffset`, respectively.
|
||||||
|
- Fix a static analysis warning.
|
||||||
|
- Fix compilation for AIX OS.
|
||||||
|
|
||||||
|
v0.13.17 - 2024-12-17
|
||||||
|
- Fix a possible crash when reading from MS-ADPCM encoded files.
|
||||||
|
- Improve detection of ARM64EC
|
||||||
|
|
||||||
v0.13.16 - 2024-02-27
|
v0.13.16 - 2024-02-27
|
||||||
- Fix a Wdouble-promotion warning.
|
- Fix a Wdouble-promotion warning.
|
||||||
|
|
||||||
|
2107
libs/raylib/src/external/glfw/src/mappings.h
vendored
2107
libs/raylib/src/external/glfw/src/mappings.h
vendored
File diff suppressed because it is too large
Load Diff
1649
libs/raylib/src/external/miniaudio.h
vendored
1649
libs/raylib/src/external/miniaudio.h
vendored
File diff suppressed because it is too large
Load Diff
2
libs/raylib/src/external/rprand.h
vendored
2
libs/raylib/src/external/rprand.h
vendored
@ -90,7 +90,7 @@
|
|||||||
#define RPRAND_FREE(ptr) free(ptr)
|
#define RPRAND_FREE(ptr) free(ptr)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Simple log system to avoid RPNG_LOG() calls if required
|
// Simple log system to avoid log calls if required
|
||||||
// NOTE: Avoiding those calls, also avoids const strings memory usage
|
// NOTE: Avoiding those calls, also avoids const strings memory usage
|
||||||
#define RPRAND_SHOW_LOG_INFO
|
#define RPRAND_SHOW_LOG_INFO
|
||||||
#if defined(RPNG_SHOW_LOG_INFO)
|
#if defined(RPNG_SHOW_LOG_INFO)
|
||||||
|
@ -70,6 +70,16 @@ typedef struct {
|
|||||||
EGLConfig config; // Graphic config
|
EGLConfig config; // Graphic config
|
||||||
} PlatformData;
|
} PlatformData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// Store data for both Hover and Touch events
|
||||||
|
// Used to ignore Hover events which are interpreted as Touch events
|
||||||
|
int32_t pointCount; // Number of touch points active
|
||||||
|
int32_t pointId[MAX_TOUCH_POINTS]; // Point identifiers
|
||||||
|
Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen
|
||||||
|
|
||||||
|
int32_t hoverPoints[MAX_TOUCH_POINTS]; // Hover Points
|
||||||
|
} TouchRaw;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Global Variables Definition
|
// Global Variables Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
@ -246,6 +256,8 @@ static const KeyboardKey mapKeycode[KEYCODE_MAP_SIZE] = {
|
|||||||
KEY_KP_EQUAL // AKEYCODE_NUMPAD_EQUALS
|
KEY_KP_EQUAL // AKEYCODE_NUMPAD_EQUALS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static TouchRaw touchRaw = { 0 };
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Internal Functions Declaration
|
// Module Internal Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
@ -801,6 +813,8 @@ int InitPlatform(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_TOUCH_POINTS; i++) touchRaw.hoverPoints[i] = -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1269,25 +1283,85 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register touch points count
|
// Register touch points count
|
||||||
CORE.Input.Touch.pointCount = AMotionEvent_getPointerCount(event);
|
touchRaw.pointCount = AMotionEvent_getPointerCount(event);
|
||||||
|
|
||||||
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||||
{
|
{
|
||||||
// Register touch points id
|
// Register touch points id
|
||||||
CORE.Input.Touch.pointId[i] = AMotionEvent_getPointerId(event, i);
|
touchRaw.pointId[i] = AMotionEvent_getPointerId(event, i);
|
||||||
|
|
||||||
// Register touch points position
|
// Register touch points position
|
||||||
CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
|
touchRaw.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
|
||||||
|
|
||||||
// Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height
|
// Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height
|
||||||
float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width;
|
float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width;
|
||||||
float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height;
|
float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height;
|
||||||
CORE.Input.Touch.position[i].x = CORE.Input.Touch.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
|
touchRaw.position[i].x = touchRaw.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
|
||||||
CORE.Input.Touch.position[i].y = CORE.Input.Touch.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
|
touchRaw.position[i].y = touchRaw.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t action = AMotionEvent_getAction(event);
|
int32_t action = AMotionEvent_getAction(event);
|
||||||
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
|
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
|
||||||
|
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||||
|
|
||||||
|
if (flags == AMOTION_EVENT_ACTION_HOVER_ENTER)
|
||||||
|
{
|
||||||
|
// The new pointer is hover
|
||||||
|
// So add it to hoverPoints
|
||||||
|
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||||
|
{
|
||||||
|
if (touchRaw.hoverPoints[i] == -1)
|
||||||
|
{
|
||||||
|
touchRaw.hoverPoints[i] = touchRaw.pointId[pointerIndex];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags == AMOTION_EVENT_ACTION_POINTER_UP) || (flags == AMOTION_EVENT_ACTION_UP) || (flags == AMOTION_EVENT_ACTION_HOVER_EXIT))
|
||||||
|
{
|
||||||
|
// One of the touchpoints is released, remove it from touch point arrays
|
||||||
|
if (flags == AMOTION_EVENT_ACTION_HOVER_EXIT)
|
||||||
|
{
|
||||||
|
// If the touchPoint is hover, remove it from hoverPoints
|
||||||
|
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||||
|
{
|
||||||
|
if (touchRaw.hoverPoints[i] == touchRaw.pointId[pointerIndex])
|
||||||
|
{
|
||||||
|
touchRaw.hoverPoints[i] = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = pointerIndex; (i < touchRaw.pointCount - 1) && (i < MAX_TOUCH_POINTS - 1); i++)
|
||||||
|
{
|
||||||
|
touchRaw.pointId[i] = touchRaw.pointId[i+1];
|
||||||
|
touchRaw.position[i] = touchRaw.position[i+1];
|
||||||
|
}
|
||||||
|
touchRaw.pointCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pointCount = 0;
|
||||||
|
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||||
|
{
|
||||||
|
// If the touchPoint is hover, Ignore it
|
||||||
|
bool hover = false;
|
||||||
|
for (int j = 0; j < MAX_TOUCH_POINTS; j++)
|
||||||
|
{
|
||||||
|
// Check if the touchPoint is in hoverPointers
|
||||||
|
if (touchRaw.hoverPoints[j] == touchRaw.pointId[i])
|
||||||
|
{
|
||||||
|
hover = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hover) continue;
|
||||||
|
|
||||||
|
CORE.Input.Touch.pointId[pointCount] = touchRaw.pointId[i];
|
||||||
|
CORE.Input.Touch.position[pointCount] = touchRaw.position[i];
|
||||||
|
pointCount++;
|
||||||
|
}
|
||||||
|
CORE.Input.Touch.pointCount = pointCount;
|
||||||
|
|
||||||
#if defined(SUPPORT_GESTURES_SYSTEM)
|
#if defined(SUPPORT_GESTURES_SYSTEM)
|
||||||
GestureEvent gestureEvent = { 0 };
|
GestureEvent gestureEvent = { 0 };
|
||||||
@ -1312,20 +1386,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
|||||||
ProcessGestureEvent(gestureEvent);
|
ProcessGestureEvent(gestureEvent);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
|
||||||
|
|
||||||
if (flags == AMOTION_EVENT_ACTION_POINTER_UP || flags == AMOTION_EVENT_ACTION_UP)
|
|
||||||
{
|
|
||||||
// One of the touchpoints is released, remove it from touch point arrays
|
|
||||||
for (int i = pointerIndex; (i < CORE.Input.Touch.pointCount - 1) && (i < MAX_TOUCH_POINTS); i++)
|
|
||||||
{
|
|
||||||
CORE.Input.Touch.pointId[i] = CORE.Input.Touch.pointId[i+1];
|
|
||||||
CORE.Input.Touch.position[i] = CORE.Input.Touch.position[i+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
CORE.Input.Touch.pointCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When all touchpoints are tapped and released really quickly, this event is generated
|
// When all touchpoints are tapped and released really quickly, this event is generated
|
||||||
if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;
|
if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/**********************************************************************************************
|
/**********************************************************************************************
|
||||||
*
|
*
|
||||||
* rcore_desktop - Functions to manage window, graphics device and inputs
|
* rcore_desktop_glfw - Functions to manage window, graphics device and inputs
|
||||||
*
|
*
|
||||||
* PLATFORM: DESKTOP: GLFW
|
* PLATFORM: DESKTOP: GLFW
|
||||||
* - Windows (Win32, Win64)
|
* - Windows (Win32, Win64)
|
||||||
@ -576,7 +576,7 @@ void SetWindowIcons(Image *images, int count)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
int valid = 0;
|
int valid = 0;
|
||||||
GLFWimage *icons = RL_CALLOC(count, sizeof(GLFWimage));
|
GLFWimage *icons = (GLFWimage *)RL_CALLOC(count, sizeof(GLFWimage));
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
@ -1238,7 +1238,7 @@ void PollInputEvents(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current axis state
|
// Get current state of axes
|
||||||
const float *axes = state.axes;
|
const float *axes = state.axes;
|
||||||
|
|
||||||
for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1); k++)
|
for (int k = 0; (axes != NULL) && (k < GLFW_GAMEPAD_AXIS_LAST + 1); k++)
|
||||||
@ -1246,7 +1246,7 @@ void PollInputEvents(void)
|
|||||||
CORE.Input.Gamepad.axisState[i][k] = axes[k];
|
CORE.Input.Gamepad.axisState[i][k] = axes[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather axis)
|
// Register buttons for 2nd triggers (because GLFW doesn't count these as buttons but rather as axes)
|
||||||
if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1f)
|
if (CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] > 0.1f)
|
||||||
{
|
{
|
||||||
CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 1;
|
CORE.Input.Gamepad.currentButtonState[i][GAMEPAD_BUTTON_LEFT_TRIGGER_2] = 1;
|
||||||
@ -1327,6 +1327,7 @@ int InitPlatform(void)
|
|||||||
.reallocate = ReallocateWrapper,
|
.reallocate = ReallocateWrapper,
|
||||||
.user = NULL, // RL_*ALLOC macros are not capable of handling user-provided data
|
.user = NULL, // RL_*ALLOC macros are not capable of handling user-provided data
|
||||||
};
|
};
|
||||||
|
|
||||||
glfwInitAllocator(&allocator);
|
glfwInitAllocator(&allocator);
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
@ -1696,6 +1697,8 @@ int InitPlatform(void)
|
|||||||
// Retrieve gamepad names
|
// Retrieve gamepad names
|
||||||
for (int i = 0; i < MAX_GAMEPADS; i++)
|
for (int i = 0; i < MAX_GAMEPADS; i++)
|
||||||
{
|
{
|
||||||
|
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
|
||||||
|
// we can get a not-NULL terminated string, so, we only copy up to (MAX_GAMEPAD_NAME_LENGTH - 1)
|
||||||
if (glfwJoystickPresent(i)) strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
|
if (glfwJoystickPresent(i)) strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -1752,6 +1755,10 @@ static void ErrorCallback(int error, const char *description)
|
|||||||
// NOTE: Window resizing not enabled by default, use SetConfigFlags()
|
// NOTE: Window resizing not enabled by default, use SetConfigFlags()
|
||||||
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
||||||
{
|
{
|
||||||
|
// WARNING: On window minimization, callback is called,
|
||||||
|
// but we don't want to change internal screen values, it breaks things
|
||||||
|
if ((width == 0) || (height == 0)) return;
|
||||||
|
|
||||||
// Reset viewport and projection matrix for new size
|
// Reset viewport and projection matrix for new size
|
||||||
SetupViewport(width, height);
|
SetupViewport(width, height);
|
||||||
|
|
||||||
@ -1969,6 +1976,9 @@ static void JoystickCallback(int jid, int event)
|
|||||||
{
|
{
|
||||||
if (event == GLFW_CONNECTED)
|
if (event == GLFW_CONNECTED)
|
||||||
{
|
{
|
||||||
|
// WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH,
|
||||||
|
// we can get a not-NULL terminated string, so, we clean destination and only copy up to -1
|
||||||
|
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
|
||||||
strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
|
strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||||
}
|
}
|
||||||
else if (event == GLFW_DISCONNECTED)
|
else if (event == GLFW_DISCONNECTED)
|
||||||
|
@ -175,7 +175,9 @@ static const unsigned short keyMappingRGFW[] = {
|
|||||||
[RGFW_superL] = KEY_LEFT_SUPER,
|
[RGFW_superL] = KEY_LEFT_SUPER,
|
||||||
#ifndef RGFW_MACOS
|
#ifndef RGFW_MACOS
|
||||||
[RGFW_shiftR] = KEY_RIGHT_SHIFT,
|
[RGFW_shiftR] = KEY_RIGHT_SHIFT,
|
||||||
|
[RGFW_controlR] = KEY_RIGHT_CONTROL,
|
||||||
[RGFW_altR] = KEY_RIGHT_ALT,
|
[RGFW_altR] = KEY_RIGHT_ALT,
|
||||||
|
[RGFW_superR] = KEY_RIGHT_SUPER,
|
||||||
#endif
|
#endif
|
||||||
[RGFW_space] = KEY_SPACE,
|
[RGFW_space] = KEY_SPACE,
|
||||||
|
|
||||||
@ -583,7 +585,7 @@ void SetWindowPosition(int x, int y)
|
|||||||
// Set monitor for the current window
|
// Set monitor for the current window
|
||||||
void SetWindowMonitor(int monitor)
|
void SetWindowMonitor(int monitor)
|
||||||
{
|
{
|
||||||
RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors()[monitor]);
|
RGFW_window_moveToMonitor(platform.window, RGFW_getMonitors(NULL)[monitor]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
|
// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE)
|
||||||
@ -640,7 +642,7 @@ int GetMonitorCount(void)
|
|||||||
#define MAX_MONITORS_SUPPORTED 6
|
#define MAX_MONITORS_SUPPORTED 6
|
||||||
|
|
||||||
int count = MAX_MONITORS_SUPPORTED;
|
int count = MAX_MONITORS_SUPPORTED;
|
||||||
RGFW_monitor *mons = RGFW_getMonitors();
|
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
@ -657,7 +659,7 @@ int GetMonitorCount(void)
|
|||||||
// Get current monitor where window is placed
|
// Get current monitor where window is placed
|
||||||
int GetCurrentMonitor(void)
|
int GetCurrentMonitor(void)
|
||||||
{
|
{
|
||||||
RGFW_monitor *mons = RGFW_getMonitors();
|
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||||
RGFW_monitor mon = { 0 };
|
RGFW_monitor mon = { 0 };
|
||||||
|
|
||||||
if (platform.window) mon = RGFW_window_getMonitor(platform.window);
|
if (platform.window) mon = RGFW_window_getMonitor(platform.window);
|
||||||
@ -674,7 +676,7 @@ int GetCurrentMonitor(void)
|
|||||||
// Get selected monitor position
|
// Get selected monitor position
|
||||||
Vector2 GetMonitorPosition(int monitor)
|
Vector2 GetMonitorPosition(int monitor)
|
||||||
{
|
{
|
||||||
RGFW_monitor *mons = RGFW_getMonitors();
|
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||||
|
|
||||||
return (Vector2){ (float)mons[monitor].x, (float)mons[monitor].y };
|
return (Vector2){ (float)mons[monitor].x, (float)mons[monitor].y };
|
||||||
}
|
}
|
||||||
@ -682,7 +684,7 @@ Vector2 GetMonitorPosition(int monitor)
|
|||||||
// Get selected monitor width (currently used by monitor)
|
// Get selected monitor width (currently used by monitor)
|
||||||
int GetMonitorWidth(int monitor)
|
int GetMonitorWidth(int monitor)
|
||||||
{
|
{
|
||||||
RGFW_monitor *mons = RGFW_getMonitors();
|
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||||
|
|
||||||
return mons[monitor].mode.area.w;
|
return mons[monitor].mode.area.w;
|
||||||
}
|
}
|
||||||
@ -690,7 +692,7 @@ int GetMonitorWidth(int monitor)
|
|||||||
// Get selected monitor height (currently used by monitor)
|
// Get selected monitor height (currently used by monitor)
|
||||||
int GetMonitorHeight(int monitor)
|
int GetMonitorHeight(int monitor)
|
||||||
{
|
{
|
||||||
RGFW_monitor *mons = RGFW_getMonitors();
|
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||||
|
|
||||||
return mons[monitor].mode.area.h;
|
return mons[monitor].mode.area.h;
|
||||||
}
|
}
|
||||||
@ -698,7 +700,7 @@ int GetMonitorHeight(int monitor)
|
|||||||
// Get selected monitor physical width in millimetres
|
// Get selected monitor physical width in millimetres
|
||||||
int GetMonitorPhysicalWidth(int monitor)
|
int GetMonitorPhysicalWidth(int monitor)
|
||||||
{
|
{
|
||||||
RGFW_monitor *mons = RGFW_getMonitors();
|
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||||
|
|
||||||
return mons[monitor].physW;
|
return mons[monitor].physW;
|
||||||
}
|
}
|
||||||
@ -706,7 +708,7 @@ int GetMonitorPhysicalWidth(int monitor)
|
|||||||
// Get selected monitor physical height in millimetres
|
// Get selected monitor physical height in millimetres
|
||||||
int GetMonitorPhysicalHeight(int monitor)
|
int GetMonitorPhysicalHeight(int monitor)
|
||||||
{
|
{
|
||||||
RGFW_monitor *mons = RGFW_getMonitors();
|
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||||
|
|
||||||
return (int)mons[monitor].physH;
|
return (int)mons[monitor].physH;
|
||||||
}
|
}
|
||||||
@ -714,7 +716,7 @@ int GetMonitorPhysicalHeight(int monitor)
|
|||||||
// Get selected monitor refresh rate
|
// Get selected monitor refresh rate
|
||||||
int GetMonitorRefreshRate(int monitor)
|
int GetMonitorRefreshRate(int monitor)
|
||||||
{
|
{
|
||||||
RGFW_monitor *mons = RGFW_getMonitors();
|
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||||
|
|
||||||
return (int)mons[monitor].mode.refreshRate;
|
return (int)mons[monitor].mode.refreshRate;
|
||||||
}
|
}
|
||||||
@ -722,7 +724,7 @@ int GetMonitorRefreshRate(int monitor)
|
|||||||
// Get the human-readable, UTF-8 encoded name of the selected monitor
|
// Get the human-readable, UTF-8 encoded name of the selected monitor
|
||||||
const char *GetMonitorName(int monitor)
|
const char *GetMonitorName(int monitor)
|
||||||
{
|
{
|
||||||
RGFW_monitor *mons = RGFW_getMonitors();
|
RGFW_monitor *mons = RGFW_getMonitors(NULL);
|
||||||
|
|
||||||
return mons[monitor].name;
|
return mons[monitor].name;
|
||||||
}
|
}
|
||||||
@ -987,7 +989,7 @@ void PollInputEvents(void)
|
|||||||
|
|
||||||
if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)))
|
if ((CORE.Window.eventWaiting) || (IsWindowState(FLAG_WINDOW_MINIMIZED) && !IsWindowState(FLAG_WINDOW_ALWAYS_RUN)))
|
||||||
{
|
{
|
||||||
RGFW_window_eventWait(platform.window, 0); // Wait for input events: keyboard/mouse/window events (callbacks) -> Update keys state
|
RGFW_window_eventWait(platform.window, -1); // Wait for input events: keyboard/mouse/window events (callbacks) -> Update keys state
|
||||||
CORE.Time.previous = GetTime();
|
CORE.Time.previous = GetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1319,6 +1321,13 @@ int InitPlatform(void)
|
|||||||
platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags);
|
platform.window = RGFW_createWindow(CORE.Window.title, RGFW_RECT(0, 0, CORE.Window.screen.width, CORE.Window.screen.height), flags);
|
||||||
platform.mon.mode.area.w = 0;
|
platform.mon.mode.area.w = 0;
|
||||||
|
|
||||||
|
if (platform.window != NULL)
|
||||||
|
{
|
||||||
|
// NOTE: RGFW's exit key is distinct from raylib's exit key (which can
|
||||||
|
// be set with SetExitKey()) and defaults to Escape
|
||||||
|
platform.window->exitKey = RGFW_keyNULL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef PLATFORM_WEB_RGFW
|
#ifndef PLATFORM_WEB_RGFW
|
||||||
RGFW_area screenSize = RGFW_getScreenSize();
|
RGFW_area screenSize = RGFW_getScreenSize();
|
||||||
CORE.Window.display.width = screenSize.w;
|
CORE.Window.display.width = screenSize.w;
|
||||||
|
@ -424,6 +424,8 @@ void ClosePlatform(void); // Close platform
|
|||||||
|
|
||||||
static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode); // Help convert SDL scancodes to raylib key
|
static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode); // Help convert SDL scancodes to raylib key
|
||||||
|
|
||||||
|
static int GetCodepointNextSDL(const char *text, int *codepointSize); // Get next codepoint in a byte sequence and bytes processed
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Declaration
|
// Module Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
@ -1601,13 +1603,18 @@ void PollInputEvents(void)
|
|||||||
{
|
{
|
||||||
// NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int)
|
// NOTE: event.text.text data comes an UTF-8 text sequence but we register codepoints (int)
|
||||||
|
|
||||||
int codepointSize = 0;
|
|
||||||
|
|
||||||
// Check if there is space available in the queue
|
// Check if there is space available in the queue
|
||||||
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
|
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
|
||||||
{
|
{
|
||||||
// Add character (codepoint) to the queue
|
// Add character (codepoint) to the queue
|
||||||
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = GetCodepointNext(event.text.text, &codepointSize);
|
#if defined(PLATFORM_DESKTOP_SDL3)
|
||||||
|
unsigned int textLen = strlen(event.text.text);
|
||||||
|
unsigned int codepoint = (unsigned int)SDL_StepUTF8(&event.text.text, textLen);
|
||||||
|
#else
|
||||||
|
int codepointSize = 0;
|
||||||
|
int codepoint = GetCodepointNextSDL(event.text.text, &codepointSize);
|
||||||
|
#endif
|
||||||
|
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = codepoint;
|
||||||
CORE.Input.Keyboard.charPressedQueueCount++;
|
CORE.Input.Keyboard.charPressedQueueCount++;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@ -1697,8 +1704,8 @@ void PollInputEvents(void)
|
|||||||
CORE.Input.Gamepad.axisCount[jid] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
|
CORE.Input.Gamepad.axisCount[jid] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[jid]));
|
||||||
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f;
|
||||||
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
CORE.Input.Gamepad.axisState[jid][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f;
|
||||||
|
memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH);
|
||||||
strncpy(CORE.Input.Gamepad.name[jid], SDL_GameControllerNameForIndex(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
|
strncpy(CORE.Input.Gamepad.name[jid], SDL_GameControllerNameForIndex(jid), MAX_GAMEPAD_NAME_LENGTH - 1);
|
||||||
CORE.Input.Gamepad.name[jid][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0';
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1825,7 +1832,7 @@ void PollInputEvents(void)
|
|||||||
{
|
{
|
||||||
if (platform.gamepadId[i] == event.jaxis.which)
|
if (platform.gamepadId[i] == event.jaxis.which)
|
||||||
{
|
{
|
||||||
// SDL axis value range is -32768 to 32767, we normalize it to RayLib's -1.0 to 1.0f range
|
// SDL axis value range is -32768 to 32767, we normalize it to raylib's -1.0 to 1.0f range
|
||||||
float value = event.jaxis.value/(float)32767;
|
float value = event.jaxis.value/(float)32767;
|
||||||
CORE.Input.Gamepad.axisState[i][axis] = value;
|
CORE.Input.Gamepad.axisState[i][axis] = value;
|
||||||
|
|
||||||
@ -2093,4 +2100,42 @@ static KeyboardKey ConvertScancodeToKey(SDL_Scancode sdlScancode)
|
|||||||
|
|
||||||
return KEY_NULL; // No equivalent key in Raylib
|
return KEY_NULL; // No equivalent key in Raylib
|
||||||
}
|
}
|
||||||
// EOF
|
|
||||||
|
// Get next codepoint in a byte sequence and bytes processed
|
||||||
|
static int GetCodepointNextSDL(const char *text, int *codepointSize)
|
||||||
|
{
|
||||||
|
const char *ptr = text;
|
||||||
|
int codepoint = 0x3f; // Codepoint (defaults to '?')
|
||||||
|
*codepointSize = 1;
|
||||||
|
|
||||||
|
// Get current codepoint and bytes processed
|
||||||
|
if (0xf0 == (0xf8 & ptr[0]))
|
||||||
|
{
|
||||||
|
// 4 byte UTF-8 codepoint
|
||||||
|
if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks
|
||||||
|
codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]);
|
||||||
|
*codepointSize = 4;
|
||||||
|
}
|
||||||
|
else if (0xe0 == (0xf0 & ptr[0]))
|
||||||
|
{
|
||||||
|
// 3 byte UTF-8 codepoint */
|
||||||
|
if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks
|
||||||
|
codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]);
|
||||||
|
*codepointSize = 3;
|
||||||
|
}
|
||||||
|
else if (0xc0 == (0xe0 & ptr[0]))
|
||||||
|
{
|
||||||
|
// 2 byte UTF-8 codepoint
|
||||||
|
if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } // 10xxxxxx checks
|
||||||
|
codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]);
|
||||||
|
*codepointSize = 2;
|
||||||
|
}
|
||||||
|
else if (0x00 == (0x80 & ptr[0]))
|
||||||
|
{
|
||||||
|
// 1 byte UTF-8 codepoint
|
||||||
|
codepoint = ptr[0];
|
||||||
|
*codepointSize = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return codepoint;
|
||||||
|
}
|
||||||
|
@ -124,7 +124,7 @@ typedef struct {
|
|||||||
|
|
||||||
// Gamepad data
|
// Gamepad data
|
||||||
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
|
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
|
||||||
int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXIS][2]; // [0] = min, [1] = range value of the axis
|
int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXES][2]; // [0] = min, [1] = range value of the axes
|
||||||
int gamepadAbsAxisMap[MAX_GAMEPADS][ABS_CNT]; // Maps the axes gamepads from the evdev api to a sequential one
|
int gamepadAbsAxisMap[MAX_GAMEPADS][ABS_CNT]; // Maps the axes gamepads from the evdev api to a sequential one
|
||||||
int gamepadCount; // The number of gamepads registered
|
int gamepadCount; // The number of gamepads registered
|
||||||
} PlatformData;
|
} PlatformData;
|
||||||
@ -948,7 +948,7 @@ int InitPlatform(void)
|
|||||||
|
|
||||||
TRACELOG(LOG_TRACE, "DISPLAY: EGL configs available: %d", numConfigs);
|
TRACELOG(LOG_TRACE, "DISPLAY: EGL configs available: %d", numConfigs);
|
||||||
|
|
||||||
EGLConfig *configs = RL_CALLOC(numConfigs, sizeof(*configs));
|
EGLConfig *configs = (EGLConfig *)RL_CALLOC(numConfigs, sizeof(*configs));
|
||||||
if (!configs)
|
if (!configs)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get memory for EGL configs");
|
TRACELOG(LOG_WARNING, "DISPLAY: Failed to get memory for EGL configs");
|
||||||
@ -1374,7 +1374,7 @@ static void InitEvdevInput(void)
|
|||||||
if ((strncmp("event", entity->d_name, strlen("event")) == 0) || // Search for devices named "event*"
|
if ((strncmp("event", entity->d_name, strlen("event")) == 0) || // Search for devices named "event*"
|
||||||
(strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*"
|
(strncmp("mouse", entity->d_name, strlen("mouse")) == 0)) // Search for devices named "mouse*"
|
||||||
{
|
{
|
||||||
sprintf(path, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
|
snprintf(path, MAX_FILEPATH_LENGTH, "%s%s", DEFAULT_EVDEV_PATH, entity->d_name);
|
||||||
ConfigureEvdevDevice(path); // Configure the device if appropriate
|
ConfigureEvdevDevice(path); // Configure the device if appropriate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1460,7 +1460,7 @@ static void ConfigureEvdevDevice(char *device)
|
|||||||
// matter if we support them
|
// matter if we support them
|
||||||
else if (hasAbsXY && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
|
else if (hasAbsXY && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
|
||||||
|
|
||||||
// If any of the common joystick axis is present, we assume it's a gamepad
|
// If any of the common joystick axes are present, we assume it's a gamepad
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int axis = (hasAbsXY? ABS_Z : ABS_X); axis < ABS_PRESSURE; axis++)
|
for (int axis = (hasAbsXY? ABS_Z : ABS_X); axis < ABS_PRESSURE; axis++)
|
||||||
@ -1546,7 +1546,7 @@ static void ConfigureEvdevDevice(char *device)
|
|||||||
if (absAxisCount > 0)
|
if (absAxisCount > 0)
|
||||||
{
|
{
|
||||||
// TODO / NOTE
|
// TODO / NOTE
|
||||||
// So gamepad axis (as in the actual linux joydev.c) are just simply enumerated
|
// So gamepad axes (as in the actual linux joydev.c) are just simply enumerated
|
||||||
// and (at least for some input drivers like xpat) it's convention to use
|
// and (at least for some input drivers like xpat) it's convention to use
|
||||||
// ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the
|
// ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the
|
||||||
// shoulder buttons
|
// shoulder buttons
|
||||||
@ -1681,7 +1681,7 @@ static void PollGamepadEvents(void)
|
|||||||
|
|
||||||
TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: Axis: %2i Value: %i", i, axisRaylib, event.value);
|
TRACELOG(LOG_DEBUG, "INPUT: Gamepad %2i: Axis: %2i Value: %i", i, axisRaylib, event.value);
|
||||||
|
|
||||||
if (axisRaylib < MAX_GAMEPAD_AXIS)
|
if (axisRaylib < MAX_GAMEPAD_AXES)
|
||||||
{
|
{
|
||||||
int min = platform.gamepadAbsAxisRange[i][event.code][0];
|
int min = platform.gamepadAbsAxisRange[i][event.code][0];
|
||||||
int range = platform.gamepadAbsAxisRange[i][event.code][1];
|
int range = platform.gamepadAbsAxisRange[i][event.code][1];
|
||||||
|
@ -1081,7 +1081,7 @@ void PollInputEvents(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register axis data for every connected gamepad
|
// Register axis data for every connected gamepad
|
||||||
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXIS); j++)
|
for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXES); j++)
|
||||||
{
|
{
|
||||||
CORE.Input.Gamepad.axisState[i][j] = gamepadState.axis[j];
|
CORE.Input.Gamepad.axisState[i][j] = gamepadState.axis[j];
|
||||||
}
|
}
|
||||||
@ -1746,7 +1746,7 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE
|
|||||||
if (gamepadEvent->connected && (gamepadEvent->index < MAX_GAMEPADS))
|
if (gamepadEvent->connected && (gamepadEvent->index < MAX_GAMEPADS))
|
||||||
{
|
{
|
||||||
CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
|
CORE.Input.Gamepad.ready[gamepadEvent->index] = true;
|
||||||
sprintf(CORE.Input.Gamepad.name[gamepadEvent->index], "%s", gamepadEvent->id);
|
snprintf(CORE.Input.Gamepad.name[gamepadEvent->index], MAX_GAMEPAD_NAME_LENGTH, "%s", gamepadEvent->id);
|
||||||
}
|
}
|
||||||
else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
|
else CORE.Input.Gamepad.ready[gamepadEvent->index] = false;
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@
|
|||||||
#include "utils.h" // Required for: fopen() Android mapping
|
#include "utils.h" // Required for: fopen() Android mapping
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_MODULE_RAUDIO)
|
#if defined(SUPPORT_MODULE_RAUDIO) || defined(RAUDIO_STANDALONE)
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// To avoid conflicting windows.h symbols with raylib, some flags are defined
|
// To avoid conflicting windows.h symbols with raylib, some flags are defined
|
||||||
@ -1037,6 +1037,8 @@ void UnloadSoundAlias(Sound alias)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update sound buffer with new data
|
// Update sound buffer with new data
|
||||||
|
// NOTE 1: data format must match sound.stream.sampleSize
|
||||||
|
// NOTE 2: frameCount must not exceed sound.frameCount
|
||||||
void UpdateSound(Sound sound, const void *data, int frameCount)
|
void UpdateSound(Sound sound, const void *data, int frameCount)
|
||||||
{
|
{
|
||||||
if (sound.stream.buffer != NULL)
|
if (sound.stream.buffer != NULL)
|
||||||
@ -1337,7 +1339,7 @@ Music LoadMusicStream(const char *fileName)
|
|||||||
#if defined(SUPPORT_FILEFORMAT_WAV)
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
else if (IsFileExtension(fileName, ".wav"))
|
else if (IsFileExtension(fileName, ".wav"))
|
||||||
{
|
{
|
||||||
drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
|
drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav));
|
||||||
bool success = drwav_init_file(ctxWav, fileName, NULL);
|
bool success = drwav_init_file(ctxWav, fileName, NULL);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
@ -1387,7 +1389,7 @@ Music LoadMusicStream(const char *fileName)
|
|||||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||||
else if (IsFileExtension(fileName, ".mp3"))
|
else if (IsFileExtension(fileName, ".mp3"))
|
||||||
{
|
{
|
||||||
drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
|
drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3));
|
||||||
int result = drmp3_init_file(ctxMp3, fileName, NULL);
|
int result = drmp3_init_file(ctxMp3, fileName, NULL);
|
||||||
|
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
@ -1478,7 +1480,7 @@ Music LoadMusicStream(const char *fileName)
|
|||||||
#if defined(SUPPORT_FILEFORMAT_MOD)
|
#if defined(SUPPORT_FILEFORMAT_MOD)
|
||||||
else if (IsFileExtension(fileName, ".mod"))
|
else if (IsFileExtension(fileName, ".mod"))
|
||||||
{
|
{
|
||||||
jar_mod_context_t *ctxMod = RL_CALLOC(1, sizeof(jar_mod_context_t));
|
jar_mod_context_t *ctxMod = (jar_mod_context_t *)RL_CALLOC(1, sizeof(jar_mod_context_t));
|
||||||
jar_mod_init(ctxMod);
|
jar_mod_init(ctxMod);
|
||||||
int result = jar_mod_load_file(ctxMod, fileName);
|
int result = jar_mod_load_file(ctxMod, fileName);
|
||||||
|
|
||||||
@ -1529,7 +1531,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
|
|||||||
#if defined(SUPPORT_FILEFORMAT_WAV)
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0))
|
else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0))
|
||||||
{
|
{
|
||||||
drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
|
drwav *ctxWav = (drwav *)RL_CALLOC(1, sizeof(drwav));
|
||||||
|
|
||||||
bool success = drwav_init_memory(ctxWav, (const void *)data, dataSize, NULL);
|
bool success = drwav_init_memory(ctxWav, (const void *)data, dataSize, NULL);
|
||||||
|
|
||||||
@ -1580,7 +1582,7 @@ Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data,
|
|||||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||||
else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
|
else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
|
||||||
{
|
{
|
||||||
drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
|
drmp3 *ctxMp3 = (drmp3 *)RL_CALLOC(1, sizeof(drmp3));
|
||||||
int success = drmp3_init_memory(ctxMp3, (const void*)data, dataSize, NULL);
|
int success = drmp3_init_memory(ctxMp3, (const void*)data, dataSize, NULL);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
@ -1869,6 +1871,7 @@ void SeekMusicStream(Music music, float position)
|
|||||||
void UpdateMusicStream(Music music)
|
void UpdateMusicStream(Music music)
|
||||||
{
|
{
|
||||||
if (music.stream.buffer == NULL) return;
|
if (music.stream.buffer == NULL) return;
|
||||||
|
if (!music.stream.buffer->playing) return;
|
||||||
|
|
||||||
ma_mutex_lock(&AUDIO.System.lock);
|
ma_mutex_lock(&AUDIO.System.lock);
|
||||||
|
|
||||||
@ -1888,14 +1891,28 @@ void UpdateMusicStream(Music music)
|
|||||||
// Check both sub-buffers to check if they require refilling
|
// Check both sub-buffers to check if they require refilling
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
if (!music.stream.buffer->isSubBufferProcessed[i]) continue; // No refilling required, move to next sub-buffer
|
|
||||||
|
|
||||||
unsigned int framesLeft = music.frameCount - music.stream.buffer->framesProcessed; // Frames left to be processed
|
unsigned int framesLeft = music.frameCount - music.stream.buffer->framesProcessed; // Frames left to be processed
|
||||||
unsigned int framesToStream = 0; // Total frames to be streamed
|
unsigned int framesToStream = 0; // Total frames to be streamed
|
||||||
|
|
||||||
if ((framesLeft >= subBufferSizeInFrames) || music.looping) framesToStream = subBufferSizeInFrames;
|
if ((framesLeft >= subBufferSizeInFrames) || music.looping) framesToStream = subBufferSizeInFrames;
|
||||||
else framesToStream = framesLeft;
|
else framesToStream = framesLeft;
|
||||||
|
|
||||||
|
if (framesToStream == 0)
|
||||||
|
{
|
||||||
|
// Check if both buffers have been processed
|
||||||
|
if (music.stream.buffer->isSubBufferProcessed[0] && music.stream.buffer->isSubBufferProcessed[1])
|
||||||
|
{
|
||||||
|
ma_mutex_unlock(&AUDIO.System.lock);
|
||||||
|
StopMusicStream(music);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ma_mutex_unlock(&AUDIO.System.lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!music.stream.buffer->isSubBufferProcessed[i]) continue; // No refilling required, move to next sub-buffer
|
||||||
|
|
||||||
int frameCountStillNeeded = framesToStream;
|
int frameCountStillNeeded = framesToStream;
|
||||||
int frameCountReadTotal = 0;
|
int frameCountReadTotal = 0;
|
||||||
|
|
||||||
@ -2008,19 +2025,6 @@ void UpdateMusicStream(Music music)
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpdateAudioStreamInLockedState(music.stream, AUDIO.System.pcmBuffer, framesToStream);
|
UpdateAudioStreamInLockedState(music.stream, AUDIO.System.pcmBuffer, framesToStream);
|
||||||
|
|
||||||
music.stream.buffer->framesProcessed = music.stream.buffer->framesProcessed%music.frameCount;
|
|
||||||
|
|
||||||
if (framesLeft <= subBufferSizeInFrames)
|
|
||||||
{
|
|
||||||
if (!music.looping)
|
|
||||||
{
|
|
||||||
ma_mutex_unlock(&AUDIO.System.lock);
|
|
||||||
// Streaming is ending, we filled latest frames from input
|
|
||||||
StopMusicStream(music);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ma_mutex_unlock(&AUDIO.System.lock);
|
ma_mutex_unlock(&AUDIO.System.lock);
|
||||||
@ -2083,8 +2087,12 @@ float GetMusicTimePlayed(Music music)
|
|||||||
int subBufferSize = (int)music.stream.buffer->sizeInFrames/2;
|
int subBufferSize = (int)music.stream.buffer->sizeInFrames/2;
|
||||||
int framesInFirstBuffer = music.stream.buffer->isSubBufferProcessed[0]? 0 : subBufferSize;
|
int framesInFirstBuffer = music.stream.buffer->isSubBufferProcessed[0]? 0 : subBufferSize;
|
||||||
int framesInSecondBuffer = music.stream.buffer->isSubBufferProcessed[1]? 0 : subBufferSize;
|
int framesInSecondBuffer = music.stream.buffer->isSubBufferProcessed[1]? 0 : subBufferSize;
|
||||||
|
int framesInBuffers = framesInFirstBuffer + framesInSecondBuffer;
|
||||||
|
if (framesInBuffers > music.frameCount) {
|
||||||
|
if (!music.looping) framesInBuffers = music.frameCount;
|
||||||
|
}
|
||||||
int framesSentToMix = music.stream.buffer->frameCursorPos%subBufferSize;
|
int framesSentToMix = music.stream.buffer->frameCursorPos%subBufferSize;
|
||||||
int framesPlayed = (framesProcessed - framesInFirstBuffer - framesInSecondBuffer + framesSentToMix)%(int)music.frameCount;
|
int framesPlayed = (framesProcessed - framesInBuffers + framesSentToMix)%(int)music.frameCount;
|
||||||
if (framesPlayed < 0) framesPlayed += music.frameCount;
|
if (framesPlayed < 0) framesPlayed += music.frameCount;
|
||||||
secondsPlayed = (float)framesPlayed/music.stream.sampleRate;
|
secondsPlayed = (float)framesPlayed/music.stream.sampleRate;
|
||||||
ma_mutex_unlock(&AUDIO.System.lock);
|
ma_mutex_unlock(&AUDIO.System.lock);
|
||||||
@ -2681,8 +2689,7 @@ static void UpdateAudioStreamInLockedState(AudioStream stream, const void *data,
|
|||||||
ma_uint32 subBufferSizeInFrames = stream.buffer->sizeInFrames/2;
|
ma_uint32 subBufferSizeInFrames = stream.buffer->sizeInFrames/2;
|
||||||
unsigned char *subBuffer = stream.buffer->data + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate);
|
unsigned char *subBuffer = stream.buffer->data + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate);
|
||||||
|
|
||||||
// Total frames processed in buffer is always the complete size, filled with 0 if required
|
stream.buffer->framesProcessed += frameCount;
|
||||||
stream.buffer->framesProcessed += subBufferSizeInFrames;
|
|
||||||
|
|
||||||
// Does this API expect a whole buffer to be updated in one go?
|
// Does this API expect a whole buffer to be updated in one go?
|
||||||
// Assuming so, but if not will need to change this logic
|
// Assuming so, but if not will need to change this logic
|
||||||
|
@ -743,7 +743,7 @@ typedef enum {
|
|||||||
GAMEPAD_BUTTON_RIGHT_THUMB // Gamepad joystick pressed button right
|
GAMEPAD_BUTTON_RIGHT_THUMB // Gamepad joystick pressed button right
|
||||||
} GamepadButton;
|
} GamepadButton;
|
||||||
|
|
||||||
// Gamepad axis
|
// Gamepad axes
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GAMEPAD_AXIS_LEFT_X = 0, // Gamepad left stick X axis
|
GAMEPAD_AXIS_LEFT_X = 0, // Gamepad left stick X axis
|
||||||
GAMEPAD_AXIS_LEFT_Y = 1, // Gamepad left stick Y axis
|
GAMEPAD_AXIS_LEFT_Y = 1, // Gamepad left stick Y axis
|
||||||
@ -954,7 +954,7 @@ typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args);
|
|||||||
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data
|
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data
|
||||||
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data
|
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data
|
||||||
typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data
|
typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data
|
||||||
typedef bool (*SaveFileTextCallback)(const char *fileName, char *text); // FileIO: Save text data
|
typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // FileIO: Save text data
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Global Variables Definition
|
// Global Variables Definition
|
||||||
@ -1125,7 +1125,7 @@ RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save
|
|||||||
RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success
|
RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success
|
||||||
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
|
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
|
||||||
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
|
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
|
||||||
RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
|
RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
// File system functions
|
// File system functions
|
||||||
@ -1155,8 +1155,8 @@ RLAPI long GetFileModTime(const char *fileName); // Get file mo
|
|||||||
// Compression/Encoding functionality
|
// Compression/Encoding functionality
|
||||||
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()
|
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()
|
||||||
RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree()
|
RLAPI 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 char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string (includes NULL terminator), memory must be MemFree()
|
||||||
RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree()
|
RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize); // Decode Base64 string (expected NULL terminated), memory must be MemFree()
|
||||||
RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code
|
RLAPI unsigned int 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 *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes)
|
||||||
RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
|
RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
|
||||||
@ -1194,8 +1194,8 @@ RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Check if a game
|
|||||||
RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once
|
RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once
|
||||||
RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed
|
RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed
|
||||||
RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed
|
RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed
|
||||||
RLAPI int GetGamepadAxisCount(int gamepad); // Get gamepad axis count for a gamepad
|
RLAPI int GetGamepadAxisCount(int gamepad); // Get axis count for a gamepad
|
||||||
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get axis movement value for a gamepad axis
|
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get movement value for a gamepad axis
|
||||||
RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB)
|
RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB)
|
||||||
RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds)
|
RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds)
|
||||||
|
|
||||||
@ -1266,7 +1266,9 @@ RLAPI void DrawCircleV(Vector2 center, float radius, Color color);
|
|||||||
RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline
|
RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline
|
||||||
RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version)
|
RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version)
|
||||||
RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse
|
RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse
|
||||||
|
RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse (Vector version)
|
||||||
RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline
|
RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline
|
||||||
|
RLAPI void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse outline (Vector version)
|
||||||
RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring
|
RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring
|
||||||
RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline
|
RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline
|
||||||
RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle
|
RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle
|
||||||
@ -1275,7 +1277,7 @@ RLAPI void DrawRectangleRec(Rectangle rec, Color color);
|
|||||||
RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters
|
RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters
|
||||||
RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom); // Draw a vertical-gradient-filled rectangle
|
RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom); // Draw a vertical-gradient-filled rectangle
|
||||||
RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right); // Draw a horizontal-gradient-filled rectangle
|
RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right); // Draw a horizontal-gradient-filled rectangle
|
||||||
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight); // Draw a gradient-filled rectangle with custom vertex colors
|
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight); // Draw a gradient-filled rectangle with custom vertex colors
|
||||||
RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline
|
RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline
|
||||||
RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters
|
RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters
|
||||||
RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges
|
RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges
|
||||||
@ -1408,8 +1410,8 @@ RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color c
|
|||||||
RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image
|
RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image
|
||||||
RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
|
RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image
|
||||||
RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image
|
RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image
|
||||||
RLAPI void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
|
RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center)
|
||||||
RLAPI void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
|
RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image
|
||||||
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
|
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
|
||||||
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
|
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
|
||||||
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
|
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
|
||||||
@ -1424,8 +1426,8 @@ RLAPI bool IsTextureValid(Texture2D texture);
|
|||||||
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
|
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
|
||||||
RLAPI bool IsRenderTextureValid(RenderTexture2D target); // Check if a render texture is valid (loaded in GPU)
|
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 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 UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data (pixels should be able to fill texture)
|
||||||
RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data
|
RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data (pixels and rec should fit in texture)
|
||||||
|
|
||||||
// Texture configuration functions
|
// Texture configuration functions
|
||||||
RLAPI void GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture
|
RLAPI void GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture
|
||||||
@ -1646,7 +1648,7 @@ RLAPI Sound LoadSound(const char *fileName); // Load so
|
|||||||
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
|
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 Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data
|
||||||
RLAPI bool IsSoundValid(Sound sound); // Checks if a sound is valid (data loaded and buffers initialized)
|
RLAPI 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 UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (data and frame count should fit in sound)
|
||||||
RLAPI void UnloadWave(Wave wave); // Unload wave data
|
RLAPI void UnloadWave(Wave wave); // Unload wave data
|
||||||
RLAPI void UnloadSound(Sound sound); // Unload sound
|
RLAPI void UnloadSound(Sound sound); // Unload sound
|
||||||
RLAPI void UnloadSoundAlias(Sound alias); // Unload a sound alias (does not deallocate sample data)
|
RLAPI void UnloadSoundAlias(Sound alias); // Unload a sound alias (does not deallocate sample data)
|
||||||
|
@ -235,10 +235,10 @@ __declspec(dllimport) unsigned int __stdcall timeEndPeriod(unsigned int uPeriod)
|
|||||||
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
|
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
|
||||||
#endif
|
#endif
|
||||||
#ifndef MAX_GAMEPAD_NAME_LENGTH
|
#ifndef MAX_GAMEPAD_NAME_LENGTH
|
||||||
#define MAX_GAMEPAD_NAME_LENGTH 128 // Maximum number of characters of gamepad name (byte size)
|
#define MAX_GAMEPAD_NAME_LENGTH 128 // Maximum number of characters in a gamepad name (byte size)
|
||||||
#endif
|
#endif
|
||||||
#ifndef MAX_GAMEPAD_AXIS
|
#ifndef MAX_GAMEPAD_AXES
|
||||||
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
|
#define MAX_GAMEPAD_AXES 8 // Maximum number of axes supported (per gamepad)
|
||||||
#endif
|
#endif
|
||||||
#ifndef MAX_GAMEPAD_BUTTONS
|
#ifndef MAX_GAMEPAD_BUTTONS
|
||||||
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
|
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
|
||||||
@ -354,12 +354,12 @@ typedef struct CoreData {
|
|||||||
} Touch;
|
} Touch;
|
||||||
struct {
|
struct {
|
||||||
int lastButtonPressed; // Register last gamepad button pressed
|
int lastButtonPressed; // Register last gamepad button pressed
|
||||||
int axisCount[MAX_GAMEPADS]; // Register number of available gamepad axis
|
int axisCount[MAX_GAMEPADS]; // Register number of available gamepad axes
|
||||||
bool ready[MAX_GAMEPADS]; // Flag to know if gamepad is ready
|
bool ready[MAX_GAMEPADS]; // Flag to know if gamepad is ready
|
||||||
char name[MAX_GAMEPADS][MAX_GAMEPAD_NAME_LENGTH]; // Gamepad name holder
|
char name[MAX_GAMEPADS][MAX_GAMEPAD_NAME_LENGTH]; // Gamepad name holder
|
||||||
char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state
|
char currentButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Current gamepad buttons state
|
||||||
char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state
|
char previousButtonState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Previous gamepad buttons state
|
||||||
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state
|
float axisState[MAX_GAMEPADS][MAX_GAMEPAD_AXES]; // Gamepad axes state
|
||||||
|
|
||||||
} Gamepad;
|
} Gamepad;
|
||||||
} Input;
|
} Input;
|
||||||
@ -523,25 +523,25 @@ const char *TextFormat(const char *text, ...); // Formatting of tex
|
|||||||
#define PLATFORM_DESKTOP_GLFW
|
#define PLATFORM_DESKTOP_GLFW
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We're using `#pragma message` because `#warning` is not adopted by MSVC.
|
// We're using '#pragma message' because '#warning' is not adopted by MSVC
|
||||||
#if defined(SUPPORT_CLIPBOARD_IMAGE)
|
#if defined(SUPPORT_CLIPBOARD_IMAGE)
|
||||||
#if !defined(SUPPORT_MODULE_RTEXTURES)
|
#if !defined(SUPPORT_MODULE_RTEXTURES)
|
||||||
#pragma message ("Warning: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly")
|
#pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// It's nice to have support Bitmap on Linux as well, but not as necessary as Windows
|
// It's nice to have support Bitmap on Linux as well, but not as necessary as Windows
|
||||||
#if !defined(SUPPORT_FILEFORMAT_BMP) && defined(_WIN32)
|
#if !defined(SUPPORT_FILEFORMAT_BMP) && defined(_WIN32)
|
||||||
#pragma message ("Warning: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows")
|
#pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// From what I've tested applications on Wayland saves images on clipboard as PNG.
|
// From what I've tested applications on Wayland saves images on clipboard as PNG
|
||||||
#if (!defined(SUPPORT_FILEFORMAT_PNG) || !defined(SUPPORT_FILEFORMAT_JPG)) && !defined(_WIN32)
|
#if (!defined(SUPPORT_FILEFORMAT_PNG) || !defined(SUPPORT_FILEFORMAT_JPG)) && !defined(_WIN32)
|
||||||
#pragma message ("Warning: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
|
#pragma message ("WARNING: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Not needed because `rtexture.c` will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined.
|
// Not needed because `rtexture.c` will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined
|
||||||
// #if !defined(STBI_REQUIRED)
|
// #if !defined(STBI_REQUIRED)
|
||||||
// #pragma message ("Warning: "STBI_REQUIRED is not defined, that means we can't load images from clipbard"
|
// #pragma message ("WARNING: "STBI_REQUIRED is not defined, that means we can't load images from clipbard"
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
#endif // SUPPORT_CLIPBOARD_IMAGE
|
#endif // SUPPORT_CLIPBOARD_IMAGE
|
||||||
@ -2328,11 +2328,14 @@ FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool
|
|||||||
// Unload directory filepaths
|
// Unload directory filepaths
|
||||||
// WARNING: files.count is not reseted to 0 after unloading
|
// WARNING: files.count is not reseted to 0 after unloading
|
||||||
void UnloadDirectoryFiles(FilePathList files)
|
void UnloadDirectoryFiles(FilePathList files)
|
||||||
|
{
|
||||||
|
if (files.paths != NULL)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
|
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
|
||||||
|
|
||||||
RL_FREE(files.paths);
|
RL_FREE(files.paths);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create directories (including full path requested), returns 0 on success
|
// Create directories (including full path requested), returns 0 on success
|
||||||
int MakeDirectory(const char *dirPath)
|
int MakeDirectory(const char *dirPath)
|
||||||
@ -2512,7 +2515,7 @@ unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDa
|
|||||||
|
|
||||||
#if defined(SUPPORT_COMPRESSION_API)
|
#if defined(SUPPORT_COMPRESSION_API)
|
||||||
// Compress data and generate a valid DEFLATE stream
|
// Compress data and generate a valid DEFLATE stream
|
||||||
struct sdefl *sdefl = RL_CALLOC(1, sizeof(struct sdefl)); // WARNING: Possible stack overflow, struct sdefl is almost 1MB
|
struct sdefl *sdefl = (struct sdefl *)RL_CALLOC(1, sizeof(struct sdefl)); // WARNING: Possible stack overflow, struct sdefl is almost 1MB
|
||||||
int bounds = sdefl_bound(dataSize);
|
int bounds = sdefl_bound(dataSize);
|
||||||
compData = (unsigned char *)RL_CALLOC(bounds, 1);
|
compData = (unsigned char *)RL_CALLOC(bounds, 1);
|
||||||
|
|
||||||
@ -2551,96 +2554,112 @@ unsigned char *DecompressData(const unsigned char *compData, int compDataSize, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encode data to Base64 string
|
// Encode data to Base64 string
|
||||||
|
// NOTE: Returned string includes NULL terminator, considered on outputSize
|
||||||
char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
|
char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
|
||||||
{
|
{
|
||||||
static const unsigned char base64encodeTable[] = {
|
// Base64 conversion table from RFC 4648 [0..63]
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
// NOTE: They represent 64 values (6 bits), to encode 3 bytes of data into 4 "sixtets" (6bit characters)
|
||||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
static const char base64EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int modTable[] = { 0, 2, 1 };
|
// Compute expected size and padding
|
||||||
|
int paddedSize = dataSize;
|
||||||
|
while (paddedSize%3 != 0) paddedSize++; // Padding bytes to round 4*(dataSize/3) to 4 bytes
|
||||||
|
int estimatedOutputSize = 4*(paddedSize/3);
|
||||||
|
int padding = paddedSize - dataSize;
|
||||||
|
|
||||||
*outputSize = 4*((dataSize + 2)/3);
|
// Adding null terminator to string
|
||||||
|
estimatedOutputSize += 1;
|
||||||
|
|
||||||
char *encodedData = (char *)RL_MALLOC(*outputSize);
|
// Load some memory to store encoded string
|
||||||
|
char *encodedData = (char *)RL_CALLOC(estimatedOutputSize, 1);
|
||||||
|
if (encodedData == NULL) return NULL;
|
||||||
|
|
||||||
if (encodedData == NULL) return NULL; // Security check
|
int outputCount = 0;
|
||||||
|
for (int i = 0; i < dataSize;)
|
||||||
for (int i = 0, j = 0; i < dataSize;)
|
|
||||||
{
|
{
|
||||||
unsigned int octetA = (i < dataSize)? (unsigned char)data[i++] : 0;
|
unsigned int octetA = 0;
|
||||||
unsigned int octetB = (i < dataSize)? (unsigned char)data[i++] : 0;
|
unsigned int octetB = 0;
|
||||||
unsigned int octetC = (i < dataSize)? (unsigned char)data[i++] : 0;
|
unsigned int octetC = 0;
|
||||||
|
unsigned int octetPack = 0;
|
||||||
|
|
||||||
unsigned int triple = (octetA << 0x10) + (octetB << 0x08) + octetC;
|
octetA = data[i]; // Generates 2 sextets
|
||||||
|
octetB = ((i + 1) < dataSize)? data[i + 1] : 0; // Generates 3 sextets
|
||||||
|
octetC = ((i + 2) < dataSize)? data[i + 2] : 0; // Generates 4 sextets
|
||||||
|
|
||||||
encodedData[j++] = base64encodeTable[(triple >> 3*6) & 0x3F];
|
octetPack = (octetA << 16) | (octetB << 8) | octetC;
|
||||||
encodedData[j++] = base64encodeTable[(triple >> 2*6) & 0x3F];
|
|
||||||
encodedData[j++] = base64encodeTable[(triple >> 1*6) & 0x3F];
|
encodedData[outputCount + 0] = (unsigned char)(base64EncodeTable[(octetPack >> 18) & 0x3f]);
|
||||||
encodedData[j++] = base64encodeTable[(triple >> 0*6) & 0x3F];
|
encodedData[outputCount + 1] = (unsigned char)(base64EncodeTable[(octetPack >> 12) & 0x3f]);
|
||||||
|
encodedData[outputCount + 2] = (unsigned char)(base64EncodeTable[(octetPack >> 6) & 0x3f]);
|
||||||
|
encodedData[outputCount + 3] = (unsigned char)(base64EncodeTable[octetPack & 0x3f]);
|
||||||
|
outputCount += 4;
|
||||||
|
i += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < modTable[dataSize%3]; i++) encodedData[*outputSize - 1 - i] = '='; // Padding character
|
// Add required padding bytes
|
||||||
|
for (int p = 0; p < padding; p++) encodedData[outputCount - p - 1] = '=';
|
||||||
|
|
||||||
|
// Add null terminator to string
|
||||||
|
encodedData[outputCount] = '\0';
|
||||||
|
outputCount++;
|
||||||
|
|
||||||
|
if (outputCount != estimatedOutputSize) TRACELOG(LOG_WARNING, "BASE64: Output size differs from estimation");
|
||||||
|
|
||||||
|
*outputSize = estimatedOutputSize;
|
||||||
return encodedData;
|
return encodedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode Base64 string data
|
// Decode Base64 string (expected NULL terminated)
|
||||||
unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
|
unsigned char *DecodeDataBase64(const char *text, int *outputSize)
|
||||||
{
|
{
|
||||||
static const unsigned char base64decodeTable[] = {
|
// Base64 decode table
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
// NOTE: Following ASCII order [0..255] assigning the expected sixtet value to
|
||||||
0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
// every character in the corresponding ASCII position
|
||||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
static const unsigned char base64DecodeTable[256] = {
|
||||||
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
|
['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, ['F'] = 5, ['G'] = 6, ['H'] = 7,
|
||||||
|
['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15,
|
||||||
|
['Q'] = 16, ['R'] = 17, ['S'] = 18, ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25,
|
||||||
|
['a'] = 26, ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33,
|
||||||
|
['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, ['p'] = 41,
|
||||||
|
['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47, ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51,
|
||||||
|
['0'] = 52, ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
|
||||||
|
['8'] = 60, ['9'] = 61, ['+'] = 62, ['/'] = 63
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get output size of Base64 input data
|
// Compute expected size and padding
|
||||||
int outSize = 0;
|
int dataSize = (int)strlen(text); // WARNING: Expecting NULL terminated strings!
|
||||||
for (int i = 0; data[4*i] != 0; i++)
|
int ending = dataSize - 1;
|
||||||
|
int padding = 0;
|
||||||
|
while (text[ending] == '=') { padding++; ending--; }
|
||||||
|
int estimatedOutputSize = 3*(dataSize/4) - padding;
|
||||||
|
int maxOutputSize = 3*(dataSize/4);
|
||||||
|
|
||||||
|
// Load some memory to store decoded data
|
||||||
|
// NOTE: Allocated enough size to include padding
|
||||||
|
unsigned char *decodedData = (unsigned char *)RL_CALLOC(maxOutputSize, 1);
|
||||||
|
if (decodedData == NULL) return NULL;
|
||||||
|
|
||||||
|
int outputCount = 0;
|
||||||
|
for (int i = 0; i < dataSize;)
|
||||||
{
|
{
|
||||||
if (data[4*i + 3] == '=')
|
// Every 4 sixtets must generate 3 octets
|
||||||
{
|
unsigned int sixtetA = base64DecodeTable[(unsigned char)text[i]];
|
||||||
if (data[4*i + 2] == '=') outSize += 1;
|
unsigned int sixtetB = base64DecodeTable[(unsigned char)text[i + 1]];
|
||||||
else outSize += 2;
|
unsigned int sixtetC = ((unsigned char)text[i + 2] != '=')? base64DecodeTable[(unsigned char)text[i + 2]] : 0;
|
||||||
}
|
unsigned int sixtetD = ((unsigned char)text[i + 3] != '=')? base64DecodeTable[(unsigned char)text[i + 3]] : 0;
|
||||||
else outSize += 3;
|
|
||||||
|
unsigned int octetPack = (sixtetA << 18) | (sixtetB << 12) | (sixtetC << 6) | sixtetD;
|
||||||
|
|
||||||
|
decodedData[outputCount + 0] = (octetPack >> 16) & 0xff;
|
||||||
|
decodedData[outputCount + 1] = (octetPack >> 8) & 0xff;
|
||||||
|
decodedData[outputCount + 2] = octetPack & 0xff;
|
||||||
|
outputCount += 3;
|
||||||
|
i += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate memory to store decoded Base64 data
|
if (estimatedOutputSize != (outputCount - padding)) TRACELOG(LOG_WARNING, "BASE64: Decoded size differs from estimation");
|
||||||
unsigned char *decodedData = (unsigned char *)RL_MALLOC(outSize);
|
|
||||||
|
|
||||||
for (int i = 0; i < outSize/3; i++)
|
*outputSize = estimatedOutputSize;
|
||||||
{
|
|
||||||
unsigned char a = base64decodeTable[(int)data[4*i]];
|
|
||||||
unsigned char b = base64decodeTable[(int)data[4*i + 1]];
|
|
||||||
unsigned char c = base64decodeTable[(int)data[4*i + 2]];
|
|
||||||
unsigned char d = base64decodeTable[(int)data[4*i + 3]];
|
|
||||||
|
|
||||||
decodedData[3*i] = (a << 2) | (b >> 4);
|
|
||||||
decodedData[3*i + 1] = (b << 4) | (c >> 2);
|
|
||||||
decodedData[3*i + 2] = (c << 6) | d;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outSize%3 == 1)
|
|
||||||
{
|
|
||||||
int n = outSize/3;
|
|
||||||
unsigned char a = base64decodeTable[(int)data[4*n]];
|
|
||||||
unsigned char b = base64decodeTable[(int)data[4*n + 1]];
|
|
||||||
decodedData[outSize - 1] = (a << 2) | (b >> 4);
|
|
||||||
}
|
|
||||||
else if (outSize%3 == 2)
|
|
||||||
{
|
|
||||||
int n = outSize/3;
|
|
||||||
unsigned char a = base64decodeTable[(int)data[4*n]];
|
|
||||||
unsigned char b = base64decodeTable[(int)data[4*n + 1]];
|
|
||||||
unsigned char c = base64decodeTable[(int)data[4*n + 2]];
|
|
||||||
decodedData[outSize - 2] = (a << 2) | (b >> 4);
|
|
||||||
decodedData[outSize - 1] = (b << 4) | (c >> 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
*outputSize = outSize;
|
|
||||||
return decodedData;
|
return decodedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2648,38 +2667,38 @@ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
|
|||||||
unsigned int ComputeCRC32(unsigned char *data, int dataSize)
|
unsigned int ComputeCRC32(unsigned char *data, int dataSize)
|
||||||
{
|
{
|
||||||
static unsigned int crcTable[256] = {
|
static unsigned int crcTable[256] = {
|
||||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||||
0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned int crc = ~0u;
|
unsigned int crc = ~0u;
|
||||||
@ -2743,7 +2762,7 @@ unsigned int *ComputeMD5(unsigned char *data, int dataSize)
|
|||||||
|
|
||||||
int newDataSize = ((((dataSize + 8)/64) + 1)*64) - 8;
|
int newDataSize = ((((dataSize + 8)/64) + 1)*64) - 8;
|
||||||
|
|
||||||
unsigned char *msg = RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
|
unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize + 64, 1); // Initialize with '0' bits, allocating 64 extra bytes
|
||||||
memcpy(msg, data, dataSize);
|
memcpy(msg, data, dataSize);
|
||||||
msg[dataSize] = 128; // Write the '1' bit
|
msg[dataSize] = 128; // Write the '1' bit
|
||||||
|
|
||||||
@ -2833,7 +2852,7 @@ unsigned int *ComputeSHA1(unsigned char *data, int dataSize)
|
|||||||
|
|
||||||
int newDataSize = ((((dataSize + 8)/64) + 1)*64);
|
int newDataSize = ((((dataSize + 8)/64) + 1)*64);
|
||||||
|
|
||||||
unsigned char *msg = RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
|
unsigned char *msg = (unsigned char *)RL_CALLOC(newDataSize, 1); // Initialize with '0' bits
|
||||||
memcpy(msg, data, dataSize);
|
memcpy(msg, data, dataSize);
|
||||||
msg[dataSize] = 128; // Write the '1' bit
|
msg[dataSize] = 128; // Write the '1' bit
|
||||||
|
|
||||||
@ -3364,11 +3383,11 @@ int GetGamepadAxisCount(int gamepad)
|
|||||||
// Get axis movement vector for a gamepad
|
// Get axis movement vector for a gamepad
|
||||||
float GetGamepadAxisMovement(int gamepad, int axis)
|
float GetGamepadAxisMovement(int gamepad, int axis)
|
||||||
{
|
{
|
||||||
float value = (axis == GAMEPAD_AXIS_LEFT_TRIGGER || axis == GAMEPAD_AXIS_RIGHT_TRIGGER)? -1.0f : 0.0f;
|
float value = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
|
||||||
|
|
||||||
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXIS))
|
if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES))
|
||||||
{
|
{
|
||||||
float movement = value < 0.0f ? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
|
float movement = (value < 0.0f)? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]);
|
||||||
|
|
||||||
if (movement > value) value = CORE.Input.Gamepad.axisState[gamepad][axis];
|
if (movement > value) value = CORE.Input.Gamepad.axisState[gamepad][axis];
|
||||||
}
|
}
|
||||||
@ -3753,6 +3772,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
|
|||||||
// Scan all files and directories recursively from a base path
|
// Scan all files and directories recursively from a base path
|
||||||
static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter)
|
static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter)
|
||||||
{
|
{
|
||||||
|
// WARNING: Path can not be static or it will be reused between recursive function calls!
|
||||||
char path[MAX_FILEPATH_LENGTH] = { 0 };
|
char path[MAX_FILEPATH_LENGTH] = { 0 };
|
||||||
memset(path, 0, MAX_FILEPATH_LENGTH);
|
memset(path, 0, MAX_FILEPATH_LENGTH);
|
||||||
|
|
||||||
@ -4046,10 +4066,10 @@ static void RecordAutomationEvent(void)
|
|||||||
if (currentEventList->count == currentEventList->capacity) return; // Security check
|
if (currentEventList->count == currentEventList->capacity) return; // Security check
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int axis = 0; axis < MAX_GAMEPAD_AXIS; axis++)
|
for (int axis = 0; axis < MAX_GAMEPAD_AXES; axis++)
|
||||||
{
|
{
|
||||||
// Event type: INPUT_GAMEPAD_AXIS_MOTION
|
// Event type: INPUT_GAMEPAD_AXIS_MOTION
|
||||||
float defaultMovement = (axis == GAMEPAD_AXIS_LEFT_TRIGGER || axis == GAMEPAD_AXIS_RIGHT_TRIGGER)? -1.0f : 0.0f;
|
float defaultMovement = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f;
|
||||||
if (GetGamepadAxisMovement(gamepad, axis) != defaultMovement)
|
if (GetGamepadAxisMovement(gamepad, axis) != defaultMovement)
|
||||||
{
|
{
|
||||||
currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
|
currentEventList->events[currentEventList->count].frame = CORE.Time.frameCounter;
|
||||||
|
@ -56,8 +56,8 @@
|
|||||||
*
|
*
|
||||||
* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
|
* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
|
||||||
* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
|
* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
|
||||||
* #define RL_CULL_DISTANCE_NEAR 0.001 // Default projection matrix near cull distance
|
* #define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance
|
||||||
* #define RL_CULL_DISTANCE_FAR 10000.0 // Default projection matrix far cull distance
|
* #define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance
|
||||||
*
|
*
|
||||||
* When loading a shader, the following vertex attributes and uniform
|
* When loading a shader, the following vertex attributes and uniform
|
||||||
* location names are tried to be set automatically:
|
* location names are tried to be set automatically:
|
||||||
@ -234,10 +234,10 @@
|
|||||||
|
|
||||||
// Projection matrix culling
|
// Projection matrix culling
|
||||||
#ifndef RL_CULL_DISTANCE_NEAR
|
#ifndef RL_CULL_DISTANCE_NEAR
|
||||||
#define RL_CULL_DISTANCE_NEAR 0.001 // Default near cull distance
|
#define RL_CULL_DISTANCE_NEAR 0.05 // Default near cull distance
|
||||||
#endif
|
#endif
|
||||||
#ifndef RL_CULL_DISTANCE_FAR
|
#ifndef RL_CULL_DISTANCE_FAR
|
||||||
#define RL_CULL_DISTANCE_FAR 10000.0 // Default far cull distance
|
#define RL_CULL_DISTANCE_FAR 4000.0 // Default far cull distance
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Texture parameters (equivalent to OpenGL defines)
|
// Texture parameters (equivalent to OpenGL defines)
|
||||||
@ -1748,7 +1748,6 @@ void rlTextureParameters(unsigned int id, int param, int value)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else glTexParameteri(GL_TEXTURE_2D, param, value);
|
else glTexParameteri(GL_TEXTURE_2D, param, value);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case RL_TEXTURE_MAG_FILTER:
|
case RL_TEXTURE_MAG_FILTER:
|
||||||
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break;
|
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break;
|
||||||
@ -1793,7 +1792,6 @@ void rlCubemapParameters(unsigned int id, int param, int value)
|
|||||||
else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)");
|
else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)");
|
||||||
}
|
}
|
||||||
else glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value);
|
else glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case RL_TEXTURE_MAG_FILTER:
|
case RL_TEXTURE_MAG_FILTER:
|
||||||
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); break;
|
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); break;
|
||||||
@ -1887,7 +1885,7 @@ void rlActiveDrawBuffers(int count)
|
|||||||
|
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
if (count > 8) TRACELOG(LOG_WARNING, "GL: Max color buffers limited to 8");
|
if (count > 8) TRACELOG(RL_LOG_WARNING, "GL: Max color buffers limited to 8");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned int buffers[8] = {
|
unsigned int buffers[8] = {
|
||||||
@ -1904,7 +1902,7 @@ void rlActiveDrawBuffers(int count)
|
|||||||
glDrawBuffers(count, buffers);
|
glDrawBuffers(count, buffers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else TRACELOG(LOG_WARNING, "GL: One color buffer active by default");
|
else TRACELOG(RL_LOG_WARNING, "GL: One color buffer active by default");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2112,14 +2110,12 @@ void rlSetBlendMode(int mode)
|
|||||||
{
|
{
|
||||||
// NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactors()
|
// NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactors()
|
||||||
glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation);
|
glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case RL_BLEND_CUSTOM_SEPARATE:
|
case RL_BLEND_CUSTOM_SEPARATE:
|
||||||
{
|
{
|
||||||
// NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactorsSeparate()
|
// NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactorsSeparate()
|
||||||
glBlendFuncSeparate(RLGL.State.glBlendSrcFactorRGB, RLGL.State.glBlendDestFactorRGB, RLGL.State.glBlendSrcFactorAlpha, RLGL.State.glBlendDestFactorAlpha);
|
glBlendFuncSeparate(RLGL.State.glBlendSrcFactorRGB, RLGL.State.glBlendDestFactorRGB, RLGL.State.glBlendSrcFactorAlpha, RLGL.State.glBlendDestFactorAlpha);
|
||||||
glBlendEquationSeparate(RLGL.State.glBlendEquationRGB, RLGL.State.glBlendEquationAlpha);
|
glBlendEquationSeparate(RLGL.State.glBlendEquationRGB, RLGL.State.glBlendEquationAlpha);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@ -2223,10 +2219,10 @@ static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACELOG(LOG_WARNING, "GL: OpenGL debug message: %s", message);
|
TRACELOG(RL_LOG_WARNING, "GL: OpenGL debug message: %s", message);
|
||||||
TRACELOG(LOG_WARNING, " > Type: %s", msgType);
|
TRACELOG(RL_LOG_WARNING, " > Type: %s", msgType);
|
||||||
TRACELOG(LOG_WARNING, " > Source = %s", msgSource);
|
TRACELOG(RL_LOG_WARNING, " > Source = %s", msgSource);
|
||||||
TRACELOG(LOG_WARNING, " > Severity = %s", msgSeverity);
|
TRACELOG(RL_LOG_WARNING, " > Severity = %s", msgSeverity);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -2429,7 +2425,7 @@ void rlLoadExtensions(void *loader)
|
|||||||
|
|
||||||
// Get supported extensions list
|
// Get supported extensions list
|
||||||
GLint numExt = 0;
|
GLint numExt = 0;
|
||||||
const char **extList = RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
|
const char **extList = (const char **)RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
|
||||||
const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
|
const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string
|
||||||
|
|
||||||
// NOTE: We have to duplicate string because glGetString() returns a const string
|
// NOTE: We have to duplicate string because glGetString() returns a const string
|
||||||
@ -3747,19 +3743,16 @@ void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType,
|
|||||||
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_2D, texId, mipLevel);
|
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_2D, texId, mipLevel);
|
||||||
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_RENDERBUFFER, texId);
|
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_RENDERBUFFER, texId);
|
||||||
else if (texType >= RL_ATTACHMENT_CUBEMAP_POSITIVE_X) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_CUBE_MAP_POSITIVE_X + texType, texId, mipLevel);
|
else if (texType >= RL_ATTACHMENT_CUBEMAP_POSITIVE_X) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_CUBE_MAP_POSITIVE_X + texType, texId, mipLevel);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case RL_ATTACHMENT_DEPTH:
|
case RL_ATTACHMENT_DEPTH:
|
||||||
{
|
{
|
||||||
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
|
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
|
||||||
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, texId);
|
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, texId);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case RL_ATTACHMENT_STENCIL:
|
case RL_ATTACHMENT_STENCIL:
|
||||||
{
|
{
|
||||||
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
|
if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel);
|
||||||
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, texId);
|
else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, texId);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@ -4185,6 +4178,9 @@ unsigned int rlCompileShader(const char *shaderCode, int type)
|
|||||||
RL_FREE(log);
|
RL_FREE(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unload object allocated by glCreateShader(),
|
||||||
|
// despite failing in the compilation process
|
||||||
|
glDeleteShader(shader);
|
||||||
shader = 0;
|
shader = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -496,12 +496,18 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
|
|||||||
vertices[2] = (Vector3){ cosslice*vertices[2].x - sinslice*vertices[2].z, vertices[2].y, sinslice*vertices[2].x + cosslice*vertices[2].z }; // Rotation matrix around y axis
|
vertices[2] = (Vector3){ cosslice*vertices[2].x - sinslice*vertices[2].z, vertices[2].y, sinslice*vertices[2].x + cosslice*vertices[2].z }; // Rotation matrix around y axis
|
||||||
vertices[3] = (Vector3){ cosslice*vertices[3].x - sinslice*vertices[3].z, vertices[3].y, sinslice*vertices[3].x + cosslice*vertices[3].z };
|
vertices[3] = (Vector3){ cosslice*vertices[3].x - sinslice*vertices[3].z, vertices[3].y, sinslice*vertices[3].x + cosslice*vertices[3].z };
|
||||||
|
|
||||||
|
rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||||
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||||
|
rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||||
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||||
|
rlNormal3f(vertices[1].x, vertices[1].y, vertices[1].z);
|
||||||
rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
|
rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
|
||||||
|
|
||||||
|
rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||||
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||||
|
rlNormal3f(vertices[2].x, vertices[2].y, vertices[2].z);
|
||||||
rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
|
rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
|
||||||
|
rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||||
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1423,9 +1429,13 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
|||||||
|
|
||||||
rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
|
rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
|
||||||
|
|
||||||
rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
|
if (mesh.animVertices) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animVertices);
|
||||||
|
else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
|
||||||
|
|
||||||
rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
|
rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
|
||||||
rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
|
if (mesh.normals) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animNormals);
|
||||||
|
else rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
|
||||||
|
|
||||||
rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
|
rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
|
||||||
|
|
||||||
rlPushMatrix();
|
rlPushMatrix();
|
||||||
@ -2164,7 +2174,7 @@ Material *LoadMaterials(const char *fileName, int *materialCount)
|
|||||||
int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
|
int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
|
||||||
if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
|
if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
|
||||||
|
|
||||||
materials = RL_MALLOC(count*sizeof(Material));
|
materials = (Material *)RL_MALLOC(count*sizeof(Material));
|
||||||
ProcessMaterialsOBJ(materials, mats, count);
|
ProcessMaterialsOBJ(materials, mats, count);
|
||||||
|
|
||||||
tinyobj_materials_free(mats, count);
|
tinyobj_materials_free(mats, count);
|
||||||
@ -3598,16 +3608,16 @@ BoundingBox GetMeshBoundingBox(Mesh mesh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute mesh tangents
|
// Compute mesh tangents
|
||||||
// NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates
|
|
||||||
// Implementation based on: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
|
|
||||||
void GenMeshTangents(Mesh *mesh)
|
void GenMeshTangents(Mesh *mesh)
|
||||||
{
|
{
|
||||||
if ((mesh->vertices == NULL) || (mesh->texcoords == NULL))
|
// Check if input mesh data is useful
|
||||||
|
if ((mesh == NULL) || (mesh->vertices == NULL) || (mesh->texcoords == NULL) || (mesh->normals == NULL))
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "MESH: Tangents generation requires texcoord vertex attribute data");
|
TRACELOG(LOG_WARNING, "MESH: Tangents generation requires vertices, texcoords and normals vertex attribute data");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocate or reallocate tangents data
|
||||||
if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
|
if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3615,26 +3625,51 @@ void GenMeshTangents(Mesh *mesh)
|
|||||||
mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
|
mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
|
// Allocate temporary arrays for tangents calculation
|
||||||
Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
|
Vector3 *tan1 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
|
||||||
|
Vector3 *tan2 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
|
||||||
|
|
||||||
if (mesh->vertexCount % 3 != 0)
|
if (tan1 == NULL || tan2 == NULL)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "MESH: vertexCount expected to be a multiple of 3. Expect uninitialized values.");
|
TRACELOG(LOG_WARNING, "MESH: Failed to allocate temporary memory for tangent calculation");
|
||||||
|
if (tan1) RL_FREE(tan1);
|
||||||
|
if (tan2) RL_FREE(tan2);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i <= mesh->vertexCount - 3; i += 3)
|
// Process all triangles of the mesh
|
||||||
|
// 'triangleCount' must be always valid
|
||||||
|
for (int t = 0; t < mesh->triangleCount; t++)
|
||||||
{
|
{
|
||||||
// Get triangle vertices
|
// Get triangle vertex indices
|
||||||
Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] };
|
int i0, i1, i2;
|
||||||
Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] };
|
|
||||||
Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] };
|
if (mesh->indices != NULL)
|
||||||
|
{
|
||||||
|
// Use indices if available
|
||||||
|
i0 = mesh->indices[t*3 + 0];
|
||||||
|
i1 = mesh->indices[t*3 + 1];
|
||||||
|
i2 = mesh->indices[t*3 + 2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Sequential access for non-indexed mesh
|
||||||
|
i0 = t*3 + 0;
|
||||||
|
i1 = t*3 + 1;
|
||||||
|
i2 = t*3 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get triangle vertices position
|
||||||
|
Vector3 v1 = { mesh->vertices[i0*3 + 0], mesh->vertices[i0*3 + 1], mesh->vertices[i0*3 + 2] };
|
||||||
|
Vector3 v2 = { mesh->vertices[i1*3 + 0], mesh->vertices[i1*3 + 1], mesh->vertices[i1*3 + 2] };
|
||||||
|
Vector3 v3 = { mesh->vertices[i2*3 + 0], mesh->vertices[i2*3 + 1], mesh->vertices[i2*3 + 2] };
|
||||||
|
|
||||||
// Get triangle texcoords
|
// Get triangle texcoords
|
||||||
Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] };
|
Vector2 uv1 = { mesh->texcoords[i0*2 + 0], mesh->texcoords[i0*2 + 1] };
|
||||||
Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] };
|
Vector2 uv2 = { mesh->texcoords[i1*2 + 0], mesh->texcoords[i1*2 + 1] };
|
||||||
Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] };
|
Vector2 uv3 = { mesh->texcoords[i2*2 + 0], mesh->texcoords[i2*2 + 1] };
|
||||||
|
|
||||||
|
// Calculate triangle edges
|
||||||
float x1 = v2.x - v1.x;
|
float x1 = v2.x - v1.x;
|
||||||
float y1 = v2.y - v1.y;
|
float y1 = v2.y - v1.y;
|
||||||
float z1 = v2.z - v1.z;
|
float z1 = v2.z - v1.z;
|
||||||
@ -3642,65 +3677,95 @@ void GenMeshTangents(Mesh *mesh)
|
|||||||
float y2 = v3.y - v1.y;
|
float y2 = v3.y - v1.y;
|
||||||
float z2 = v3.z - v1.z;
|
float z2 = v3.z - v1.z;
|
||||||
|
|
||||||
|
// Calculate texture coordinate differences
|
||||||
float s1 = uv2.x - uv1.x;
|
float s1 = uv2.x - uv1.x;
|
||||||
float t1 = uv2.y - uv1.y;
|
float t1 = uv2.y - uv1.y;
|
||||||
float s2 = uv3.x - uv1.x;
|
float s2 = uv3.x - uv1.x;
|
||||||
float t2 = uv3.y - uv1.y;
|
float t2 = uv3.y - uv1.y;
|
||||||
|
|
||||||
|
// Calculate denominator and check for degenerate UV
|
||||||
float div = s1*t2 - s2*t1;
|
float div = s1*t2 - s2*t1;
|
||||||
float r = (div == 0.0f)? 0.0f : 1.0f/div;
|
float r = (fabsf(div) < 0.0001f)? 0.0f : 1.0f/div;
|
||||||
|
|
||||||
|
// Calculate tangent and bitangent directions
|
||||||
Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
|
Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
|
||||||
Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
|
Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
|
||||||
|
|
||||||
tan1[i + 0] = sdir;
|
// Accumulate tangents and bitangents for each vertex of the triangle
|
||||||
tan1[i + 1] = sdir;
|
tan1[i0] = Vector3Add(tan1[i0], sdir);
|
||||||
tan1[i + 2] = sdir;
|
tan1[i1] = Vector3Add(tan1[i1], sdir);
|
||||||
|
tan1[i2] = Vector3Add(tan1[i2], sdir);
|
||||||
|
|
||||||
tan2[i + 0] = tdir;
|
tan2[i0] = Vector3Add(tan2[i0], tdir);
|
||||||
tan2[i + 1] = tdir;
|
tan2[i1] = Vector3Add(tan2[i1], tdir);
|
||||||
tan2[i + 2] = tdir;
|
tan2[i2] = Vector3Add(tan2[i2], tdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute tangents considering normals
|
// Calculate final tangents for each vertex
|
||||||
for (int i = 0; i < mesh->vertexCount; i++)
|
for (int i = 0; i < mesh->vertexCount; i++)
|
||||||
{
|
{
|
||||||
Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
|
Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
|
||||||
Vector3 tangent = tan1[i];
|
Vector3 tangent = tan1[i];
|
||||||
|
|
||||||
// TODO: Review, not sure if tangent computation is right, just used reference proposed maths...
|
// Handle zero tangent (can happen with degenerate UVs)
|
||||||
#if defined(COMPUTE_TANGENTS_METHOD_01)
|
if (Vector3Length(tangent) < 0.0001f)
|
||||||
Vector3 tmp = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
|
{
|
||||||
tmp = Vector3Normalize(tmp);
|
// Create a tangent perpendicular to the normal
|
||||||
mesh->tangents[i*4 + 0] = tmp.x;
|
if (fabsf(normal.z) > 0.707f) tangent = (Vector3){ 1.0f, 0.0f, 0.0f };
|
||||||
mesh->tangents[i*4 + 1] = tmp.y;
|
else tangent = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
|
||||||
mesh->tangents[i*4 + 2] = tmp.z;
|
|
||||||
mesh->tangents[i*4 + 3] = 1.0f;
|
|
||||||
#else
|
|
||||||
Vector3OrthoNormalize(&normal, &tangent);
|
|
||||||
mesh->tangents[i*4 + 0] = tangent.x;
|
mesh->tangents[i*4 + 0] = tangent.x;
|
||||||
mesh->tangents[i*4 + 1] = tangent.y;
|
mesh->tangents[i*4 + 1] = tangent.y;
|
||||||
mesh->tangents[i*4 + 2] = tangent.z;
|
mesh->tangents[i*4 + 2] = tangent.z;
|
||||||
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f;
|
mesh->tangents[i*4 + 3] = 1.0f;
|
||||||
#endif
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gram-Schmidt orthogonalization to make tangent orthogonal to normal
|
||||||
|
// T_prime = T - N * dot(N, T)
|
||||||
|
Vector3 orthogonalized = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
|
||||||
|
|
||||||
|
// Handle cases where orthogonalized vector is too small
|
||||||
|
if (Vector3Length(orthogonalized) < 0.0001f)
|
||||||
|
{
|
||||||
|
// Create a tangent perpendicular to the normal
|
||||||
|
if (fabsf(normal.z) > 0.707f) orthogonalized = (Vector3){ 1.0f, 0.0f, 0.0f };
|
||||||
|
else orthogonalized = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Normalize the orthogonalized tangent
|
||||||
|
orthogonalized = Vector3Normalize(orthogonalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the calculated tangent
|
||||||
|
mesh->tangents[i*4 + 0] = orthogonalized.x;
|
||||||
|
mesh->tangents[i*4 + 1] = orthogonalized.y;
|
||||||
|
mesh->tangents[i*4 + 2] = orthogonalized.z;
|
||||||
|
|
||||||
|
// Calculate the handedness (w component)
|
||||||
|
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, orthogonalized), tan2[i]) < 0.0f)? -1.0f : 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free temporary arrays
|
||||||
RL_FREE(tan1);
|
RL_FREE(tan1);
|
||||||
RL_FREE(tan2);
|
RL_FREE(tan2);
|
||||||
|
|
||||||
|
// Update vertex buffers if available
|
||||||
if (mesh->vboId != NULL)
|
if (mesh->vboId != NULL)
|
||||||
{
|
{
|
||||||
if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0)
|
if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0)
|
||||||
{
|
{
|
||||||
// Update existing vertex buffer
|
// Update existing tangent vertex buffer
|
||||||
rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0);
|
rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Load a new tangent attributes buffer
|
// Create new tangent vertex buffer
|
||||||
mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
|
mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up vertex attributes for shader
|
||||||
rlEnableVertexArray(mesh->vaoId);
|
rlEnableVertexArray(mesh->vaoId);
|
||||||
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
|
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
|
||||||
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
|
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
|
||||||
@ -4577,13 +4642,13 @@ static Model LoadIQM(const char *fileName)
|
|||||||
//fileDataPtr += sizeof(IQMHeader); // Move file data pointer
|
//fileDataPtr += sizeof(IQMHeader); // Move file data pointer
|
||||||
|
|
||||||
// Meshes data processing
|
// Meshes data processing
|
||||||
imesh = RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
|
imesh = (IQMMesh *)RL_MALLOC(iqmHeader->num_meshes*sizeof(IQMMesh));
|
||||||
//fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_meshes, SEEK_SET);
|
||||||
//fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
|
//fread(imesh, sizeof(IQMMesh)*iqmHeader->num_meshes, 1, iqmFile);
|
||||||
memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
|
memcpy(imesh, fileDataPtr + iqmHeader->ofs_meshes, iqmHeader->num_meshes*sizeof(IQMMesh));
|
||||||
|
|
||||||
model.meshCount = iqmHeader->num_meshes;
|
model.meshCount = iqmHeader->num_meshes;
|
||||||
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
|
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||||
|
|
||||||
model.materialCount = model.meshCount;
|
model.materialCount = model.meshCount;
|
||||||
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
|
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
|
||||||
@ -4611,24 +4676,24 @@ static Model LoadIQM(const char *fileName)
|
|||||||
|
|
||||||
model.meshes[i].vertexCount = imesh[i].num_vertexes;
|
model.meshes[i].vertexCount = imesh[i].num_vertexes;
|
||||||
|
|
||||||
model.meshes[i].vertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions
|
model.meshes[i].vertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex positions
|
||||||
model.meshes[i].normals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals
|
model.meshes[i].normals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float)); // Default vertex normals
|
||||||
model.meshes[i].texcoords = RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords
|
model.meshes[i].texcoords = (float *)RL_CALLOC(model.meshes[i].vertexCount*2, sizeof(float)); // Default vertex texcoords
|
||||||
|
|
||||||
model.meshes[i].boneIds = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char)); // Up-to 4 bones supported!
|
model.meshes[i].boneIds = (unsigned char *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(unsigned char)); // Up-to 4 bones supported!
|
||||||
model.meshes[i].boneWeights = RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported!
|
model.meshes[i].boneWeights = (float *)RL_CALLOC(model.meshes[i].vertexCount*4, sizeof(float)); // Up-to 4 bones supported!
|
||||||
|
|
||||||
model.meshes[i].triangleCount = imesh[i].num_triangles;
|
model.meshes[i].triangleCount = imesh[i].num_triangles;
|
||||||
model.meshes[i].indices = RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
|
model.meshes[i].indices = (unsigned short *)RL_CALLOC(model.meshes[i].triangleCount*3, sizeof(unsigned short));
|
||||||
|
|
||||||
// Animated vertex data, what we actually process for rendering
|
// Animated vertex data, what we actually process for rendering
|
||||||
// NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
|
// NOTE: Animated vertex should be re-uploaded to GPU (if not using GPU skinning)
|
||||||
model.meshes[i].animVertices = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
model.meshes[i].animVertices = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||||
model.meshes[i].animNormals = RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
model.meshes[i].animNormals = (float *)RL_CALLOC(model.meshes[i].vertexCount*3, sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Triangles data processing
|
// Triangles data processing
|
||||||
tri = RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
|
tri = (IQMTriangle *)RL_MALLOC(iqmHeader->num_triangles*sizeof(IQMTriangle));
|
||||||
//fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_triangles, SEEK_SET);
|
||||||
//fread(tri, sizeof(IQMTriangle), iqmHeader->num_triangles, iqmFile);
|
//fread(tri, sizeof(IQMTriangle), iqmHeader->num_triangles, iqmFile);
|
||||||
memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle));
|
memcpy(tri, fileDataPtr + iqmHeader->ofs_triangles, iqmHeader->num_triangles*sizeof(IQMTriangle));
|
||||||
@ -4650,7 +4715,7 @@ static Model LoadIQM(const char *fileName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Vertex arrays data processing
|
// Vertex arrays data processing
|
||||||
va = RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
va = (IQMVertexArray *)RL_MALLOC(iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
||||||
//fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_vertexarrays, SEEK_SET);
|
||||||
//fread(va, sizeof(IQMVertexArray), iqmHeader->num_vertexarrays, iqmFile);
|
//fread(va, sizeof(IQMVertexArray), iqmHeader->num_vertexarrays, iqmFile);
|
||||||
memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
memcpy(va, fileDataPtr + iqmHeader->ofs_vertexarrays, iqmHeader->num_vertexarrays*sizeof(IQMVertexArray));
|
||||||
@ -4661,7 +4726,7 @@ static Model LoadIQM(const char *fileName)
|
|||||||
{
|
{
|
||||||
case IQM_POSITION:
|
case IQM_POSITION:
|
||||||
{
|
{
|
||||||
vertex = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
vertex = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
//fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
|
//fread(vertex, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
|
||||||
memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
|
memcpy(vertex, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
|
||||||
@ -4679,7 +4744,7 @@ static Model LoadIQM(const char *fileName)
|
|||||||
} break;
|
} break;
|
||||||
case IQM_NORMAL:
|
case IQM_NORMAL:
|
||||||
{
|
{
|
||||||
normal = RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
normal = (float *)RL_MALLOC(iqmHeader->num_vertexes*3*sizeof(float));
|
||||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
//fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
|
//fread(normal, iqmHeader->num_vertexes*3*sizeof(float), 1, iqmFile);
|
||||||
memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
|
memcpy(normal, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*3*sizeof(float));
|
||||||
@ -4697,7 +4762,7 @@ static Model LoadIQM(const char *fileName)
|
|||||||
} break;
|
} break;
|
||||||
case IQM_TEXCOORD:
|
case IQM_TEXCOORD:
|
||||||
{
|
{
|
||||||
text = RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
|
text = (float *)RL_MALLOC(iqmHeader->num_vertexes*2*sizeof(float));
|
||||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
//fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile);
|
//fread(text, iqmHeader->num_vertexes*2*sizeof(float), 1, iqmFile);
|
||||||
memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float));
|
memcpy(text, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*2*sizeof(float));
|
||||||
@ -4714,7 +4779,7 @@ static Model LoadIQM(const char *fileName)
|
|||||||
} break;
|
} break;
|
||||||
case IQM_BLENDINDEXES:
|
case IQM_BLENDINDEXES:
|
||||||
{
|
{
|
||||||
blendi = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
|
blendi = (char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(char));
|
||||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
//fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile);
|
//fread(blendi, iqmHeader->num_vertexes*4*sizeof(char), 1, iqmFile);
|
||||||
memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char));
|
memcpy(blendi, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(char));
|
||||||
@ -4731,7 +4796,7 @@ static Model LoadIQM(const char *fileName)
|
|||||||
} break;
|
} break;
|
||||||
case IQM_BLENDWEIGHTS:
|
case IQM_BLENDWEIGHTS:
|
||||||
{
|
{
|
||||||
blendw = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
blendw = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
//fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
|
//fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
|
||||||
memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
memcpy(blendw, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||||
@ -4748,14 +4813,14 @@ static Model LoadIQM(const char *fileName)
|
|||||||
} break;
|
} break;
|
||||||
case IQM_COLOR:
|
case IQM_COLOR:
|
||||||
{
|
{
|
||||||
color = RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
color = (unsigned char *)RL_MALLOC(iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||||
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
//fseek(iqmFile, va[i].offset, SEEK_SET);
|
||||||
//fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
|
//fread(blendw, iqmHeader->num_vertexes*4*sizeof(unsigned char), 1, iqmFile);
|
||||||
memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
memcpy(color, fileDataPtr + va[i].offset, iqmHeader->num_vertexes*4*sizeof(unsigned char));
|
||||||
|
|
||||||
for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
|
for (unsigned int m = 0; m < iqmHeader->num_meshes; m++)
|
||||||
{
|
{
|
||||||
model.meshes[m].colors = RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
|
model.meshes[m].colors = (unsigned char *)RL_CALLOC(model.meshes[m].vertexCount*4, sizeof(unsigned char));
|
||||||
|
|
||||||
int vCounter = 0;
|
int vCounter = 0;
|
||||||
for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
|
for (unsigned int i = imesh[m].first_vertex*4; i < (imesh[m].first_vertex + imesh[m].num_vertexes)*4; i++)
|
||||||
@ -4769,14 +4834,14 @@ static Model LoadIQM(const char *fileName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bones (joints) data processing
|
// Bones (joints) data processing
|
||||||
ijoint = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
ijoint = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||||
//fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_joints, SEEK_SET);
|
||||||
//fread(ijoint, sizeof(IQMJoint), iqmHeader->num_joints, iqmFile);
|
//fread(ijoint, sizeof(IQMJoint), iqmHeader->num_joints, iqmFile);
|
||||||
memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
|
memcpy(ijoint, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
|
||||||
|
|
||||||
model.boneCount = iqmHeader->num_joints;
|
model.boneCount = iqmHeader->num_joints;
|
||||||
model.bones = RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
|
model.bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_joints*sizeof(BoneInfo));
|
||||||
model.bindPose = RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
|
model.bindPose = (Transform *)RL_MALLOC(iqmHeader->num_joints*sizeof(Transform));
|
||||||
|
|
||||||
for (unsigned int i = 0; i < iqmHeader->num_joints; i++)
|
for (unsigned int i = 0; i < iqmHeader->num_joints; i++)
|
||||||
{
|
{
|
||||||
@ -4806,7 +4871,7 @@ static Model LoadIQM(const char *fileName)
|
|||||||
for (int i = 0; i < model.meshCount; i++)
|
for (int i = 0; i < model.meshCount; i++)
|
||||||
{
|
{
|
||||||
model.meshes[i].boneCount = model.boneCount;
|
model.meshes[i].boneCount = model.boneCount;
|
||||||
model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
model.meshes[i].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
||||||
|
|
||||||
for (int j = 0; j < model.meshes[i].boneCount; j++)
|
for (int j = 0; j < model.meshes[i].boneCount; j++)
|
||||||
{
|
{
|
||||||
@ -4898,36 +4963,36 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get bones data
|
// Get bones data
|
||||||
IQMPose *poses = RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
|
IQMPose *poses = (IQMPose *)RL_MALLOC(iqmHeader->num_poses*sizeof(IQMPose));
|
||||||
//fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_poses, SEEK_SET);
|
||||||
//fread(poses, sizeof(IQMPose), iqmHeader->num_poses, iqmFile);
|
//fread(poses, sizeof(IQMPose), iqmHeader->num_poses, iqmFile);
|
||||||
memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
|
memcpy(poses, fileDataPtr + iqmHeader->ofs_poses, iqmHeader->num_poses*sizeof(IQMPose));
|
||||||
|
|
||||||
// Get animations data
|
// Get animations data
|
||||||
*animCount = iqmHeader->num_anims;
|
*animCount = iqmHeader->num_anims;
|
||||||
IQMAnim *anim = RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
|
IQMAnim *anim = (IQMAnim *)RL_MALLOC(iqmHeader->num_anims*sizeof(IQMAnim));
|
||||||
//fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_anims, SEEK_SET);
|
||||||
//fread(anim, sizeof(IQMAnim), iqmHeader->num_anims, iqmFile);
|
//fread(anim, sizeof(IQMAnim), iqmHeader->num_anims, iqmFile);
|
||||||
memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
|
memcpy(anim, fileDataPtr + iqmHeader->ofs_anims, iqmHeader->num_anims*sizeof(IQMAnim));
|
||||||
|
|
||||||
ModelAnimation *animations = RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
|
ModelAnimation *animations = (ModelAnimation *)RL_MALLOC(iqmHeader->num_anims*sizeof(ModelAnimation));
|
||||||
|
|
||||||
// frameposes
|
// frameposes
|
||||||
unsigned short *framedata = RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
unsigned short *framedata = (unsigned short *)RL_MALLOC(iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
||||||
//fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
|
//fseek(iqmFile, iqmHeader->ofs_frames, SEEK_SET);
|
||||||
//fread(framedata, sizeof(unsigned short), iqmHeader->num_frames*iqmHeader->num_framechannels, iqmFile);
|
//fread(framedata, sizeof(unsigned short), iqmHeader->num_frames*iqmHeader->num_framechannels, iqmFile);
|
||||||
memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
memcpy(framedata, fileDataPtr + iqmHeader->ofs_frames, iqmHeader->num_frames*iqmHeader->num_framechannels*sizeof(unsigned short));
|
||||||
|
|
||||||
// joints
|
// joints
|
||||||
IQMJoint *joints = RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
IQMJoint *joints = (IQMJoint *)RL_MALLOC(iqmHeader->num_joints*sizeof(IQMJoint));
|
||||||
memcpy(joints, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
|
memcpy(joints, fileDataPtr + iqmHeader->ofs_joints, iqmHeader->num_joints*sizeof(IQMJoint));
|
||||||
|
|
||||||
for (unsigned int a = 0; a < iqmHeader->num_anims; a++)
|
for (unsigned int a = 0; a < iqmHeader->num_anims; a++)
|
||||||
{
|
{
|
||||||
animations[a].frameCount = anim[a].num_frames;
|
animations[a].frameCount = anim[a].num_frames;
|
||||||
animations[a].boneCount = iqmHeader->num_poses;
|
animations[a].boneCount = iqmHeader->num_poses;
|
||||||
animations[a].bones = RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
|
animations[a].bones = (BoneInfo *)RL_MALLOC(iqmHeader->num_poses*sizeof(BoneInfo));
|
||||||
animations[a].framePoses = RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
|
animations[a].framePoses = (Transform **)RL_MALLOC(anim[a].num_frames*sizeof(Transform *));
|
||||||
memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32); // I don't like this 32 here
|
memcpy(animations[a].name, fileDataPtr + iqmHeader->ofs_text + anim[a].name, 32); // I don't like this 32 here
|
||||||
TraceLog(LOG_INFO, "IQM Anim %s", animations[a].name);
|
TraceLog(LOG_INFO, "IQM Anim %s", animations[a].name);
|
||||||
// animations[a].framerate = anim.framerate; // TODO: Use animation framerate data?
|
// animations[a].framerate = anim.framerate; // TODO: Use animation framerate data?
|
||||||
@ -4942,7 +5007,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou
|
|||||||
animations[a].bones[j].parent = poses[j].parent;
|
animations[a].bones[j].parent = poses[j].parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
|
for (unsigned int j = 0; j < anim[a].num_frames; j++) animations[a].framePoses[j] = (Transform *)RL_MALLOC(iqmHeader->num_poses*sizeof(Transform));
|
||||||
|
|
||||||
int dcounter = anim[a].first_frame*iqmHeader->num_framechannels;
|
int dcounter = anim[a].first_frame*iqmHeader->num_framechannels;
|
||||||
|
|
||||||
@ -5133,7 +5198,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
|
|||||||
}
|
}
|
||||||
else if ((cgltfImage->buffer_view != NULL) && (cgltfImage->buffer_view->buffer->data != NULL)) // Check if image is provided as data buffer
|
else if ((cgltfImage->buffer_view != NULL) && (cgltfImage->buffer_view->buffer->data != NULL)) // Check if image is provided as data buffer
|
||||||
{
|
{
|
||||||
unsigned char *data = RL_MALLOC(cgltfImage->buffer_view->size);
|
unsigned char *data = (unsigned char *)RL_MALLOC(cgltfImage->buffer_view->size);
|
||||||
int offset = (int)cgltfImage->buffer_view->offset;
|
int offset = (int)cgltfImage->buffer_view->offset;
|
||||||
int stride = (int)cgltfImage->buffer_view->stride? (int)cgltfImage->buffer_view->stride : 1;
|
int stride = (int)cgltfImage->buffer_view->stride? (int)cgltfImage->buffer_view->stride : 1;
|
||||||
|
|
||||||
@ -5166,16 +5231,12 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat
|
|||||||
static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount)
|
static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount)
|
||||||
{
|
{
|
||||||
*boneCount = (int)skin.joints_count;
|
*boneCount = (int)skin.joints_count;
|
||||||
BoneInfo *bones = RL_MALLOC(skin.joints_count*sizeof(BoneInfo));
|
BoneInfo *bones = (BoneInfo *)RL_CALLOC(skin.joints_count, sizeof(BoneInfo));
|
||||||
|
|
||||||
for (unsigned int i = 0; i < skin.joints_count; i++)
|
for (unsigned int i = 0; i < skin.joints_count; i++)
|
||||||
{
|
{
|
||||||
cgltf_node node = *skin.joints[i];
|
cgltf_node node = *skin.joints[i];
|
||||||
if (node.name != NULL)
|
if (node.name != NULL) strncpy(bones[i].name, node.name, sizeof(bones[i].name) - 1);
|
||||||
{
|
|
||||||
strncpy(bones[i].name, node.name, sizeof(bones[i].name));
|
|
||||||
bones[i].name[sizeof(bones[i].name) - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find parent bone index
|
// Find parent bone index
|
||||||
int parentIndex = -1;
|
int parentIndex = -1;
|
||||||
@ -5201,7 +5262,7 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
/*********************************************************************************************
|
/*********************************************************************************************
|
||||||
|
|
||||||
Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
|
Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
|
||||||
Transform handling implemented by Paul Melis (@paulmelis).
|
Transform handling implemented by Paul Melis (@paulmelis)
|
||||||
Reviewed by Ramon Santamaria (@raysan5)
|
Reviewed by Ramon Santamaria (@raysan5)
|
||||||
|
|
||||||
FEATURES:
|
FEATURES:
|
||||||
@ -5211,10 +5272,10 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
PBR specular/glossiness flow and extended texture flows not supported
|
PBR specular/glossiness flow and extended texture flows not supported
|
||||||
- Supports multiple meshes per model (every primitives is loaded as a separate mesh)
|
- Supports multiple meshes per model (every primitives is loaded as a separate mesh)
|
||||||
- Supports basic animations
|
- Supports basic animations
|
||||||
- Transforms, including parent-child relations, are applied on the mesh data, but the
|
- Transforms, including parent-child relations, are applied on the mesh data,
|
||||||
hierarchy is not kept (as it can't be represented).
|
but the hierarchy is not kept (as it can't be represented)
|
||||||
- Mesh instances in the glTF file (i.e. same mesh linked from multiple nodes)
|
- Mesh instances in the glTF file (i.e. same mesh linked from multiple nodes)
|
||||||
are turned into separate raylib Meshes.
|
are turned into separate raylib Meshes
|
||||||
|
|
||||||
RESTRICTIONS:
|
RESTRICTIONS:
|
||||||
- Only triangle meshes supported
|
- Only triangle meshes supported
|
||||||
@ -5297,15 +5358,15 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
|
|
||||||
// Load our model data: meshes and materials
|
// Load our model data: meshes and materials
|
||||||
model.meshCount = primitivesCount;
|
model.meshCount = primitivesCount;
|
||||||
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
|
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||||
|
|
||||||
// NOTE: We keep an extra slot for default material, in case some mesh requires it
|
// NOTE: We keep an extra slot for default material, in case some mesh requires it
|
||||||
model.materialCount = (int)data->materials_count + 1;
|
model.materialCount = (int)data->materials_count + 1;
|
||||||
model.materials = RL_CALLOC(model.materialCount, sizeof(Material));
|
model.materials = (Material *)RL_CALLOC(model.materialCount, sizeof(Material));
|
||||||
model.materials[0] = LoadMaterialDefault(); // Load default material (index: 0)
|
model.materials[0] = LoadMaterialDefault(); // Load default material (index: 0)
|
||||||
|
|
||||||
// Load mesh-material indices, by default all meshes are mapped to material index: 0
|
// Load mesh-material indices, by default all meshes are mapped to material index: 0
|
||||||
model.meshMaterial = RL_CALLOC(model.meshCount, sizeof(int));
|
model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
|
||||||
|
|
||||||
// Load materials data
|
// Load materials data
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
@ -5430,7 +5491,7 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
// Any glTF mesh linked from more than one Node (i.e. instancing)
|
// Any glTF mesh linked from more than one Node (i.e. instancing)
|
||||||
// is turned into multiple Mesh's, as each Node will have its own
|
// is turned into multiple Mesh's, as each Node will have its own
|
||||||
// transform applied.
|
// transform applied.
|
||||||
// Note: the code below disregards the scenes defined in the file, all nodes are used.
|
// NOTE: The code below disregards the scenes defined in the file, all nodes are used.
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
int meshIndex = 0;
|
int meshIndex = 0;
|
||||||
for (unsigned int i = 0; i < data->nodes_count; i++)
|
for (unsigned int i = 0; i < data->nodes_count; i++)
|
||||||
@ -5475,7 +5536,7 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
{
|
{
|
||||||
// Init raylib mesh vertices to copy glTF attribute data
|
// Init raylib mesh vertices to copy glTF attribute data
|
||||||
model.meshes[meshIndex].vertexCount = (int)attribute->count;
|
model.meshes[meshIndex].vertexCount = (int)attribute->count;
|
||||||
model.meshes[meshIndex].vertices = RL_MALLOC(attribute->count*3*sizeof(float));
|
model.meshes[meshIndex].vertices = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
|
||||||
|
|
||||||
// Load 3 components of float data type into mesh.vertices
|
// Load 3 components of float data type into mesh.vertices
|
||||||
LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].vertices)
|
LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].vertices)
|
||||||
@ -5499,7 +5560,7 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f))
|
if ((attribute->type == cgltf_type_vec3) && (attribute->component_type == cgltf_component_type_r_32f))
|
||||||
{
|
{
|
||||||
// Init raylib mesh normals to copy glTF attribute data
|
// Init raylib mesh normals to copy glTF attribute data
|
||||||
model.meshes[meshIndex].normals = RL_MALLOC(attribute->count*3*sizeof(float));
|
model.meshes[meshIndex].normals = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
|
||||||
|
|
||||||
// Load 3 components of float data type into mesh.normals
|
// Load 3 components of float data type into mesh.normals
|
||||||
LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].normals)
|
LOAD_ATTRIBUTE(attribute, 3, float, model.meshes[meshIndex].normals)
|
||||||
@ -5516,14 +5577,14 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
}
|
}
|
||||||
else TRACELOG(LOG_WARNING, "MODEL: [%s] Normal attribute data format not supported, use vec3 float", fileName);
|
else TRACELOG(LOG_WARNING, "MODEL: [%s] Normal attribute data format not supported, use vec3 float", fileName);
|
||||||
}
|
}
|
||||||
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_tangent) // TANGENT, vec3, float
|
else if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_tangent) // TANGENT, vec4, float, w is tangent basis sign
|
||||||
{
|
{
|
||||||
cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
|
cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
|
||||||
|
|
||||||
if ((attribute->type == cgltf_type_vec4) && (attribute->component_type == cgltf_component_type_r_32f))
|
if ((attribute->type == cgltf_type_vec4) && (attribute->component_type == cgltf_component_type_r_32f))
|
||||||
{
|
{
|
||||||
// Init raylib mesh tangent to copy glTF attribute data
|
// Init raylib mesh tangent to copy glTF attribute data
|
||||||
model.meshes[meshIndex].tangents = RL_MALLOC(attribute->count*4*sizeof(float));
|
model.meshes[meshIndex].tangents = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
|
||||||
|
|
||||||
// Load 4 components of float data type into mesh.tangents
|
// Load 4 components of float data type into mesh.tangents
|
||||||
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].tangents)
|
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].tangents)
|
||||||
@ -5532,10 +5593,10 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
float *tangents = model.meshes[meshIndex].tangents;
|
float *tangents = model.meshes[meshIndex].tangents;
|
||||||
for (unsigned int k = 0; k < attribute->count; k++)
|
for (unsigned int k = 0; k < attribute->count; k++)
|
||||||
{
|
{
|
||||||
Vector3 tt = Vector3Transform((Vector3){ tangents[3*k], tangents[3*k+1], tangents[3*k+2] }, worldMatrix);
|
Vector3 tt = Vector3Transform((Vector3){ tangents[4*k], tangents[4*k+1], tangents[4*k+2] }, worldMatrix);
|
||||||
tangents[3*k] = tt.x;
|
tangents[4*k] = tt.x;
|
||||||
tangents[3*k+1] = tt.y;
|
tangents[4*k+1] = tt.y;
|
||||||
tangents[3*k+2] = tt.z;
|
tangents[4*k+2] = tt.z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else TRACELOG(LOG_WARNING, "MODEL: [%s] Tangent attribute data format not supported, use vec4 float", fileName);
|
else TRACELOG(LOG_WARNING, "MODEL: [%s] Tangent attribute data format not supported, use vec4 float", fileName);
|
||||||
@ -5609,10 +5670,10 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh color to copy glTF attribute data
|
// Init raylib mesh color to copy glTF attribute data
|
||||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||||
|
|
||||||
// Load data into a temp buffer to be converted to raylib data type
|
// Load data into a temp buffer to be converted to raylib data type
|
||||||
unsigned char *temp = RL_MALLOC(attribute->count*3*sizeof(unsigned char));
|
unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*3*sizeof(unsigned char));
|
||||||
LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp);
|
LOAD_ATTRIBUTE(attribute, 3, unsigned char, temp);
|
||||||
|
|
||||||
// Convert data to raylib color data type (4 bytes)
|
// Convert data to raylib color data type (4 bytes)
|
||||||
@ -5629,10 +5690,10 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh color to copy glTF attribute data
|
// Init raylib mesh color to copy glTF attribute data
|
||||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||||
|
|
||||||
// Load data into a temp buffer to be converted to raylib data type
|
// Load data into a temp buffer to be converted to raylib data type
|
||||||
unsigned short *temp = RL_MALLOC(attribute->count*3*sizeof(unsigned short));
|
unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*3*sizeof(unsigned short));
|
||||||
LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp);
|
LOAD_ATTRIBUTE(attribute, 3, unsigned short, temp);
|
||||||
|
|
||||||
// Convert data to raylib color data type (4 bytes)
|
// Convert data to raylib color data type (4 bytes)
|
||||||
@ -5649,10 +5710,10 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
else if (attribute->component_type == cgltf_component_type_r_32f)
|
else if (attribute->component_type == cgltf_component_type_r_32f)
|
||||||
{
|
{
|
||||||
// Init raylib mesh color to copy glTF attribute data
|
// Init raylib mesh color to copy glTF attribute data
|
||||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||||
|
|
||||||
// Load data into a temp buffer to be converted to raylib data type
|
// Load data into a temp buffer to be converted to raylib data type
|
||||||
float *temp = RL_MALLOC(attribute->count*3*sizeof(float));
|
float *temp = (float *)RL_MALLOC(attribute->count*3*sizeof(float));
|
||||||
LOAD_ATTRIBUTE(attribute, 3, float, temp);
|
LOAD_ATTRIBUTE(attribute, 3, float, temp);
|
||||||
|
|
||||||
// Convert data to raylib color data type (4 bytes)
|
// Convert data to raylib color data type (4 bytes)
|
||||||
@ -5673,7 +5734,7 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh color to copy glTF attribute data
|
// Init raylib mesh color to copy glTF attribute data
|
||||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||||
|
|
||||||
// Load 4 components of unsigned char data type into mesh.colors
|
// Load 4 components of unsigned char data type into mesh.colors
|
||||||
LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].colors)
|
LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].colors)
|
||||||
@ -5681,10 +5742,10 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh color to copy glTF attribute data
|
// Init raylib mesh color to copy glTF attribute data
|
||||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||||
|
|
||||||
// Load data into a temp buffer to be converted to raylib data type
|
// Load data into a temp buffer to be converted to raylib data type
|
||||||
unsigned short *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
||||||
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
||||||
|
|
||||||
// Convert data to raylib color data type (4 bytes)
|
// Convert data to raylib color data type (4 bytes)
|
||||||
@ -5695,10 +5756,10 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
else if (attribute->component_type == cgltf_component_type_r_32f)
|
else if (attribute->component_type == cgltf_component_type_r_32f)
|
||||||
{
|
{
|
||||||
// Init raylib mesh color to copy glTF attribute data
|
// Init raylib mesh color to copy glTF attribute data
|
||||||
model.meshes[meshIndex].colors = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
model.meshes[meshIndex].colors = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||||
|
|
||||||
// Load data into a temp buffer to be converted to raylib data type
|
// Load data into a temp buffer to be converted to raylib data type
|
||||||
float *temp = RL_MALLOC(attribute->count*4*sizeof(float));
|
float *temp = (float *)RL_MALLOC(attribute->count*4*sizeof(float));
|
||||||
LOAD_ATTRIBUTE(attribute, 4, float, temp);
|
LOAD_ATTRIBUTE(attribute, 4, float, temp);
|
||||||
|
|
||||||
// Convert data to raylib color data type (4 bytes), we expect the color data normalized
|
// Convert data to raylib color data type (4 bytes), we expect the color data normalized
|
||||||
@ -5724,7 +5785,7 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
if (attribute->component_type == cgltf_component_type_r_16u)
|
if (attribute->component_type == cgltf_component_type_r_16u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh indices to copy glTF attribute data
|
// Init raylib mesh indices to copy glTF attribute data
|
||||||
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
|
model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||||
|
|
||||||
// Load unsigned short data type into mesh.indices
|
// Load unsigned short data type into mesh.indices
|
||||||
LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices)
|
LOAD_ATTRIBUTE(attribute, 1, unsigned short, model.meshes[meshIndex].indices)
|
||||||
@ -5732,14 +5793,14 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
else if (attribute->component_type == cgltf_component_type_r_8u)
|
else if (attribute->component_type == cgltf_component_type_r_8u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh indices to copy glTF attribute data
|
// Init raylib mesh indices to copy glTF attribute data
|
||||||
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
|
model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||||
LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned char, model.meshes[meshIndex].indices, 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)
|
else if (attribute->component_type == cgltf_component_type_r_32u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh indices to copy glTF attribute data
|
// Init raylib mesh indices to copy glTF attribute data
|
||||||
model.meshes[meshIndex].indices = RL_MALLOC(attribute->count*sizeof(unsigned short));
|
model.meshes[meshIndex].indices = (unsigned short *)RL_MALLOC(attribute->count*sizeof(unsigned short));
|
||||||
LOAD_ATTRIBUTE_CAST(attribute, 1, unsigned int, model.meshes[meshIndex].indices, unsigned short);
|
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);
|
TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
|
||||||
@ -5783,7 +5844,7 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
{
|
{
|
||||||
cgltf_skin skin = data->skins[0];
|
cgltf_skin skin = data->skins[0];
|
||||||
model.bones = LoadBoneInfoGLTF(skin, &model.boneCount);
|
model.bones = LoadBoneInfoGLTF(skin, &model.boneCount);
|
||||||
model.bindPose = RL_MALLOC(model.boneCount*sizeof(Transform));
|
model.bindPose = (Transform *)RL_MALLOC(model.boneCount*sizeof(Transform));
|
||||||
|
|
||||||
for (int i = 0; i < model.boneCount; i++)
|
for (int i = 0; i < model.boneCount; i++)
|
||||||
{
|
{
|
||||||
@ -5815,15 +5876,17 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
|
|
||||||
for (unsigned int p = 0; p < mesh->primitives_count; p++)
|
for (unsigned int p = 0; p < mesh->primitives_count; p++)
|
||||||
{
|
{
|
||||||
|
bool hasJoints = false;
|
||||||
|
|
||||||
// NOTE: We only support primitives defined by triangles
|
// NOTE: We only support primitives defined by triangles
|
||||||
if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
|
if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
|
||||||
|
|
||||||
for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
|
for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
|
||||||
{
|
{
|
||||||
// NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib
|
// NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib
|
||||||
|
|
||||||
if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16)
|
if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16)
|
||||||
{
|
{
|
||||||
|
hasJoints = true;
|
||||||
cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
|
cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
|
||||||
|
|
||||||
// NOTE: JOINTS_n can only be vec4 and u8/u16
|
// NOTE: JOINTS_n can only be vec4 and u8/u16
|
||||||
@ -5838,7 +5901,7 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh boneIds to copy glTF attribute data
|
// Init raylib mesh boneIds to copy glTF attribute data
|
||||||
model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||||
|
|
||||||
// Load attribute: vec4, u8 (unsigned char)
|
// Load attribute: vec4, u8 (unsigned char)
|
||||||
LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].boneIds)
|
LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].boneIds)
|
||||||
@ -5846,10 +5909,10 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh boneIds to copy glTF attribute data
|
// Init raylib mesh boneIds to copy glTF attribute data
|
||||||
model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||||
|
|
||||||
// Load data into a temp buffer to be converted to raylib data type
|
// Load data into a temp buffer to be converted to raylib data type
|
||||||
unsigned short *temp = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned short));
|
unsigned short *temp = (unsigned short *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned short));
|
||||||
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
||||||
|
|
||||||
// Convert data to raylib color data type (4 bytes)
|
// Convert data to raylib color data type (4 bytes)
|
||||||
@ -5878,14 +5941,13 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
|
|
||||||
if (attribute->type == cgltf_type_vec4)
|
if (attribute->type == cgltf_type_vec4)
|
||||||
{
|
{
|
||||||
// TODO: Support component types: u8, u16?
|
|
||||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh bone weight to copy glTF attribute data
|
// Init raylib mesh bone weight to copy glTF attribute data
|
||||||
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||||
|
|
||||||
// Load data into a temp buffer to be converted to raylib data type
|
// Load data into a temp buffer to be converted to raylib data type
|
||||||
unsigned char *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
unsigned char *temp = (unsigned char *)RL_MALLOC(attribute->count*4*sizeof(unsigned char));
|
||||||
LOAD_ATTRIBUTE(attribute, 4, unsigned char, temp);
|
LOAD_ATTRIBUTE(attribute, 4, unsigned char, temp);
|
||||||
|
|
||||||
// Convert data to raylib bone weight data type (4 bytes)
|
// Convert data to raylib bone weight data type (4 bytes)
|
||||||
@ -5896,10 +5958,10 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
else if (attribute->component_type == cgltf_component_type_r_16u)
|
else if (attribute->component_type == cgltf_component_type_r_16u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh bone weight to copy glTF attribute data
|
// Init raylib mesh bone weight to copy glTF attribute data
|
||||||
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||||
|
|
||||||
// Load data into a temp buffer to be converted to raylib data type
|
// Load data into a temp buffer to be converted to raylib data type
|
||||||
unsigned short *temp = RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
unsigned short *temp = (unsigned short *)RL_MALLOC(attribute->count*4*sizeof(unsigned short));
|
||||||
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
||||||
|
|
||||||
// Convert data to raylib bone weight data type
|
// Convert data to raylib bone weight data type
|
||||||
@ -5910,10 +5972,11 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
else if (attribute->component_type == cgltf_component_type_r_32f)
|
else if (attribute->component_type == cgltf_component_type_r_32f)
|
||||||
{
|
{
|
||||||
// Init raylib mesh bone weight to copy glTF attribute data
|
// Init raylib mesh bone weight to copy glTF attribute data
|
||||||
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||||
|
|
||||||
// Load 4 components of float data type into mesh.boneWeights
|
// Load 4 components of float data type into mesh.boneWeights
|
||||||
// for cgltf_attribute_type_weights we have:
|
// for cgltf_attribute_type_weights we have:
|
||||||
|
|
||||||
// - data.meshes[0] (256 vertices)
|
// - data.meshes[0] (256 vertices)
|
||||||
// - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16)
|
// - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16)
|
||||||
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
|
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
|
||||||
@ -5924,10 +5987,37 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we are animated, and the mesh was not given any bone assignments, but is the child of a bone node
|
||||||
|
// in this case we need to fully attach all the verts to the parent bone so it will animate with the bone
|
||||||
|
if (data->skins_count > 0 && !hasJoints && node->parent != NULL && node->parent->mesh == NULL)
|
||||||
|
{
|
||||||
|
int parentBoneId = -1;
|
||||||
|
for (int joint = 0; joint < model.boneCount; joint++)
|
||||||
|
{
|
||||||
|
if (data->skins[0].joints[joint] == node->parent)
|
||||||
|
{
|
||||||
|
parentBoneId = joint;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentBoneId >= 0)
|
||||||
|
{
|
||||||
|
model.meshes[meshIndex].boneIds = (unsigned char *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||||
|
model.meshes[meshIndex].boneWeights = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||||
|
|
||||||
|
for (int vertexIndex = 0; vertexIndex < model.meshes[meshIndex].vertexCount*4; vertexIndex += 4)
|
||||||
|
{
|
||||||
|
model.meshes[meshIndex].boneIds[vertexIndex] = (unsigned char)parentBoneId;
|
||||||
|
model.meshes[meshIndex].boneWeights[vertexIndex] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Animated vertex data
|
// Animated vertex data
|
||||||
model.meshes[meshIndex].animVertices = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
model.meshes[meshIndex].animVertices = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||||
memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
||||||
model.meshes[meshIndex].animNormals = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
model.meshes[meshIndex].animNormals = (float *)RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||||
if (model.meshes[meshIndex].normals != NULL)
|
if (model.meshes[meshIndex].normals != NULL)
|
||||||
{
|
{
|
||||||
memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
memcpy(model.meshes[meshIndex].animNormals, model.meshes[meshIndex].normals, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
||||||
@ -5935,7 +6025,7 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
|
|
||||||
// Bone Transform Matrices
|
// Bone Transform Matrices
|
||||||
model.meshes[meshIndex].boneCount = model.boneCount;
|
model.meshes[meshIndex].boneCount = model.boneCount;
|
||||||
model.meshes[meshIndex].boneMatrices = RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));
|
model.meshes[meshIndex].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[meshIndex].boneCount, sizeof(Matrix));
|
||||||
|
|
||||||
for (int j = 0; j < model.meshes[meshIndex].boneCount; j++)
|
for (int j = 0; j < model.meshes[meshIndex].boneCount; j++)
|
||||||
{
|
{
|
||||||
@ -5944,7 +6034,6 @@ static Model LoadGLTF(const char *fileName)
|
|||||||
|
|
||||||
meshIndex++; // Move to next mesh
|
meshIndex++; // Move to next mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free all cgltf loaded data
|
// Free all cgltf loaded data
|
||||||
@ -6126,7 +6215,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
|||||||
{
|
{
|
||||||
cgltf_skin skin = data->skins[0];
|
cgltf_skin skin = data->skins[0];
|
||||||
*animCount = (int)data->animations_count;
|
*animCount = (int)data->animations_count;
|
||||||
animations = RL_MALLOC(data->animations_count*sizeof(ModelAnimation));
|
animations = (ModelAnimation *)RL_CALLOC(data->animations_count, sizeof(ModelAnimation));
|
||||||
|
|
||||||
for (unsigned int i = 0; i < data->animations_count; i++)
|
for (unsigned int i = 0; i < data->animations_count; i++)
|
||||||
{
|
{
|
||||||
@ -6141,7 +6230,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
|||||||
cgltf_interpolation_type interpolationType;
|
cgltf_interpolation_type interpolationType;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Channels *boneChannels = RL_CALLOC(animations[i].boneCount, sizeof(struct Channels));
|
struct Channels *boneChannels = (struct Channels *)RL_CALLOC(animations[i].boneCount, sizeof(struct Channels));
|
||||||
float animDuration = 0.0f;
|
float animDuration = 0.0f;
|
||||||
|
|
||||||
for (unsigned int j = 0; j < animData.channels_count; j++)
|
for (unsigned int j = 0; j < animData.channels_count; j++)
|
||||||
@ -6199,18 +6288,14 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo
|
|||||||
animDuration = (t > animDuration)? t : animDuration;
|
animDuration = (t > animDuration)? t : animDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animData.name != NULL)
|
if (animData.name != NULL) strncpy(animations[i].name, animData.name, sizeof(animations[i].name) - 1);
|
||||||
{
|
|
||||||
strncpy(animations[i].name, animData.name, sizeof(animations[i].name));
|
|
||||||
animations[i].name[sizeof(animations[i].name) - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY) + 1;
|
animations[i].frameCount = (int)(animDuration*1000.0f/GLTF_ANIMDELAY) + 1;
|
||||||
animations[i].framePoses = RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
|
animations[i].framePoses = (Transform **)RL_MALLOC(animations[i].frameCount*sizeof(Transform *));
|
||||||
|
|
||||||
for (int j = 0; j < animations[i].frameCount; j++)
|
for (int j = 0; j < animations[i].frameCount; j++)
|
||||||
{
|
{
|
||||||
animations[i].framePoses[j] = RL_MALLOC(animations[i].boneCount*sizeof(Transform));
|
animations[i].framePoses[j] = (Transform *)RL_MALLOC(animations[i].boneCount*sizeof(Transform));
|
||||||
float time = ((float) j*GLTF_ANIMDELAY)/1000.0f;
|
float time = ((float) j*GLTF_ANIMDELAY)/1000.0f;
|
||||||
|
|
||||||
for (int k = 0; k < animations[i].boneCount; k++)
|
for (int k = 0; k < animations[i].boneCount; k++)
|
||||||
@ -6360,7 +6445,7 @@ static Model LoadVOX(const char *fileName)
|
|||||||
|
|
||||||
// Copy colors
|
// Copy colors
|
||||||
size = pmesh->vertexCount*sizeof(Color);
|
size = pmesh->vertexCount*sizeof(Color);
|
||||||
pmesh->colors = RL_MALLOC(size);
|
pmesh->colors = (unsigned char *)RL_MALLOC(size);
|
||||||
memcpy(pmesh->colors, pcolors, size);
|
memcpy(pmesh->colors, pcolors, size);
|
||||||
|
|
||||||
// First material index
|
// First material index
|
||||||
@ -6496,7 +6581,7 @@ static Model LoadM3D(const char *fileName)
|
|||||||
|
|
||||||
// If no map is provided, or we have colors defined, we allocate storage for vertex colors
|
// If no map is provided, or we have colors defined, we allocate storage for vertex colors
|
||||||
// M3D specs only consider vertex colors if no material is provided, however raylib uses both and mixes the colors
|
// M3D specs only consider vertex colors if no material is provided, however raylib uses both and mixes the colors
|
||||||
if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
|
if ((mi == M3D_UNDEF) || vcolor) model.meshes[k].colors = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
|
||||||
|
|
||||||
// If no map is provided and we allocated vertex colors, set them to white
|
// If no map is provided and we allocated vertex colors, set them to white
|
||||||
if ((mi == M3D_UNDEF) && (model.meshes[k].colors != NULL))
|
if ((mi == M3D_UNDEF) && (model.meshes[k].colors != NULL))
|
||||||
@ -6530,11 +6615,11 @@ static Model LoadM3D(const char *fileName)
|
|||||||
// Without vertex color (full transparency), we use the default color
|
// Without vertex color (full transparency), we use the default color
|
||||||
if (model.meshes[k].colors != NULL)
|
if (model.meshes[k].colors != NULL)
|
||||||
{
|
{
|
||||||
if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xFF000000)
|
if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xff000000)
|
||||||
memcpy(&model.meshes[k].colors[l*12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4);
|
memcpy(&model.meshes[k].colors[l*12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4);
|
||||||
if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xFF000000)
|
if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xff000000)
|
||||||
memcpy(&model.meshes[k].colors[l*12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4);
|
memcpy(&model.meshes[k].colors[l*12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4);
|
||||||
if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xFF000000)
|
if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xff000000)
|
||||||
memcpy(&model.meshes[k].colors[l*12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4);
|
memcpy(&model.meshes[k].colors[l*12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6663,13 +6748,13 @@ static Model LoadM3D(const char *fileName)
|
|||||||
if (m3d->numbone)
|
if (m3d->numbone)
|
||||||
{
|
{
|
||||||
model.boneCount = m3d->numbone + 1;
|
model.boneCount = m3d->numbone + 1;
|
||||||
model.bones = RL_CALLOC(model.boneCount, sizeof(BoneInfo));
|
model.bones = (BoneInfo *)RL_CALLOC(model.boneCount, sizeof(BoneInfo));
|
||||||
model.bindPose = RL_CALLOC(model.boneCount, sizeof(Transform));
|
model.bindPose = (Transform *)RL_CALLOC(model.boneCount, sizeof(Transform));
|
||||||
|
|
||||||
for (i = 0; i < (int)m3d->numbone; i++)
|
for (i = 0; i < (int)m3d->numbone; i++)
|
||||||
{
|
{
|
||||||
model.bones[i].parent = m3d->bone[i].parent;
|
model.bones[i].parent = m3d->bone[i].parent;
|
||||||
strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name));
|
strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name) - 1);
|
||||||
model.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale;
|
model.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale;
|
||||||
model.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale;
|
model.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale;
|
||||||
model.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale;
|
model.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale;
|
||||||
@ -6715,7 +6800,7 @@ static Model LoadM3D(const char *fileName)
|
|||||||
memcpy(model.meshes[i].animNormals, model.meshes[i].normals, 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].boneCount = model.boneCount;
|
||||||
model.meshes[i].boneMatrices = RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
model.meshes[i].boneMatrices = (Matrix *)RL_CALLOC(model.meshes[i].boneCount, sizeof(Matrix));
|
||||||
for (j = 0; j < model.meshes[i].boneCount; j++)
|
for (j = 0; j < model.meshes[i].boneCount; j++)
|
||||||
{
|
{
|
||||||
model.meshes[i].boneMatrices[j] = MatrixIdentity();
|
model.meshes[i].boneMatrices[j] = MatrixIdentity();
|
||||||
@ -6765,24 +6850,23 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
animations = RL_MALLOC(m3d->numaction*sizeof(ModelAnimation));
|
animations = (ModelAnimation *)RL_CALLOC(m3d->numaction, sizeof(ModelAnimation));
|
||||||
*animCount = m3d->numaction;
|
*animCount = m3d->numaction;
|
||||||
|
|
||||||
for (unsigned int a = 0; a < m3d->numaction; a++)
|
for (unsigned int a = 0; a < m3d->numaction; a++)
|
||||||
{
|
{
|
||||||
animations[a].frameCount = m3d->action[a].durationmsec/M3D_ANIMDELAY;
|
animations[a].frameCount = m3d->action[a].durationmsec/M3D_ANIMDELAY;
|
||||||
animations[a].boneCount = m3d->numbone + 1;
|
animations[a].boneCount = m3d->numbone + 1;
|
||||||
animations[a].bones = RL_MALLOC((m3d->numbone + 1)*sizeof(BoneInfo));
|
animations[a].bones = (BoneInfo *)RL_MALLOC((m3d->numbone + 1)*sizeof(BoneInfo));
|
||||||
animations[a].framePoses = RL_MALLOC(animations[a].frameCount*sizeof(Transform *));
|
animations[a].framePoses = (Transform **)RL_MALLOC(animations[a].frameCount*sizeof(Transform *));
|
||||||
strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name));
|
strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name) - 1);
|
||||||
animations[a].name[sizeof(animations[a].name) - 1] = '\0';
|
|
||||||
|
|
||||||
TRACELOG(LOG_INFO, "MODEL: [%s] animation #%i: %i msec, %i frames", fileName, a, m3d->action[a].durationmsec, animations[a].frameCount);
|
TRACELOG(LOG_INFO, "MODEL: [%s] animation #%i: %i msec, %i frames", fileName, a, m3d->action[a].durationmsec, animations[a].frameCount);
|
||||||
|
|
||||||
for (i = 0; i < (int)m3d->numbone; i++)
|
for (i = 0; i < (int)m3d->numbone; i++)
|
||||||
{
|
{
|
||||||
animations[a].bones[i].parent = m3d->bone[i].parent;
|
animations[a].bones[i].parent = m3d->bone[i].parent;
|
||||||
strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name));
|
strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A special, never transformed "no bone" bone, used for boneless vertices
|
// A special, never transformed "no bone" bone, used for boneless vertices
|
||||||
@ -6793,7 +6877,7 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou
|
|||||||
// regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
|
// regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
|
||||||
for (i = 0; i < animations[a].frameCount; i++)
|
for (i = 0; i < animations[a].frameCount; i++)
|
||||||
{
|
{
|
||||||
animations[a].framePoses[i] = RL_MALLOC((m3d->numbone + 1)*sizeof(Transform));
|
animations[a].framePoses[i] = (Transform *)RL_MALLOC((m3d->numbone + 1)*sizeof(Transform));
|
||||||
|
|
||||||
m3db_t *pose = m3d_pose(m3d, a, i*M3D_ANIMDELAY);
|
m3db_t *pose = m3d_pose(m3d, a, i*M3D_ANIMDELAY);
|
||||||
|
|
||||||
|
@ -470,27 +470,39 @@ void DrawCircleLinesV(Vector2 center, float radius, Color color)
|
|||||||
|
|
||||||
// Draw ellipse
|
// Draw ellipse
|
||||||
void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color)
|
void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color)
|
||||||
|
{
|
||||||
|
DrawEllipseV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw ellipse (Vector version)
|
||||||
|
void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color)
|
||||||
{
|
{
|
||||||
rlBegin(RL_TRIANGLES);
|
rlBegin(RL_TRIANGLES);
|
||||||
for (int i = 0; i < 360; i += 10)
|
for (int i = 0; i < 360; i += 10)
|
||||||
{
|
{
|
||||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||||
rlVertex2f((float)centerX, (float)centerY);
|
rlVertex2f(center.x, center.y);
|
||||||
rlVertex2f((float)centerX + cosf(DEG2RAD*(i + 10))*radiusH, (float)centerY + sinf(DEG2RAD*(i + 10))*radiusV);
|
rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
|
||||||
rlVertex2f((float)centerX + cosf(DEG2RAD*i)*radiusH, (float)centerY + sinf(DEG2RAD*i)*radiusV);
|
rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
|
||||||
}
|
}
|
||||||
rlEnd();
|
rlEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw ellipse outline
|
// Draw ellipse outline
|
||||||
void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color)
|
void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color)
|
||||||
|
{
|
||||||
|
DrawEllipseLinesV((Vector2){ (float)centerX, (float)centerY }, radiusH, radiusV, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw ellipse outline
|
||||||
|
void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color)
|
||||||
{
|
{
|
||||||
rlBegin(RL_LINES);
|
rlBegin(RL_LINES);
|
||||||
for (int i = 0; i < 360; i += 10)
|
for (int i = 0; i < 360; i += 10)
|
||||||
{
|
{
|
||||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||||
rlVertex2f(centerX + cosf(DEG2RAD*(i + 10))*radiusH, centerY + sinf(DEG2RAD*(i + 10))*radiusV);
|
rlVertex2f(center.x + cosf(DEG2RAD*(i + 10))*radiusH, center.y + sinf(DEG2RAD*(i + 10))*radiusV);
|
||||||
rlVertex2f(centerX + cosf(DEG2RAD*i)*radiusH, centerY + sinf(DEG2RAD*i)*radiusV);
|
rlVertex2f(center.x + cosf(DEG2RAD*i)*radiusH, center.y + sinf(DEG2RAD*i)*radiusV);
|
||||||
}
|
}
|
||||||
rlEnd();
|
rlEnd();
|
||||||
}
|
}
|
||||||
@ -774,7 +786,7 @@ void DrawRectangleGradientH(int posX, int posY, int width, int height, Color lef
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw a gradient-filled rectangle
|
// Draw a gradient-filled rectangle
|
||||||
void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color topRight, Color bottomRight)
|
void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight)
|
||||||
{
|
{
|
||||||
rlSetTexture(GetShapesTexture().id);
|
rlSetTexture(GetShapesTexture().id);
|
||||||
Rectangle shapeRect = GetShapesTextureRectangle();
|
Rectangle shapeRect = GetShapesTextureRectangle();
|
||||||
@ -791,11 +803,11 @@ void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Col
|
|||||||
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||||
rlVertex2f(rec.x, rec.y + rec.height);
|
rlVertex2f(rec.x, rec.y + rec.height);
|
||||||
|
|
||||||
rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a);
|
rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a);
|
||||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
|
||||||
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
|
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
|
||||||
|
|
||||||
rlColor4ub(bottomRight.r, bottomRight.g, bottomRight.b, bottomRight.a);
|
rlColor4ub(topRight.r, topRight.g, topRight.b, topRight.a);
|
||||||
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
|
||||||
rlVertex2f(rec.x + rec.width, rec.y);
|
rlVertex2f(rec.x + rec.width, rec.y);
|
||||||
rlEnd();
|
rlEnd();
|
||||||
|
@ -161,6 +161,10 @@ extern void LoadFontDefault(void)
|
|||||||
{
|
{
|
||||||
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
|
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
|
||||||
|
|
||||||
|
// check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return
|
||||||
|
if (defaultFont.glyphs != NULL && !isGpuReady)
|
||||||
|
return;
|
||||||
|
|
||||||
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
|
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
|
||||||
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
|
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
|
||||||
|
|
||||||
@ -249,7 +253,7 @@ extern void LoadFontDefault(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
((unsigned char *)imFont.data)[(i + j)*sizeof(short)] = 0xFF;
|
((unsigned char *)imFont.data)[(i + j)*sizeof(short)] = 0xff;
|
||||||
((unsigned char *)imFont.data)[(i + j)*sizeof(short) + 1] = 0x00;
|
((unsigned char *)imFont.data)[(i + j)*sizeof(short) + 1] = 0x00;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,7 +261,18 @@ extern void LoadFontDefault(void)
|
|||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGpuReady) defaultFont.texture = LoadTextureFromImage(imFont);
|
if (isGpuReady)
|
||||||
|
{
|
||||||
|
defaultFont.texture = LoadTextureFromImage(imFont);
|
||||||
|
|
||||||
|
// we have already loaded the font glyph data an image, and the GPU is ready, we are done
|
||||||
|
// if we don't do this, we will leak memory by reallocating the glyphs and rects
|
||||||
|
if (defaultFont.glyphs != NULL)
|
||||||
|
{
|
||||||
|
UnloadImage(imFont);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
|
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -282,7 +297,7 @@ extern void LoadFontDefault(void)
|
|||||||
|
|
||||||
testPosX += (int)(defaultFont.recs[i].width + (float)charsDivisor);
|
testPosX += (int)(defaultFont.recs[i].width + (float)charsDivisor);
|
||||||
|
|
||||||
if (testPosX >= defaultFont.texture.width)
|
if (testPosX >= imFont.width)
|
||||||
{
|
{
|
||||||
currentLine++;
|
currentLine++;
|
||||||
currentPosX = 2*charsDivisor + charsWidth[i];
|
currentPosX = 2*charsDivisor + charsWidth[i];
|
||||||
@ -316,6 +331,9 @@ extern void UnloadFontDefault(void)
|
|||||||
if (isGpuReady) UnloadTexture(defaultFont.texture);
|
if (isGpuReady) UnloadTexture(defaultFont.texture);
|
||||||
RL_FREE(defaultFont.glyphs);
|
RL_FREE(defaultFont.glyphs);
|
||||||
RL_FREE(defaultFont.recs);
|
RL_FREE(defaultFont.recs);
|
||||||
|
defaultFont.glyphCount = 0;
|
||||||
|
defaultFont.glyphs = NULL;
|
||||||
|
defaultFont.recs = NULL;
|
||||||
}
|
}
|
||||||
#endif // SUPPORT_DEFAULT_FONT
|
#endif // SUPPORT_DEFAULT_FONT
|
||||||
|
|
||||||
@ -373,7 +391,7 @@ Font LoadFont(const char *fileName)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
|
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);
|
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1560,7 +1578,7 @@ const char *TextSubtext(const char *text, int position, int length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Replace text string
|
// Replace text string
|
||||||
// REQUIRES: strlen(), strstr(), strncpy(), strcpy()
|
// REQUIRES: strstr(), strncpy(), strcpy()
|
||||||
// WARNING: Allocated memory must be manually freed
|
// WARNING: Allocated memory must be manually freed
|
||||||
char *TextReplace(const char *text, const char *replace, const char *by)
|
char *TextReplace(const char *text, const char *replace, const char *by)
|
||||||
{
|
{
|
||||||
|
@ -832,10 +832,11 @@ Image GenImageGradientLinear(int width, int height, int direction, Color start,
|
|||||||
|
|
||||||
// Calculate how far the top-left pixel is along the gradient direction from the center of said gradient
|
// Calculate how far the top-left pixel is along the gradient direction from the center of said gradient
|
||||||
float startingPos = 0.5f - (cosDir*width/2) - (sinDir*height/2);
|
float startingPos = 0.5f - (cosDir*width/2) - (sinDir*height/2);
|
||||||
|
|
||||||
// With directions that lie in the first or third quadrant (i.e. from top-left to
|
// With directions that lie in the first or third quadrant (i.e. from top-left to
|
||||||
// bottom-right or vice-versa), pixel (0, 0) is the farthest point on the gradient
|
// bottom-right or vice-versa), pixel (0, 0) is the farthest point on the gradient
|
||||||
// (i.e. the pixel which should become one of the gradient's ends color); while for
|
// (i.e. the pixel which should become one of the gradient's ends color); while for
|
||||||
// directions that lie in the second or fourth quadrant, that point is pixel (width, 0).
|
// directions that lie in the second or fourth quadrant, that point is pixel (width, 0)
|
||||||
float maxPosValue = ((signbit(sinDir) != 0) == (signbit(cosDir) != 0))? fabsf(startingPos) : fabsf(startingPos + width*cosDir);
|
float maxPosValue = ((signbit(sinDir) != 0) == (signbit(cosDir) != 0))? fabsf(startingPos) : fabsf(startingPos + width*cosDir);
|
||||||
for (int i = 0; i < width; i++)
|
for (int i = 0; i < width; i++)
|
||||||
{
|
{
|
||||||
@ -2101,8 +2102,8 @@ void ImageBlurGaussian(Image *image, int blurSize)
|
|||||||
Color *pixels = LoadImageColors(*image);
|
Color *pixels = LoadImageColors(*image);
|
||||||
|
|
||||||
// Loop switches between pixelsCopy1 and pixelsCopy2
|
// Loop switches between pixelsCopy1 and pixelsCopy2
|
||||||
Vector4 *pixelsCopy1 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
Vector4 *pixelsCopy1 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||||
Vector4 *pixelsCopy2 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
Vector4 *pixelsCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||||
|
|
||||||
for (int i = 0; i < (image->height*image->width); i++)
|
for (int i = 0; i < (image->height*image->width); i++)
|
||||||
{
|
{
|
||||||
@ -2216,9 +2217,9 @@ void ImageBlurGaussian(Image *image, int blurSize)
|
|||||||
else if (pixelsCopy1[i].w <= 255.0f)
|
else if (pixelsCopy1[i].w <= 255.0f)
|
||||||
{
|
{
|
||||||
float alpha = (float)pixelsCopy1[i].w/255.0f;
|
float alpha = (float)pixelsCopy1[i].w/255.0f;
|
||||||
pixels[i].r = (unsigned char)((float)pixelsCopy1[i].x/alpha);
|
pixels[i].r = (unsigned char)fminf((float)pixelsCopy1[i].x/alpha, 255.0);
|
||||||
pixels[i].g = (unsigned char)((float)pixelsCopy1[i].y/alpha);
|
pixels[i].g = (unsigned char)fminf((float)pixelsCopy1[i].y/alpha, 255.0);
|
||||||
pixels[i].b = (unsigned char)((float)pixelsCopy1[i].z/alpha);
|
pixels[i].b = (unsigned char)fminf((float)pixelsCopy1[i].z/alpha, 255.0);
|
||||||
pixels[i].a = (unsigned char) pixelsCopy1[i].w;
|
pixels[i].a = (unsigned char) pixelsCopy1[i].w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2250,8 +2251,8 @@ void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize)
|
|||||||
|
|
||||||
Color *pixels = LoadImageColors(*image);
|
Color *pixels = LoadImageColors(*image);
|
||||||
|
|
||||||
Vector4 *imageCopy2 = RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
Vector4 *imageCopy2 = (Vector4 *)RL_MALLOC((image->height)*(image->width)*sizeof(Vector4));
|
||||||
Vector4 *temp = RL_MALLOC(kernelSize*sizeof(Vector4));
|
Vector4 *temp = (Vector4 *)RL_MALLOC(kernelSize*sizeof(Vector4));
|
||||||
|
|
||||||
for (int i = 0; i < kernelSize; i++)
|
for (int i = 0; i < kernelSize; i++)
|
||||||
{
|
{
|
||||||
@ -2926,7 +2927,16 @@ void ImageColorReplace(Image *image, Color color, Color replace)
|
|||||||
image->data = pixels;
|
image->data = pixels;
|
||||||
image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
image->format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||||
|
|
||||||
ImageFormat(image, format);
|
// Only convert back to original format if it supported alpha
|
||||||
|
if ((format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
|
||||||
|
(format == PIXELFORMAT_UNCOMPRESSED_R5G6B5) ||
|
||||||
|
(format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
|
||||||
|
(format == PIXELFORMAT_UNCOMPRESSED_R32G32B32) ||
|
||||||
|
(format == PIXELFORMAT_UNCOMPRESSED_R16G16B16) ||
|
||||||
|
(format == PIXELFORMAT_COMPRESSED_DXT1_RGB) ||
|
||||||
|
(format == PIXELFORMAT_COMPRESSED_ETC1_RGB) ||
|
||||||
|
(format == PIXELFORMAT_COMPRESSED_ETC2_RGB) ||
|
||||||
|
(format == PIXELFORMAT_COMPRESSED_PVRT_RGB)) ImageFormat(image, format);
|
||||||
}
|
}
|
||||||
#endif // SUPPORT_IMAGE_MANIPULATION
|
#endif // SUPPORT_IMAGE_MANIPULATION
|
||||||
|
|
||||||
@ -3564,34 +3574,43 @@ void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color co
|
|||||||
int dx = x2 - x1;
|
int dx = x2 - x1;
|
||||||
int dy = y2 - y1;
|
int dy = y2 - y1;
|
||||||
|
|
||||||
// Draw the main line between (x1, y1) and (x2, y2)
|
|
||||||
ImageDrawLine(dst, x1, y1, x2, y2, color);
|
|
||||||
|
|
||||||
// Determine if the line is more horizontal or vertical
|
// Determine if the line is more horizontal or vertical
|
||||||
if ((dx != 0) && (abs(dy/dx) < 1))
|
if ((dx != 0) && (abs(dy/dx) < 1))
|
||||||
{
|
{
|
||||||
// Line is more horizontal
|
// Line is more horizontal
|
||||||
// Calculate half the width of the line
|
|
||||||
int wy = (thick - 1)*(int)sqrtf((float)(dx*dx + dy*dy))/(2*abs(dx));
|
|
||||||
|
|
||||||
// Draw additional lines above and below the main line
|
// How many additional lines to draw
|
||||||
for (int i = 1; i <= wy; i++)
|
int wy = thick - 1;
|
||||||
|
|
||||||
|
// Draw the main line and lower half
|
||||||
|
for (int i = 0; i <= ((wy+1)/2); i++)
|
||||||
{
|
{
|
||||||
ImageDrawLine(dst, x1, y1 - i, x2, y2 - i, color); // Draw above the main line
|
ImageDrawLine(dst, x1, y1 + i, x2, y2 + i, color);
|
||||||
ImageDrawLine(dst, x1, y1 + i, x2, y2 + i, color); // Draw below the main line
|
}
|
||||||
|
|
||||||
|
// Draw the upper half
|
||||||
|
for (int i = 1; i <= (wy/2); i++)
|
||||||
|
{
|
||||||
|
ImageDrawLine(dst, x1, y1 - i, x2, y2 - i, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (dy != 0)
|
else if (dy != 0)
|
||||||
{
|
{
|
||||||
// Line is more vertical or perfectly horizontal
|
// Line is more vertical or perfectly horizontal
|
||||||
// Calculate half the width of the line
|
|
||||||
int wx = (thick - 1)*(int)sqrtf((float)(dx*dx + dy*dy))/(2*abs(dy));
|
|
||||||
|
|
||||||
// Draw additional lines to the left and right of the main line
|
// How many additional lines to draw
|
||||||
for (int i = 1; i <= wx; i++)
|
int wx = thick - 1;
|
||||||
|
|
||||||
|
//Draw the main line and right half
|
||||||
|
for (int i = 0; i <= ((wx+1)/2); i++)
|
||||||
{
|
{
|
||||||
ImageDrawLine(dst, x1 - i, y1, x2 - i, y2, color); // Draw left of the main line
|
ImageDrawLine(dst, x1 + i, y1, x2 + i, y2, color);
|
||||||
ImageDrawLine(dst, x1 + i, y1, x2 + i, y2, color); // Draw right of the main line
|
}
|
||||||
|
|
||||||
|
// Draw the left half
|
||||||
|
for (int i = 1; i <= (wx/2); i++)
|
||||||
|
{
|
||||||
|
ImageDrawLine(dst, x1 - i, y1, x2 - i, y2, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3835,7 +3854,7 @@ void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c
|
|||||||
|
|
||||||
// Calculate the inverse of the sum of the barycentric coordinates for normalization
|
// Calculate the inverse of the sum of the barycentric coordinates for normalization
|
||||||
// NOTE 1: Here, we act as if we multiply by 255 the reciprocal, which avoids additional
|
// NOTE 1: Here, we act as if we multiply by 255 the reciprocal, which avoids additional
|
||||||
// calculations in the loop. This is acceptable because we are only interpolating colors.
|
// calculations in the loop. This is acceptable because we are only interpolating colors
|
||||||
// NOTE 2: This sum remains constant throughout the triangle
|
// NOTE 2: This sum remains constant throughout the triangle
|
||||||
float wInvSum = 255.0f/(w1Row + w2Row + w3Row);
|
float wInvSum = 255.0f/(w1Row + w2Row + w3Row);
|
||||||
|
|
||||||
@ -3890,7 +3909,7 @@ void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Colo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw a triangle fan defined by points within an image (first vertex is the center)
|
// Draw a triangle fan defined by points within an image (first vertex is the center)
|
||||||
void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color color)
|
void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color)
|
||||||
{
|
{
|
||||||
if (pointCount >= 3)
|
if (pointCount >= 3)
|
||||||
{
|
{
|
||||||
@ -3902,7 +3921,7 @@ void ImageDrawTriangleFan(Image *dst, Vector2 *points, int pointCount, Color col
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw a triangle strip defined by points within an image
|
// Draw a triangle strip defined by points within an image
|
||||||
void ImageDrawTriangleStrip(Image *dst, Vector2 *points, int pointCount, Color color)
|
void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color)
|
||||||
{
|
{
|
||||||
if (pointCount >= 3)
|
if (pointCount >= 3)
|
||||||
{
|
{
|
||||||
@ -4337,14 +4356,17 @@ void UnloadRenderTexture(RenderTexture2D target)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update GPU texture with new data
|
// Update GPU texture with new data
|
||||||
// NOTE: pixels data must match texture.format
|
// NOTE 1: pixels data must match texture.format
|
||||||
|
// NOTE 2: pixels data must contain at least as many pixels as texture
|
||||||
void UpdateTexture(Texture2D texture, const void *pixels)
|
void UpdateTexture(Texture2D texture, const void *pixels)
|
||||||
{
|
{
|
||||||
rlUpdateTexture(texture.id, 0, 0, texture.width, texture.height, texture.format, pixels);
|
rlUpdateTexture(texture.id, 0, 0, texture.width, texture.height, texture.format, pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update GPU texture rectangle with new data
|
// Update GPU texture rectangle with new data
|
||||||
// NOTE: pixels data must match texture.format
|
// NOTE 1: pixels data must match texture.format
|
||||||
|
// NOTE 2: pixels data must contain as many pixels as rec contains
|
||||||
|
// NOTE 3: rec must fit completely within texture's width and height
|
||||||
void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels)
|
void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels)
|
||||||
{
|
{
|
||||||
rlUpdateTexture(texture.id, (int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, texture.format, pixels);
|
rlUpdateTexture(texture.id, (int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, texture.format, pixels);
|
||||||
@ -5147,10 +5169,10 @@ Color GetColor(unsigned int hexValue)
|
|||||||
{
|
{
|
||||||
Color color;
|
Color color;
|
||||||
|
|
||||||
color.r = (unsigned char)(hexValue >> 24) & 0xFF;
|
color.r = (unsigned char)(hexValue >> 24) & 0xff;
|
||||||
color.g = (unsigned char)(hexValue >> 16) & 0xFF;
|
color.g = (unsigned char)(hexValue >> 16) & 0xff;
|
||||||
color.b = (unsigned char)(hexValue >> 8) & 0xFF;
|
color.b = (unsigned char)(hexValue >> 8) & 0xff;
|
||||||
color.a = (unsigned char)hexValue & 0xFF;
|
color.a = (unsigned char)hexValue & 0xff;
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
@ -5390,17 +5412,16 @@ static float HalfToFloat(unsigned short x)
|
|||||||
{
|
{
|
||||||
float result = 0.0f;
|
float result = 0.0f;
|
||||||
|
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
float fm;
|
float fm;
|
||||||
unsigned int ui;
|
unsigned int ui;
|
||||||
} uni;
|
} uni;
|
||||||
|
|
||||||
const unsigned int e = (x & 0x7C00) >> 10; // Exponent
|
const unsigned int e = (x & 0x7c00) >> 10; // Exponent
|
||||||
const unsigned int m = (x & 0x03FF) << 13; // Mantissa
|
const unsigned int m = (x & 0x03ff) << 13; // Mantissa
|
||||||
uni.fm = (float)m;
|
uni.fm = (float)m;
|
||||||
const unsigned int v = uni.ui >> 23; // Evil log2 bit hack to count leading zeros in denormalized format
|
const unsigned int v = uni.ui >> 23; // Evil log2 bit hack to count leading zeros in denormalized format
|
||||||
uni.ui = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007FE000)); // sign : normalized : denormalized
|
uni.ui = (x & 0x8000) << 16 | (e != 0)*((e + 112) << 23 | m) | ((e == 0)&(m != 0))*((v - 37) << 23 | ((m << (150 - v)) & 0x007fe000)); // sign : normalized : denormalized
|
||||||
|
|
||||||
result = uni.fm;
|
result = uni.fm;
|
||||||
|
|
||||||
@ -5412,18 +5433,17 @@ static unsigned short FloatToHalf(float x)
|
|||||||
{
|
{
|
||||||
unsigned short result = 0;
|
unsigned short result = 0;
|
||||||
|
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
float fm;
|
float fm;
|
||||||
unsigned int ui;
|
unsigned int ui;
|
||||||
} uni;
|
} uni;
|
||||||
uni.fm = x;
|
uni.fm = x;
|
||||||
|
|
||||||
const unsigned int b = uni.ui + 0x00001000; // Round-to-nearest-even: add last bit after truncated mantissa
|
const unsigned int b = uni.ui + 0x00001000; // Round-to-nearest-even: add last bit after truncated mantissa
|
||||||
const unsigned int e = (b & 0x7F800000) >> 23; // Exponent
|
const unsigned int e = (b & 0x7f800000) >> 23; // Exponent
|
||||||
const unsigned int m = b & 0x007FFFFF; // Mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
|
const unsigned int m = b & 0x007fffff; // Mantissa; in line below: 0x007ff000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
|
||||||
|
|
||||||
result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7C00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7FFF; // sign : normalized : denormalized : saturate
|
result = (b & 0x80000000) >> 16 | (e > 112)*((((e - 112) << 10) & 0x7c00) | m >> 13) | ((e < 113) & (e > 101))*((((0x007ff000 + m) >> (125 - e)) + 1) >> 1) | (e > 143)*0x7fff; // sign : normalized : denormalized : saturate
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -405,7 +405,7 @@ void UnloadFileText(char *text)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save text data to file (write), string must be '\0' terminated
|
// Save text data to file (write), string must be '\0' terminated
|
||||||
bool SaveFileText(const char *fileName, char *text)
|
bool SaveFileText(const char *fileName, const char *text)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user