Squashed 'libs/raylib/' changes from 3a1d6261e..9b6c09c32

9b6c09c32 Merge pull request #5049 from wwderw/master
0b125a5fd Update Makefile
0b7dda8ab Merge pull request #5050 from katanya04/master
3d93b3026 Update font load message
78a06990c Merge pull request #5041 from PanicTitan/master
82b80a699 Review formatting, avoid variable
71b302846 Review formatting, avoid variable
8823aba9d Update rprand.h
6b9a685ba Merge pull request #5048 from veins1/patch-4
14582a9f0 Merge pull request #5047 from RomainPlmg/#5009-fix-colorreplace-alpha
093e5200d Update Makefile
0405de794 Fix for music stopping too early
d03ac97ef GetMusicTimePlayed fix for music shorter than buffer size
34af70866 [rtextures] Fix ImageColorReplace() alpha issue #5009
e00c5eb8b Merge pull request #5043 from vinnyhorgan/master
cbea2ff50 Merge pull request #5046 from maiconpintoabreu/updatestream-music
3320a2c83 Fix to prevent UpdateMusicStream to run without music playing
e7c043529 Merge pull request #5044 from backspaceoverload/fix-HalfToFloat
44ebf3238 Fix HalfToFloat Mantissa hex value
901afadbf fix warning log macro in rlgl
f34e24068 Merge pull request #5042 from Sir-Irk/ImageDrawLineEx_fix
fce3102f1 Remove excess comments
9f03d7c42 fixing comments
0c69c43c3 fix ImageDrawLineEx to be able to draw even numbered thicknesses
9e908e4a7 Update core_custom_frame_control.c to work properly on web
20a07a65d Merge pull request #5037 from garrisonhh/fix-gaussian-blur
8dbacafbe fix overflow in cast for ImageBlurGaussian
55a567471 Merge pull request #5036 from sleeptightAnsiC/update_glfw_mappings_h
930890555 [glfw] update mappings.h using GenerateMappings.cmake
defbeee1a Merge pull request #5020 from Emil2010/master
d972582bc Merge pull request #5025 from zedeckj/master
595756498 Merge pull request #5026 from jonathandw743/sdlfix
eaea8e0b0 Merge pull request #5033 from wwderw/master
8ef51850b Update raudio.c
a92f67bf3 Merge pull request #5031 from AmityWilder/safety-comments
205b6a092 Merge branch 'raysan5:master' into safety-comments
9f6d37ecb Update raylib_api.* by CI
d4f09984a Add safety notes to 'Update_' functions
79c29cbe2 fixed compile error for PLATFORM sdl
e91a3697f Fixed typo
910f4083e update dr_libs
7f8dfc6c6 Merge pull request #5018 from maiconpintoabreu/fix-zig-wasm-win-mac
f1600a0c7 Fix issue on zig build emscripten run if the user has not installed emsdk
46f01e315 Merge pull request #5013 from maiconpintoabreu/zig-examples
2e74133a6 Merge pull request #5014 from fosskers/colin/cl-binding
7f32b9a96 Merge pull request #5015 from Sir-Irk/gltf_model_fix
8cf932c82 Merge pull request #5016 from Sir-Irk/fix_pbr_example_tangents
ed509193d remving w multiply on the tangent itself
f86295732 fixing shader tangents to be vec4
bee524e5e fixing offset for processing tangents for gltf loading
eef1bac3e fix misspelling
0cae8890b Remove -fno-stack-protector as it is not needed and add requestFullscreen on exported methods
1db006b08 docs: mention another Common Lisp binding
8f50436dc Fix comments
6e9c3acaa Add run examples using zig and emscripten for web
bdda18656 Merge pull request #5011 from maiconpintoabreu/update-emsdk-fix-touch
d659037fb Update emsdk version for zig build to fix the issue with the EM_BOOL
c35e13647 Merge branch 'master' of https://github.com/raysan5/raylib
44f670899 REVIEWED: Avoid `rtext` dependency on `rcore_desktop_sdl`  #4959
e09dcf611 Merge pull request #5006 from ElDigoXD/patch-1
6266d0f41 Fix typo on config.h
b67737608 Delete shader in case compilation fails
1abac023b Update rcore.c
8b0230f5b Merge pull request #5002 from mlorenc227/master
518ad8b01 Fix ScanDirectoryFilesRecursively
4bc8d3761 Merge pull request #4999 from danilwhale/raylib-cs.bleedingedge
43bad2612 docs: add Raylib-cs.BleedingEdge to the bindings
fd4375a74 Merge pull request #4992 from M374LX/rgfw-update
17a618758 Merge pull request #4995 from Not-Nik/zig-raygui-options
abf255fbe Merge pull request #4993 from Marcos-cat/master
106bcf460 add uiua bindings to the list
96c898852 Update RGFW
3e336e447 Reviewed warning
59bcf680a Code gardening...
8a3a8ee8e Update shapes_digital_clock.c
533c12c38 Small security tweaks
5f497d068 REVIEWED: `shapes_digital_clock` example
cb369f8df Merge pull request #4985 from hmz-rhl/master
3f228f459 [examples] : adding new fancy clock
8d319b100 Merge pull request #4983 from M374LX/miniaudio-update
d218db9ee Merge pull request #4982 from LainLayer/rgfw-timeout
59338c2c2 Update raylib_api.* by CI
714de02a8 Merge pull request #4980 from williewillus/pr4980
c81097505 Merge pull request #4981 from garrisonhh/add-build-zig-zon-license
53faf7ae7 Merge pull request #4977 from jestarray/patch-2
bb5b5434a Update miniaudio to v0.11.22
51958d6e2 changed `RGFW_window_eventWait` timeout to -1
b52a9f8a0 Add LICENSE to build.zig.zon
19ae6f2c2 [rshapes] Fix incorrect parameter names in DrawRectangleGradientEx
58a6846c8 Update raylib_api.* by CI
296e3af47 add const qualifier to ImageDrawTriangleFan and ImageDrawTriangleStrip arguments
924c87db3 Merge pull request #4976 from M374LX/rgfw-update-dev
6eeaf1dd5 Update RGFW to 1.7.5-dev
c1bb53738 Merge pull request #4974 from M374LX/rgfw-escape-fix
9bf4388a4 Merge pull request #4965 from M374LX/rgfw-update
3414d96ea Update raylib_api.* by CI
20c0c92bd Merge pull request #4963 from meowstr/master
bc2b2864e RGFW: fix Escape always closing the window
b26f6d34b Allow passing options to raygui in build.zig
b9c2ecc44 Merge pull request #4969 from M374LX/update-comments
8f2ecfba4 Update raylib_api.* by CI
341817261 Update comments
015db1641 Merge pull request #4964 from M374LX/axes-comment
a9525bfbc Update RGFW to 1.7
16f398b46 Update comment (gamepad axes)
6d5aedbd3 Add DrawEllipseV and DrawEllipseLinesV
913c23648 REVIEWED: `MAX_GAMEPAD_AXES`
341bfb22c REVIEWED: `MAX_GAMEPAD_AXEX` for consistency #4960
2afae1b3e Merge pull request #4962 from M374LX/rgfw-rctrl
f9fa63366 Merge pull request #4958 from M374LX/unused-var
c0cf57f8f RGFW backend: add missing Right Control key
299f5350a Remove unused variable
2d952d8e9 Update raylib_api.* by CI
d7148f5f9 REDESIGNED: Base64 encoding/decoding functions
5ddd13b77 REVIEWED: Hexadecimal formatting to be consistent
8d9c1cecb Update raylib_api.* by CI
afb52b19a WARNING: REDESIGNED: `EncodeDataBase64()`, NULL terminated string returned
21f0fe2a7 Removed some spaces
e3b9dbe75 Merge pull request #4947 from padmadevd/master
b6daa48a9 Update rcore_android.c
a1d57e83f Merge pull request #4948 from parzivail/bug/meshnormals
21e711b13 Fix typo in mesh animNormals
5da2d1011 Update rcore_android.c
2be18e2c5 Merge pull request #4944 from Pivok7/master
0ffc8c517 Pbr example fix
8c99a508c REVIEWED: `WindowSizeCallback()`, GLFW
a51d33444 Merge branch 'master' of https://github.com/raysan5/raylib
9d4c31533 Update rtext.c
15a0cf89b Merge pull request #4936 from lumenkeyes/master
ba3121914 Merge pull request #4937 from Bigfoot71/fix-gen-tangents
5076d5743 Merge pull request #4938 from JeffM2501/const_save_callback
4a1e9931a Update raylib_api.* by CI
aa684a33d make save file callback match const correctness of calling function
d135eef46 fix and improve `GenMeshTangents`
6f11e27bb fix typo
dea6a2477 build.zig fix: link EGL for Android
63b988ade Update raylib_api.* by CI
f7d03efb4 REVIEWED: `DecodeDataBase64()`, follow convention:
3083f0cd4 REVIEWED: `SaveFileText()`, const input text
693c9c292 Formatting tweaks
4ac31f7cd Merge pull request #4928 from JeffM2501/unload_default_font
ebaa922f6 Properly clean up the default font on unload, it may be reused if the window is created again
7e0727836 Update rprand.h
1402e830b Merge pull request #4926 from karl-zylinski/draw-sphere-normals
6fad12db7 Merge pull request #4927 from lumenkeyes/master
35de7b26a catch error in build.zig
eae3fd83d properly detect if abi is android
c4b9c0e03 properly generate android triple in build.zig
a15548fb5 Add normals to DrawSphereEx
3d6e24af4 Merge pull request #4906 from Bigfoot71/fix-clip
512b1bed4 Merge pull request #4925 from JeffM2501/animated_meshes_GL11
e07e3354a Merge branch 'animated_meshes_GL11' of github.com:JeffM2501/raylib into animated_meshes_GL11
ee2ab11cc Use the animated verts and normals in GL 1.1 if they exist
95c96b345 Use the animated verts and normals in GL 1.1 if they exist
31d63d08e Merge pull request #4922 from Bigfoot71/review-file-dir-2
a7ad2d196 Merge pull request #4918 from JeffM2501/default_font_image_leaks
3d292a6c3 Merge pull request #4923 from JeffM2501/gltf_bone_fix
e53a43b7b Assign meshes without bone weights to the bone they are attached to so they animate.
38aec920b makes `path` static in `ScanDirectoryFilesRecursively`
03988d2ce added a NULL check in `UnloadDirectoryFiles`
c08714438 Merge branch 'raysan5:master' into fix-clip
82c87d1f6 Merge pull request #4920 from MrScautHD/patch-1
8533d284c Update BINDINGS.md
94c5de33a Make the default font loadable before InitWindow, for use with the image API. Make the default font loader early out if we have already loaded parts of it, so we don't leak memory
461c9c9d9 review tabs
a7333a9da review near/far

git-subtree-dir: libs/raylib
git-subtree-split: 9b6c09c32f7283e849918aef220ec4fa629af8d2
This commit is contained in:
sergeypdev 2025-07-19 18:18:38 +04:00
parent 6b853a6601
commit bf5a3f231b
44 changed files with 16968 additions and 13072 deletions

View File

@ -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 |
@ -49,7 +51,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| [raylib-luajit-generated](https://github.com/james2doyle/raylib-luajit-generated) | 5.5 | [Lua](http://www.lua.org) | MIT | | [raylib-luajit-generated](https://github.com/james2doyle/raylib-luajit-generated) | 5.5 | [Lua](http://www.lua.org) | MIT |
| [raylib-matte](https://github.com/jcorks/raylib-matte) | 4.6-dev | [Matte](https://github.com/jcorks/matte) | **???** | | [raylib-matte](https://github.com/jcorks/raylib-matte) | 4.6-dev | [Matte](https://github.com/jcorks/matte) | **???** |
| [Raylib.nelua](https://github.com/AuzFox/Raylib.nelua) | **5.5** | [nelua](https://nelua.io) | Zlib | | [Raylib.nelua](https://github.com/AuzFox/Raylib.nelua) | **5.5** | [nelua](https://nelua.io) | Zlib |
| [raylib-bindings](https://github.com/vaiorabbit/raylib-bindings) | 5.6-dev | [Ruby](https://www.ruby-lang.org/en) | Zlib | | [raylib-bindings](https://github.com/vaiorabbit/raylib-bindings) | 5.6-dev | [Ruby](https://www.ruby-lang.org/en) | Zlib |
| [naylib](https://github.com/planetis-m/naylib) | **5.6-dev** | [Nim](https://nim-lang.org) | MIT | | [naylib](https://github.com/planetis-m/naylib) | **5.6-dev** | [Nim](https://nim-lang.org) | MIT |
| [node-raylib](https://github.com/RobLoach/node-raylib) | 4.5 | [Node.js](https://nodejs.org/en) | Zlib | | [node-raylib](https://github.com/RobLoach/node-raylib) | 4.5 | [Node.js](https://nodejs.org/en) | Zlib |
| [raylib-odin](https://github.com/odin-lang/Odin/tree/master/vendor/raylib) | **5.5** | [Odin](https://odin-lang.org) | BSD-3Clause | | [raylib-odin](https://github.com/odin-lang/Odin/tree/master/vendor/raylib) | **5.5** | [Odin](https://odin-lang.org) | BSD-3Clause |
@ -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

252
build.zig
View File

@ -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,71 +549,154 @@ 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;
const exe = b.addExecutable(.{ if (target.result.os.tag == .emscripten) {
.name = name, const exe_lib = b.addStaticLibrary(.{
.target = target, .name = name,
.optimize = optimize, .target = target,
}); .optimize = optimize,
exe.addCSourceFile(.{ .file = b.path(path), .flags = &.{} }); });
exe.linkLibC(); exe_lib.addCSourceFile(.{
.file = b.path(path),
.flags = &.{},
});
exe_lib.linkLibC();
// special examples that test using these external dependencies directly if (std.mem.eql(u8, name, "rlgl_standalone")) {
// alongside raylib //TODO: Make rlgl_standalone example work
if (std.mem.eql(u8, name, "rlgl_standalone")) { continue;
exe.addIncludePath(b.path("src"));
exe.addIncludePath(b.path("src/external/glfw/include"));
if (!hasCSource(raylib.root_module, "rglfw.c")) {
exe.addCSourceFile(.{ .file = b.path("src/rglfw.c"), .flags = &.{} });
} }
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(.{
.name = name,
.target = target,
.optimize = optimize,
});
exe.addCSourceFile(.{ .file = b.path(path), .flags = &.{} });
exe.linkLibC();
// special examples that test using these external dependencies directly
// alongside raylib
if (std.mem.eql(u8, name, "rlgl_standalone")) {
exe.addIncludePath(b.path("src"));
exe.addIncludePath(b.path("src/external/glfw/include"));
if (!hasCSource(raylib.root_module, "rglfw.c")) {
exe.addCSourceFile(.{ .file = b.path("src/rglfw.c"), .flags = &.{} });
}
}
if (std.mem.eql(u8, name, "raylib_opengl_interop")) {
exe.addIncludePath(b.path("src/external"));
}
exe.linkLibrary(raylib);
switch (target.result.os.tag) {
.windows => {
exe.linkSystemLibrary("winmm");
exe.linkSystemLibrary("gdi32");
exe.linkSystemLibrary("opengl32");
exe.root_module.addCMacro("PLATFORM_DESKTOP", "");
},
.linux => {
exe.linkSystemLibrary("GL");
exe.linkSystemLibrary("rt");
exe.linkSystemLibrary("dl");
exe.linkSystemLibrary("m");
exe.linkSystemLibrary("X11");
exe.root_module.addCMacro("PLATFORM_DESKTOP", "");
},
.macos => {
exe.linkFramework("Foundation");
exe.linkFramework("Cocoa");
exe.linkFramework("OpenGL");
exe.linkFramework("CoreAudio");
exe.linkFramework("CoreVideo");
exe.linkFramework("IOKit");
exe.root_module.addCMacro("PLATFORM_DESKTOP", "");
},
else => {
@panic("Unsupported OS");
},
}
const install_cmd = b.addInstallArtifact(exe, .{});
const run_cmd = b.addRunArtifact(exe);
run_cmd.cwd = b.path(module_subpath);
run_cmd.step.dependOn(&install_cmd.step);
const run_step = b.step(name, name);
run_step.dependOn(&run_cmd.step);
all.dependOn(&install_cmd.step);
} }
if (std.mem.eql(u8, name, "raylib_opengl_interop")) {
exe.addIncludePath(b.path("src/external"));
}
exe.linkLibrary(raylib);
switch (target.result.os.tag) {
.windows => {
exe.linkSystemLibrary("winmm");
exe.linkSystemLibrary("gdi32");
exe.linkSystemLibrary("opengl32");
exe.root_module.addCMacro("PLATFORM_DESKTOP", "");
},
.linux => {
exe.linkSystemLibrary("GL");
exe.linkSystemLibrary("rt");
exe.linkSystemLibrary("dl");
exe.linkSystemLibrary("m");
exe.linkSystemLibrary("X11");
exe.root_module.addCMacro("PLATFORM_DESKTOP", "");
},
.macos => {
exe.linkFramework("Foundation");
exe.linkFramework("Cocoa");
exe.linkFramework("OpenGL");
exe.linkFramework("CoreAudio");
exe.linkFramework("CoreVideo");
exe.linkFramework("IOKit");
exe.root_module.addCMacro("PLATFORM_DESKTOP", "");
},
else => {
@panic("Unsupported OS");
},
}
const install_cmd = b.addInstallArtifact(exe, .{});
const run_cmd = b.addRunArtifact(exe);
run_cmd.cwd = b.path(module_subpath);
run_cmd.step.dependOn(&install_cmd.step);
const run_step = b.step(name, name);
run_step.dependOn(&run_cmd.step);
all.dependOn(&install_cmd.step);
} }
return all; return all;
} }

View File

@ -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",
}, },
} }

View File

@ -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 \

View File

@ -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 \

View File

@ -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!

View File

@ -61,7 +61,9 @@ int main(void)
{ {
// Update // Update
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
PollInputEvents(); // Poll input events (SUPPORT_CUSTOM_FRAME_CONTROL) #ifndef PLATFORM_WEB // NOTE: On non web platforms the PollInputEvents just works before the inputs checks
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

View File

@ -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);

View File

@ -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);
@ -71,4 +71,4 @@ void main()
// Calculate final vertex position // Calculate final vertex position
gl_Position = mvp*vec4(vertexPosition, 1.0); gl_Position = mvp*vec4(vertexPosition, 1.0);
} }

View File

@ -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);
@ -45,4 +45,4 @@ void main()
// Calculate final vertex position // Calculate final vertex position
gl_Position = mvp*vec4(vertexPosition, 1.0); gl_Position = mvp*vec4(vertexPosition, 1.0);
} }

View File

@ -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;
@ -228,6 +230,10 @@ int main()
SetShaderValue(shader, textureTilingLoc, &floorTextureTiling, SHADER_UNIFORM_VEC2); SetShaderValue(shader, textureTilingLoc, &floorTextureTiling, SHADER_UNIFORM_VEC2);
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
@ -237,6 +243,10 @@ int main()
SetShaderValue(shader, emissiveColorLoc, &carEmissiveColor, SHADER_UNIFORM_VEC4); SetShaderValue(shader, emissiveColorLoc, &carEmissiveColor, SHADER_UNIFORM_VEC4);
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

View File

@ -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);

View 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);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -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);
} }

View File

@ -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": [
{ {

View File

@ -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

View File

@ -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="" />

View File

@ -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)

View File

@ -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 & \

View File

@ -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

21393
src/external/RGFW.h vendored

File diff suppressed because it is too large Load Diff

462
src/external/dr_flac.h vendored
View File

@ -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
============ ============
@ -179,7 +70,7 @@ reports metadata to the application through the use of a callback, and every met
The main opening APIs (`drflac_open()`, etc.) will fail if the header is not present. The presents a problem in certain scenarios such as broadcast style The main opening APIs (`drflac_open()`, etc.) will fail if the header is not present. The presents a problem in certain scenarios such as broadcast style
streams or internet radio where the header may not be present because the user has started playback mid-stream. To handle this, use the relaxed APIs: streams or internet radio where the header may not be present because the user has started playback mid-stream. To handle this, use the relaxed APIs:
`drflac_open_relaxed()` `drflac_open_relaxed()`
`drflac_open_with_metadata_relaxed()` `drflac_open_with_metadata_relaxed()`
@ -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;
@ -6702,10 +6636,10 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d
/* Skip to the index point count */ /* Skip to the index point count */
pRunningData += 35; pRunningData += 35;
indexCount = pRunningData[0]; indexCount = pRunningData[0];
pRunningData += 1; pRunningData += 1;
bufferSize += indexCount * sizeof(drflac_cuesheet_track_index); bufferSize += indexCount * sizeof(drflac_cuesheet_track_index);
/* Quick validation check. */ /* Quick validation check. */
@ -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,38 +7406,50 @@ 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) {
while (bytesSeeked < offset) {
int bytesRemainingToSeek = offset - bytesSeeked;
DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
DRFLAC_ASSERT(origin == drflac_seek_origin_current); if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) {
bytesSeeked += bytesRemainingToSeek;
(void)bytesSeeked; /* <-- Silence a dead store warning emitted by Clang Static Analyzer. */
oggbs->bytesRemainingInPage -= bytesRemainingToSeek;
break;
}
while (bytesSeeked < offset) { /* If we get here it means some of the requested data is contained in the next pages. */
int bytesRemainingToSeek = offset - bytesSeeked; if (oggbs->bytesRemainingInPage > 0) {
DRFLAC_ASSERT(bytesRemainingToSeek >= 0); bytesSeeked += (int)oggbs->bytesRemainingInPage;
oggbs->bytesRemainingInPage = 0;
}
if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { DRFLAC_ASSERT(bytesRemainingToSeek > 0);
bytesSeeked += bytesRemainingToSeek; if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
(void)bytesSeeked; /* <-- Silence a dead store warning emitted by Clang Static Analyzer. */ /* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */
oggbs->bytesRemainingInPage -= bytesRemainingToSeek; return DRFLAC_FALSE;
break; }
}
/* If we get here it means some of the requested data is contained in the next pages. */
if (oggbs->bytesRemainingInPage > 0) {
bytesSeeked += (int)oggbs->bytesRemainingInPage;
oggbs->bytesRemainingInPage = 0;
}
DRFLAC_ASSERT(bytesRemainingToSeek > 0);
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
/* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */
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) {
whence = SEEK_CUR;
} else if (origin == DRFLAC_SEEK_END) {
whence = SEEK_END;
}
return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; 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. */ }
} if ((size_t)newCursor > memoryStream->dataSize) {
} else { return DRFLAC_FALSE; /* Trying to seek beyond the end of the buffer. */
if ((drflac_uint32)offset <= memoryStream->dataSize) {
memoryStream->currentReadPos = offset;
} else {
return DRFLAC_FALSE; /* Trying to seek too far forward. */
}
} }
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.

899
src/external/dr_mp3.h vendored

File diff suppressed because it is too large Load Diff

492
src/external/dr_wav.h vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1813
src/external/miniaudio.h vendored

File diff suppressed because it is too large Load Diff

44
src/external/rprand.h vendored
View File

@ -15,15 +15,15 @@
* - Support 64 bits generation * - Support 64 bits generation
* *
* ADDITIONAL NOTES: * ADDITIONAL NOTES:
* This library implements two pseudo-random number generation algorithms: * This library implements two pseudo-random number generation algorithms:
* *
* - Xoshiro128** : https://prng.di.unimi.it/xoshiro128starstar.c * - Xoshiro128** : https://prng.di.unimi.it/xoshiro128starstar.c
* - SplitMix64 : https://prng.di.unimi.it/splitmix64.c * - SplitMix64 : https://prng.di.unimi.it/splitmix64.c
* *
* SplitMix64 is used to initialize the Xoshiro128** state, from a provided seed * SplitMix64 is used to initialize the Xoshiro128** state, from a provided seed
* *
* It's suggested to use SplitMix64 to initialize the state of the generators starting from * It's suggested to use SplitMix64 to initialize the state of the generators starting from
* a 64-bit seed, as research has shown that initialization must be performed with a generator * a 64-bit seed, as research has shown that initialization must be performed with a generator
* radically different in nature from the one initialized to avoid correlation on similar seeds. * radically different in nature from the one initialized to avoid correlation on similar seeds.
* *
* CONFIGURATION: * CONFIGURATION:
@ -31,7 +31,7 @@
* Generates the implementation of the library into the included file. * Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers * If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation. * or source files without problems. But only ONE file should hold the implementation.
* *
* DEPENDENCIES: none * DEPENDENCIES: none
* *
* VERSIONS HISTORY: * VERSIONS HISTORY:
@ -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)
@ -153,7 +153,7 @@ static uint32_t rprand_state[4] = { // Xoshiro128** state, initializ
0x218b21e5, 0x218b21e5,
0xaa91febd, 0xaa91febd,
0x976414d4 0x976414d4
}; };
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module internal functions declaration // Module internal functions declaration
@ -190,8 +190,8 @@ int rprand_get_value(int min, int max)
int *rprand_load_sequence(unsigned int count, int min, int max) int *rprand_load_sequence(unsigned int count, int min, int max)
{ {
int *sequence = NULL; int *sequence = NULL;
if (count > (unsigned int)(abs(max - min) + 1)) if (count > (unsigned int)(abs(max - min) + 1))
{ {
RPRAND_LOG("WARNING: Sequence count required is greater than range provided\n"); RPRAND_LOG("WARNING: Sequence count required is greater than range provided\n");
//count = (max - min); //count = (max - min);
@ -244,26 +244,26 @@ static inline uint32_t rprand_rotate_left(const uint32_t x, int k)
} }
// Xoshiro128** generator info: // Xoshiro128** generator info:
// //
// Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) // Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
// //
// To the extent possible under law, the author has dedicated all copyright // To the extent possible under law, the author has dedicated all copyright
// and related and neighboring rights to this software to the public domain // and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty. // worldwide. This software is distributed without any warranty.
// //
// See <http://creativecommons.org/publicdomain/zero/1.0/>. // See <http://creativecommons.org/publicdomain/zero/1.0/>.
// //
// This is xoshiro128** 1.1, one of our 32-bit all-purpose, rock-solid // This is xoshiro128** 1.1, one of our 32-bit all-purpose, rock-solid
// generators. It has excellent speed, a state size (128 bits) that is // generators. It has excellent speed, a state size (128 bits) that is
// large enough for mild parallelism, and it passes all tests we are aware // large enough for mild parallelism, and it passes all tests we are aware
// of. // of.
// //
// Note that version 1.0 had mistakenly s[0] instead of s[1] as state // Note that version 1.0 had mistakenly s[0] instead of s[1] as state
// word passed to the scrambler. // word passed to the scrambler.
// //
// For generating just single-precision (i.e., 32-bit) floating-point // For generating just single-precision (i.e., 32-bit) floating-point
// numbers, xoshiro128+ is even faster. // numbers, xoshiro128+ is even faster.
// //
// The state must be seeded so that it is not everywhere zero. // The state must be seeded so that it is not everywhere zero.
// //
uint32_t rprand_xoshiro(void) uint32_t rprand_xoshiro(void)
@ -275,29 +275,29 @@ uint32_t rprand_xoshiro(void)
rprand_state[3] ^= rprand_state[1]; rprand_state[3] ^= rprand_state[1];
rprand_state[1] ^= rprand_state[2]; rprand_state[1] ^= rprand_state[2];
rprand_state[0] ^= rprand_state[3]; rprand_state[0] ^= rprand_state[3];
rprand_state[2] ^= t; rprand_state[2] ^= t;
rprand_state[3] = rprand_rotate_left(rprand_state[3], 11); rprand_state[3] = rprand_rotate_left(rprand_state[3], 11);
return result; return result;
} }
// SplitMix64 generator info: // SplitMix64 generator info:
// //
// Written in 2015 by Sebastiano Vigna (vigna@acm.org) // Written in 2015 by Sebastiano Vigna (vigna@acm.org)
// //
// To the extent possible under law, the author has dedicated all copyright // To the extent possible under law, the author has dedicated all copyright
// and related and neighboring rights to this software to the public domain // and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty. // worldwide. This software is distributed without any warranty.
// //
// See <http://creativecommons.org/publicdomain/zero/1.0/>. // See <http://creativecommons.org/publicdomain/zero/1.0/>.
// //
// //
// This is a fixed-increment version of Java 8's SplittableRandom generator // This is a fixed-increment version of Java 8's SplittableRandom generator
// See http://dx.doi.org/10.1145/2714064.2660195 and // See http://dx.doi.org/10.1145/2714064.2660195 and
// http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html // http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
// //
// It is a very fast generator passing BigCrush, and it can be useful if // It is a very fast generator passing BigCrush, and it can be useful if
// for some reason you absolutely want 64 bits of state. // for some reason you absolutely want 64 bits of state.
uint64_t rprand_splitmix64() uint64_t rprand_splitmix64()

View File

@ -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;

View File

@ -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)
@ -130,9 +130,9 @@ static void CursorEnterCallback(GLFWwindow *window, int enter);
static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback
// Wrappers used by glfwInitAllocator // Wrappers used by glfwInitAllocator
static void* AllocateWrapper(size_t size, void* user); // GLFW3 GLFWallocatefun, wrapps around RL_MALLOC macro static void *AllocateWrapper(size_t size, void *user); // GLFW3 GLFWallocatefun, wrapps around RL_MALLOC macro
static void* ReallocateWrapper(void* block, size_t size, void* user); // GLFW3 GLFWreallocatefun, wrapps around RL_MALLOC macro static void *ReallocateWrapper(void *block, size_t size, void *user); // GLFW3 GLFWreallocatefun, wrapps around RL_MALLOC macro
static void DeallocateWrapper(void* block, void* user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro static void DeallocateWrapper(void *block, void *user); // GLFW3 GLFWdeallocatefun, wraps around RL_FREE macro
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Declaration // Module Functions Declaration
@ -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;
@ -1300,17 +1300,17 @@ static void SetDimensionsFromMonitor(GLFWmonitor *monitor)
// We need to provide these because GLFWallocator expects function pointers with specific signatures. // We need to provide these because GLFWallocator expects function pointers with specific signatures.
// Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch. // Similar wrappers exist in utils.c but we cannot reuse them here due to declaration mismatch.
// https://www.glfw.org/docs/latest/intro_guide.html#init_allocator // https://www.glfw.org/docs/latest/intro_guide.html#init_allocator
static void* AllocateWrapper(size_t size, void* user) static void *AllocateWrapper(size_t size, void *user)
{ {
(void)user; (void)user;
return RL_MALLOC(size); return RL_MALLOC(size);
} }
static void* ReallocateWrapper(void* block, size_t size, void* user) static void *ReallocateWrapper(void *block, size_t size, void *user)
{ {
(void)user; (void)user;
return RL_REALLOC(block, size); return RL_REALLOC(block, size);
} }
static void DeallocateWrapper(void* block, void* user) static void DeallocateWrapper(void *block, void *user)
{ {
(void)user; (void)user;
RL_FREE(block); RL_FREE(block);
@ -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)

View File

@ -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;

View File

@ -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
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -721,7 +723,7 @@ void SetWindowIcon(Image image)
bmask = 0x001F, amask = 0; bmask = 0x001F, amask = 0;
depth = 16, pitch = image.width*2; depth = 16, pitch = image.width*2;
} break; } break;
case PIXELFORMAT_UNCOMPRESSED_R8G8B8: case PIXELFORMAT_UNCOMPRESSED_R8G8B8:
{ {
// WARNING: SDL2 could be using BGR but SDL3 RGB // WARNING: SDL2 could be using BGR but SDL3 RGB
rmask = 0xFF0000, gmask = 0x00FF00; rmask = 0xFF0000, gmask = 0x00FF00;
@ -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;
}

View File

@ -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];

View File

@ -163,13 +163,13 @@ bool WindowShouldClose(void)
// REF: https://emscripten.org/docs/porting/asyncify.html // REF: https://emscripten.org/docs/porting/asyncify.html
// WindowShouldClose() is not called on a web-ready raylib application if using emscripten_set_main_loop() // WindowShouldClose() is not called on a web-ready raylib application if using emscripten_set_main_loop()
// and encapsulating one frame execution on a UpdateDrawFrame() function, // and encapsulating one frame execution on a UpdateDrawFrame() function,
// allowing the browser to manage execution asynchronously // allowing the browser to manage execution asynchronously
// Optionally we can manage the time we give-control-back-to-browser if required, // Optionally we can manage the time we give-control-back-to-browser if required,
// but it seems below line could generate stuttering on some browsers // but it seems below line could generate stuttering on some browsers
emscripten_sleep(12); emscripten_sleep(12);
return false; return false;
} }
@ -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;

View File

@ -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

View File

@ -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
@ -1123,7 +1123,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
@ -1153,8 +1153,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)
@ -1192,8 +1192,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)
@ -1264,7 +1264,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
@ -1273,7 +1275,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
@ -1406,8 +1408,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)
@ -1422,8 +1424,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
@ -1644,7 +1646,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)

View File

@ -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
@ -2314,9 +2314,12 @@ FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool
// 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)
{ {
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]); if (files.paths != NULL)
{
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
@ -2497,7 +2500,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);
@ -2536,96 +2539,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;
} }
@ -2633,38 +2652,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;
@ -2728,7 +2747,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
@ -2818,7 +2837,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
@ -3349,11 +3368,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];
} }
@ -3738,6 +3757,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);
@ -4031,10 +4051,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;

View File

@ -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

View File

@ -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; mesh->tangents[i*4 + 0] = tangent.x;
#else mesh->tangents[i*4 + 1] = tangent.y;
Vector3OrthoNormalize(&normal, &tangent); mesh->tangents[i*4 + 2] = tangent.z;
mesh->tangents[i*4 + 0] = tangent.x; mesh->tangents[i*4 + 3] = 1.0f;
mesh->tangents[i*4 + 1] = tangent.y; continue;
mesh->tangents[i*4 + 2] = tangent.z; }
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f;
#endif // 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,16 +6025,15 @@ 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++)
{ {
model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity(); model.meshes[meshIndex].boneMatrices[j] = MatrixIdentity();
} }
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);

View File

@ -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();

View File

@ -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)
{ {

View File

@ -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;
} }

View File

@ -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;