Merge branch 'master' into win32

This commit is contained in:
Ray 2025-08-31 12:00:22 +02:00 committed by GitHub
commit 65291b957a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
52 changed files with 697 additions and 671 deletions

View File

@ -7,6 +7,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
| Name | raylib Version | Language | License | | Name | raylib Version | Language | License |
| :--------------------------------------------------------------------------------------- | :--------------: | :------------------------------------------------------------------: | :------------------: | | :--------------------------------------------------------------------------------------- | :--------------: | :------------------------------------------------------------------: | :------------------: |
| [raylib](https://github.com/raysan5/raylib) | **5.5** | [C/C++](https://en.wikipedia.org/wiki/C_(programming_language)) | Zlib | | [raylib](https://github.com/raysan5/raylib) | **5.5** | [C/C++](https://en.wikipedia.org/wiki/C_(programming_language)) | Zlib |
| [raylib-ada](https://github.com/Fabien-Chouteau/raylib-ada) | **5.5** | [Ada](https://en.wikipedia.org/wiki/Ada_(programming_language)) | MIT |
| [raylib-beef](https://github.com/Starpelly/raylib-beef) | **5.5** | [Beef](https://www.beeflang.org) | MIT | | [raylib-beef](https://github.com/Starpelly/raylib-beef) | **5.5** | [Beef](https://www.beeflang.org) | MIT |
| [raybit](https://github.com/Alex-Velez/raybit) | **5.0** | [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) | MIT | | [raybit](https://github.com/Alex-Velez/raybit) | **5.0** | [Brainfuck](https://en.wikipedia.org/wiki/Brainfuck) | MIT |
| [raylib-c3](https://github.com/c3lang/vendor/tree/main/libraries/raylib55.c3l) | **5.5** | [C3](https://c3-lang.org) | MIT | | [raylib-c3](https://github.com/c3lang/vendor/tree/main/libraries/raylib55.c3l) | **5.5** | [C3](https://c3-lang.org) | MIT |

572
build.zig
View File

@ -14,61 +14,82 @@ comptime {
@compileError("Raylib requires zig version " ++ min_ver); @compileError("Raylib requires zig version " ++ min_ver);
} }
pub const emsdk = struct {
const zemscripten = @import("zemscripten");
pub fn shell(b: *std.Build) std.Build.LazyPath {
return b.dependency("raylib", .{}).path("src/shell.html");
}
pub const FlagsOptions = struct {
optimize: std.builtin.OptimizeMode,
asyncify: bool = true,
};
pub fn emccDefaultFlags(allocator: std.mem.Allocator, options: FlagsOptions) zemscripten.EmccFlags {
var emcc_flags = zemscripten.emccDefaultFlags(allocator, .{
.optimize = options.optimize,
.fsanitize = true,
});
if (options.asyncify)
emcc_flags.put("-sASYNCIFY", {}) catch unreachable;
return emcc_flags;
}
pub const SettingsOptions = struct {
optimize: std.builtin.OptimizeMode,
es3: bool = true,
emsdk_allocator: zemscripten.EmsdkAllocator = .emmalloc,
};
pub fn emccDefaultSettings(allocator: std.mem.Allocator, options: SettingsOptions) zemscripten.EmccSettings {
var emcc_settings = zemscripten.emccDefaultSettings(allocator, .{
.optimize = options.optimize,
.emsdk_allocator = options.emsdk_allocator,
});
if (options.es3)
emcc_settings.put("FULL_ES3", "1") catch unreachable;
emcc_settings.put("USE_GLFW", "3") catch unreachable;
emcc_settings.put("EXPORTED_RUNTIME_METHODS", "['requestFullscreen']") catch unreachable;
return emcc_settings;
}
pub fn emccStep(b: *std.Build, raylib: *std.Build.Step.Compile, wasm: *std.Build.Step.Compile, options: zemscripten.StepOptions) *std.Build.Step {
const activate_emsdk_step = zemscripten.activateEmsdkStep(b);
const emsdk_dep = b.dependency("emsdk", .{});
raylib.root_module.addIncludePath(emsdk_dep.path("upstream/emscripten/cache/sysroot/include"));
wasm.root_module.addIncludePath(emsdk_dep.path("upstream/emscripten/cache/sysroot/include"));
const emcc_step = zemscripten.emccStep(b, wasm, options);
emcc_step.dependOn(activate_emsdk_step);
return emcc_step;
}
pub fn emrunStep(
b: *std.Build,
html_path: []const u8,
extra_args: []const []const u8,
) *std.Build.Step {
return zemscripten.emrunStep(b, html_path, extra_args);
}
};
fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void { fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void {
switch (platform) { switch (platform) {
.glfw => raylib.root_module.addCMacro("PLATFORM_DESKTOP_GLFW", ""), .glfw => raylib.root_module.addCMacro("PLATFORM_DESKTOP_GLFW", ""),
.rgfw => raylib.root_module.addCMacro("PLATFORM_DESKTOP_RGFW", ""), .rgfw => raylib.root_module.addCMacro("PLATFORM_DESKTOP_RGFW", ""),
.sdl => raylib.root_module.addCMacro("PLATFORM_DESKTOP_SDL", ""), .sdl => raylib.root_module.addCMacro("PLATFORM_DESKTOP_SDL", ""),
.android => raylib.root_module.addCMacro("PLATFORM_ANDROID", ""), .android => raylib.root_module.addCMacro("PLATFORM_ANDROID", ""),
.drm => {}, else => {},
.win32 => raylib.root_module.addCMacro("PLATFORM_DESKTOP_WIN32", ""),
} }
} }
fn createEmsdkStep(b: *std.Build, emsdk: *std.Build.Dependency) *std.Build.Step.Run {
if (builtin.os.tag == .windows) {
return b.addSystemCommand(&.{emsdk.path("emsdk.bat").getPath(b)});
} else {
return b.addSystemCommand(&.{emsdk.path("emsdk").getPath(b)});
}
}
fn emSdkSetupStep(b: *std.Build, emsdk: *std.Build.Dependency) !?*std.Build.Step.Run {
const dot_emsc_path = emsdk.path(".emscripten").getPath(b);
const dot_emsc_exists = !std.meta.isError(std.fs.accessAbsolute(dot_emsc_path, .{}));
if (!dot_emsc_exists) {
const emsdk_install = createEmsdkStep(b, emsdk);
emsdk_install.addArgs(&.{ "install", "latest" });
const emsdk_activate = createEmsdkStep(b, emsdk);
emsdk_activate.addArgs(&.{ "activate", "latest" });
emsdk_activate.step.dependOn(&emsdk_install.step);
return emsdk_activate;
} else {
return null;
}
}
// 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
@ -100,10 +121,20 @@ const config_h_flags = outer: {
break :outer flags[0..i].*; break :outer flags[0..i].*;
}; };
pub fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile {
var raylib_flags_arr: std.ArrayList([]const u8) = .empty; var raylib_flags_arr: std.ArrayList([]const u8) = .empty;
defer raylib_flags_arr.deinit(b.allocator); defer raylib_flags_arr.deinit(b.allocator);
const raylib = b.addLibrary(.{
.name = "raylib",
.linkage = options.linkage,
.root_module = b.createModule(.{
.optimize = optimize,
.target = target,
.link_libc = true,
}),
});
try raylib_flags_arr.appendSlice( try raylib_flags_arr.appendSlice(
b.allocator, b.allocator,
&[_][]const u8{ &[_][]const u8{
@ -114,7 +145,7 @@ pub fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize:
}, },
); );
if (options.shared) { if (options.linkage == .dynamic) {
try raylib_flags_arr.appendSlice( try raylib_flags_arr.appendSlice(
b.allocator, b.allocator,
&[_][]const u8{ &[_][]const u8{
@ -160,16 +191,6 @@ pub fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize:
try raylib_flags_arr.appendSlice(b.allocator, &config_h_flags); try raylib_flags_arr.appendSlice(b.allocator, &config_h_flags);
} }
const raylib = b.addLibrary(.{
.name = "raylib",
.linkage = if (options.shared) .dynamic else .static,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});
raylib.linkLibC();
// No GLFW required on PLATFORM_DRM // No GLFW required on PLATFORM_DRM
if (options.platform != .drm) { if (options.platform != .drm) {
raylib.addIncludePath(b.path("src/external/glfw/include")); raylib.addIncludePath(b.path("src/external/glfw/include"));
@ -211,23 +232,22 @@ pub fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize:
.glfw => try c_source_files.append(b.allocator, "src/rglfw.c"), .glfw => try c_source_files.append(b.allocator, "src/rglfw.c"),
.rgfw, .sdl, .drm, .android, .win32 => {}, .rgfw, .sdl, .drm, .android, .win32 => {},
} }
raylib.linkSystemLibrary("shcore"); raylib.root_module.linkSystemLibrary("winmm", .{});
raylib.linkSystemLibrary("winmm"); raylib.root_module.linkSystemLibrary("gdi32", .{});
raylib.linkSystemLibrary("gdi32"); raylib.root_module.linkSystemLibrary("opengl32", .{});
raylib.linkSystemLibrary("opengl32");
setDesktopPlatform(raylib, options.platform); setDesktopPlatform(raylib, options.platform);
}, },
.linux => { .linux => {
if (options.platform == .drm) { if (options.platform == .drm) {
if (options.opengl_version == .auto) { if (options.opengl_version == .auto) {
raylib.linkSystemLibrary("GLESv2"); raylib.root_module.linkSystemLibrary("GLESv2", .{});
raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", ""); raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", "");
} }
raylib.linkSystemLibrary("EGL"); raylib.root_module.linkSystemLibrary("EGL", .{});
raylib.linkSystemLibrary("gbm"); raylib.root_module.linkSystemLibrary("gbm", .{});
raylib.linkSystemLibrary2("libdrm", .{ .use_pkg_config = .force }); raylib.root_module.linkSystemLibrary("libdrm", .{ .use_pkg_config = .force });
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", "");
@ -262,12 +282,12 @@ pub fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize:
const androidAsmPath = try std.fs.path.join(b.allocator, &.{ androidIncludePath, "/asm-generic" }); const androidAsmPath = try std.fs.path.join(b.allocator, &.{ androidIncludePath, "/asm-generic" });
const androidGluePath = try std.fs.path.join(b.allocator, &.{ androidNdkPathString, "/sources/android/native_app_glue/" }); const androidGluePath = try std.fs.path.join(b.allocator, &.{ androidNdkPathString, "/sources/android/native_app_glue/" });
raylib.addLibraryPath(.{ .cwd_relative = androidLibPath }); raylib.root_module.addLibraryPath(.{ .cwd_relative = androidLibPath });
raylib.root_module.addLibraryPath(.{ .cwd_relative = androidApiSpecificPath }); raylib.root_module.addLibraryPath(.{ .cwd_relative = androidApiSpecificPath });
raylib.addSystemIncludePath(.{ .cwd_relative = androidIncludePath }); raylib.root_module.addSystemIncludePath(.{ .cwd_relative = androidIncludePath });
raylib.addSystemIncludePath(.{ .cwd_relative = androidArchIncludePath }); raylib.root_module.addSystemIncludePath(.{ .cwd_relative = androidArchIncludePath });
raylib.addSystemIncludePath(.{ .cwd_relative = androidAsmPath }); raylib.root_module.addSystemIncludePath(.{ .cwd_relative = androidAsmPath });
raylib.addSystemIncludePath(.{ .cwd_relative = androidGluePath }); raylib.root_module.addSystemIncludePath(.{ .cwd_relative = androidGluePath });
var libcData: std.ArrayList(u8) = .empty; var libcData: std.ArrayList(u8) = .empty;
var aw: std.Io.Writer.Allocating = .fromArrayList(b.allocator, &libcData); var aw: std.Io.Writer.Allocating = .fromArrayList(b.allocator, &libcData);
@ -291,15 +311,15 @@ pub fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize:
if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) { if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) {
raylib.root_module.addCMacro("_GLFW_X11", ""); raylib.root_module.addCMacro("_GLFW_X11", "");
raylib.linkSystemLibrary("GLX"); raylib.root_module.linkSystemLibrary("GLX", .{});
raylib.linkSystemLibrary("X11"); raylib.root_module.linkSystemLibrary("X11", .{});
raylib.linkSystemLibrary("Xcursor"); raylib.root_module.linkSystemLibrary("Xcursor", .{});
raylib.linkSystemLibrary("Xext"); raylib.root_module.linkSystemLibrary("Xext", .{});
raylib.linkSystemLibrary("Xfixes"); raylib.root_module.linkSystemLibrary("Xfixes", .{});
raylib.linkSystemLibrary("Xi"); raylib.root_module.linkSystemLibrary("Xi", .{});
raylib.linkSystemLibrary("Xinerama"); raylib.root_module.linkSystemLibrary("Xinerama", .{});
raylib.linkSystemLibrary("Xrandr"); raylib.root_module.linkSystemLibrary("Xrandr", .{});
raylib.linkSystemLibrary("Xrender"); raylib.root_module.linkSystemLibrary("Xrender", .{});
} }
if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) { if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) {
@ -311,9 +331,9 @@ pub fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize:
@panic("`wayland-scanner` not found"); @panic("`wayland-scanner` not found");
}; };
raylib.root_module.addCMacro("_GLFW_WAYLAND", ""); raylib.root_module.addCMacro("_GLFW_WAYLAND", "");
raylib.linkSystemLibrary("EGL"); raylib.root_module.linkSystemLibrary("EGL", .{});
raylib.linkSystemLibrary("wayland-client"); raylib.root_module.linkSystemLibrary("wayland-client", .{});
raylib.linkSystemLibrary("xkbcommon"); raylib.root_module.linkSystemLibrary("xkbcommon", .{});
waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol"); waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol");
waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol"); waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol");
waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol"); waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol");
@ -329,25 +349,25 @@ pub fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize:
}, },
.freebsd, .openbsd, .netbsd, .dragonfly => { .freebsd, .openbsd, .netbsd, .dragonfly => {
try c_source_files.append(b.allocator, "rglfw.c"); try c_source_files.append(b.allocator, "rglfw.c");
raylib.linkSystemLibrary("GL"); raylib.root_module.linkSystemLibrary("GL", .{});
raylib.linkSystemLibrary("rt"); raylib.root_module.linkSystemLibrary("rt", .{});
raylib.linkSystemLibrary("dl"); raylib.root_module.linkSystemLibrary("dl", .{});
raylib.linkSystemLibrary("m"); raylib.root_module.linkSystemLibrary("m", .{});
raylib.linkSystemLibrary("X11"); raylib.root_module.linkSystemLibrary("X11", .{});
raylib.linkSystemLibrary("Xrandr"); raylib.root_module.linkSystemLibrary("Xrandr", .{});
raylib.linkSystemLibrary("Xinerama"); raylib.root_module.linkSystemLibrary("Xinerama", .{});
raylib.linkSystemLibrary("Xi"); raylib.root_module.linkSystemLibrary("Xi", .{});
raylib.linkSystemLibrary("Xxf86vm"); raylib.root_module.linkSystemLibrary("Xxf86vm", .{});
raylib.linkSystemLibrary("Xcursor"); raylib.root_module.linkSystemLibrary("Xcursor", .{});
setDesktopPlatform(raylib, options.platform); setDesktopPlatform(raylib, options.platform);
}, },
.macos => { .macos => {
// Include xcode_frameworks for cross compilation // Include xcode_frameworks for cross compilation
if (b.lazyDependency("xcode_frameworks", .{})) |dep| { if (b.lazyDependency("xcode_frameworks", .{})) |dep| {
raylib.addSystemFrameworkPath(dep.path("Frameworks")); raylib.root_module.addSystemFrameworkPath(dep.path("Frameworks"));
raylib.addSystemIncludePath(dep.path("include")); raylib.root_module.addSystemIncludePath(dep.path("include"));
raylib.addLibraryPath(dep.path("lib")); raylib.root_module.addLibraryPath(dep.path("lib"));
} }
// On macos rglfw.c include Objective-C files. // On macos rglfw.c include Objective-C files.
@ -357,26 +377,18 @@ pub fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize:
.flags = raylib_flags_arr.items, .flags = raylib_flags_arr.items,
}); });
_ = raylib_flags_arr.pop(); _ = raylib_flags_arr.pop();
raylib.linkFramework("Foundation"); raylib.root_module.linkFramework("Foundation", .{});
raylib.linkFramework("CoreServices"); raylib.root_module.linkFramework("CoreServices", .{});
raylib.linkFramework("CoreGraphics"); raylib.root_module.linkFramework("CoreGraphics", .{});
raylib.linkFramework("AppKit"); raylib.root_module.linkFramework("AppKit", .{});
raylib.linkFramework("IOKit"); raylib.root_module.linkFramework("IOKit", .{});
setDesktopPlatform(raylib, options.platform); setDesktopPlatform(raylib, options.platform);
}, },
.emscripten => { .emscripten => {
if (b.lazyDependency("emsdk", .{})) |dep| {
if (try emSdkSetupStep(b, dep)) |emSdkStep| {
raylib.step.dependOn(&emSdkStep.step);
}
raylib.addIncludePath(dep.path("upstream/emscripten/cache/sysroot/include"));
}
raylib.root_module.addCMacro("PLATFORM_WEB", ""); raylib.root_module.addCMacro("PLATFORM_WEB", "");
if (options.opengl_version == .auto) { if (options.opengl_version == .auto) {
raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", ""); raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES3", "");
} }
}, },
else => { else => {
@ -398,9 +410,9 @@ pub fn addRaygui(b: *std.Build, raylib: *std.Build.Step.Compile, raygui_dep: *st
raylib.step.dependOn(&gen_step.step); raylib.step.dependOn(&gen_step.step);
const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n"); const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n");
raylib.addCSourceFile(.{ .file = raygui_c_path }); raylib.root_module.addCSourceFile(.{ .file = raygui_c_path });
raylib.addIncludePath(raygui_dep.path("src")); raylib.root_module.addIncludePath(raygui_dep.path("src"));
raylib.addIncludePath(raylib_dep.path("src")); raylib.root_module.addIncludePath(raylib_dep.path("src"));
raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h"); raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h");
} }
@ -412,7 +424,7 @@ pub const Options = struct {
rtext: bool = true, rtext: bool = true,
rtextures: bool = true, rtextures: bool = true,
platform: PlatformBackend = .glfw, platform: PlatformBackend = .glfw,
shared: bool = false, linkage: std.builtin.LinkMode = .static,
linux_display_backend: LinuxDisplayBackend = .Both, linux_display_backend: LinuxDisplayBackend = .Both,
opengl_version: OpenglVersion = .auto, opengl_version: OpenglVersion = .auto,
android_ndk: []const u8 = "", android_ndk: []const u8 = "",
@ -430,7 +442,7 @@ pub const Options = struct {
.rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext, .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext,
.rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures, .rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures,
.rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes, .rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes,
.shared = b.option(bool, "shared", "Compile as shared library") orelse defaults.shared, .linkage = b.option(std.builtin.LinkMode, "linkage", "Compile as shared or static library") orelse defaults.linkage,
.linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend, .linux_display_backend = b.option(LinuxDisplayBackend, "linux_display_backend", "Linux display backend to use") orelse defaults.linux_display_backend,
.opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version, .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version,
.config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{}, .config = b.option([]const u8, "config", "Compile with custom define macros overriding config.h") orelse &.{},
@ -478,14 +490,7 @@ pub const PlatformBackend = enum {
}; };
pub fn build(b: *std.Build) !void { pub fn build(b: *std.Build) !void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
// Standard optimization options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
// set a preferred release mode, allowing the user to decide how to optimize.
const optimize = b.standardOptimizeOption(.{}); const optimize = b.standardOptimizeOption(.{});
const lib = try compileRaylib(b, target, optimize, Options.getOptions(b)); const lib = try compileRaylib(b, target, optimize, Options.getOptions(b));
@ -508,6 +513,145 @@ pub fn build(b: *std.Build) !void {
examples.dependOn(try addExamples("textures", b, target, optimize, lib)); examples.dependOn(try addExamples("textures", b, target, optimize, lib));
} }
fn addExamples(
comptime module: []const u8,
b: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
raylib: *std.Build.Step.Compile,
) !*std.Build.Step {
const all = b.step(module, "All " ++ module ++ " examples");
const module_subpath = b.pathJoin(&.{ "examples", module });
var dir = try std.fs.cwd().openDir(b.pathFromRoot(module_subpath), .{ .iterate = true });
defer dir.close();
var iter = dir.iterate();
while (try iter.next()) |entry| {
if (entry.kind != .file) continue;
const extension_idx = std.mem.lastIndexOf(u8, entry.name, ".c") orelse continue;
const name = entry.name[0..extension_idx];
const path = b.pathJoin(&.{ module_subpath, entry.name });
// 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;
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFile(.{ .file = b.path(path), .flags = &.{} });
exe_mod.linkLibrary(raylib);
const run_step = b.step(name, name);
if (target.result.os.tag == .emscripten) {
const wasm = b.addLibrary(.{
.name = name,
.linkage = .static,
.root_module = exe_mod,
});
if (std.mem.eql(u8, name, "rlgl_standalone")) {
//TODO: Make rlgl_standalone example work
continue;
}
if (std.mem.eql(u8, name, "raylib_opengl_interop")) {
//TODO: Make raylib_opengl_interop example work
continue;
}
const emcc_flags = emsdk.emccDefaultFlags(b.allocator, .{ .optimize = optimize });
const emcc_settings = emsdk.emccDefaultSettings(b.allocator, .{ .optimize = optimize });
const install_dir: std.Build.InstallDir = .{ .custom = "htmlout" };
const emcc_step = emsdk.emccStep(b, raylib, wasm, .{
.optimize = optimize,
.flags = emcc_flags,
.settings = emcc_settings,
.shell_file_path = b.path("src/shell.html"),
.embed_paths = &.{
.{
.src_path = b.pathJoin(&.{ module_subpath, "resources" }),
.virtual_path = "resources",
},
},
.install_dir = install_dir,
});
const html_filename = try std.fmt.allocPrint(b.allocator, "{s}.html", .{wasm.name});
const emrun_step = emsdk.emrunStep(
b,
b.getInstallPath(install_dir, html_filename),
&.{"--no_browser"},
);
emrun_step.dependOn(emcc_step);
run_step.dependOn(emrun_step);
all.dependOn(emcc_step);
} else {
// special examples that test using these external dependencies directly
// alongside raylib
if (std.mem.eql(u8, name, "rlgl_standalone")) {
exe_mod.addIncludePath(b.path("src"));
exe_mod.addIncludePath(b.path("src/external/glfw/include"));
if (!hasCSource(raylib.root_module, "rglfw.c")) {
exe_mod.addCSourceFile(.{ .file = b.path("src/rglfw.c"), .flags = &.{} });
}
}
if (std.mem.eql(u8, name, "raylib_opengl_interop")) {
exe_mod.addIncludePath(b.path("src/external"));
}
switch (target.result.os.tag) {
.windows => {
exe_mod.linkSystemLibrary("winmm", .{});
exe_mod.linkSystemLibrary("gdi32", .{});
exe_mod.linkSystemLibrary("opengl32", .{});
exe_mod.addCMacro("PLATFORM_DESKTOP", "");
},
.linux => {
exe_mod.linkSystemLibrary("GL", .{});
exe_mod.linkSystemLibrary("rt", .{});
exe_mod.linkSystemLibrary("dl", .{});
exe_mod.linkSystemLibrary("m", .{});
exe_mod.linkSystemLibrary("X11", .{});
exe_mod.addCMacro("PLATFORM_DESKTOP", "");
},
.macos => {
exe_mod.linkFramework("Foundation", .{});
exe_mod.linkFramework("Cocoa", .{});
exe_mod.linkFramework("OpenGL", .{});
exe_mod.linkFramework("CoreAudio", .{});
exe_mod.linkFramework("CoreVideo", .{});
exe_mod.linkFramework("IOKit", .{});
exe_mod.addCMacro("PLATFORM_DESKTOP", "");
},
else => {
@panic("Unsupported OS");
},
}
const exe = b.addExecutable(.{
.name = name,
.root_module = exe_mod,
});
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);
run_step.dependOn(&run_cmd.step);
all.dependOn(&install_cmd.step);
}
}
return all;
}
fn waylandGenerate( fn waylandGenerate(
b: *std.Build, b: *std.Build,
raylib: *std.Build.Step.Compile, raylib: *std.Build.Step.Compile,
@ -521,196 +665,16 @@ fn waylandGenerate(
const client_step = b.addSystemCommand(&.{ "wayland-scanner", "client-header" }); const client_step = b.addSystemCommand(&.{ "wayland-scanner", "client-header" });
client_step.addFileArg(b.path(protocolDir)); client_step.addFileArg(b.path(protocolDir));
raylib.addIncludePath(client_step.addOutputFileArg(clientHeader).dirname()); raylib.root_module.addIncludePath(client_step.addOutputFileArg(clientHeader).dirname());
const private_step = b.addSystemCommand(&.{ "wayland-scanner", "private-code" }); const private_step = b.addSystemCommand(&.{ "wayland-scanner", "private-code" });
private_step.addFileArg(b.path(protocolDir)); private_step.addFileArg(b.path(protocolDir));
raylib.addIncludePath(private_step.addOutputFileArg(privateCode).dirname()); raylib.root_module.addIncludePath(private_step.addOutputFileArg(privateCode).dirname());
raylib.step.dependOn(&client_step.step); raylib.step.dependOn(&client_step.step);
raylib.step.dependOn(&private_step.step); raylib.step.dependOn(&private_step.step);
} }
fn addExamples(
comptime module: []const u8,
b: *std.Build,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
raylib: *std.Build.Step.Compile,
) !*std.Build.Step {
const all = b.step(module, "All " ++ module ++ " examples");
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 });
defer if (comptime builtin.zig_version.minor >= 12) dir.close();
var iter = dir.iterate();
while (try iter.next()) |entry| {
if (entry.kind != .file) continue;
const extension_idx = std.mem.lastIndexOf(u8, entry.name, ".c") orelse continue;
const name = entry.name[0..extension_idx];
const path = b.pathJoin(&.{ module_subpath, entry.name });
// 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 (target.result.os.tag == .emscripten) {
const exe_lib = b.addLibrary(.{
.name = name,
.linkage = .static,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});
exe_lib.addCSourceFile(.{
.file = b.path(path),
.flags = &.{},
});
exe_lib.linkLibC();
if (std.mem.eql(u8, name, "rlgl_standalone")) {
//TODO: Make rlgl_standalone example work
continue;
}
if (std.mem.eql(u8, name, "raylib_opengl_interop")) {
//TODO: Make raylib_opengl_interop example work
continue;
}
exe_lib.linkLibrary(raylib);
// Include emscripten for cross compilation
if (b.lazyDependency("emsdk", .{})) |emsdk_dep| {
if (try emSdkSetupStep(b, emsdk_dep)) |emSdkStep| {
exe_lib.step.dependOn(&emSdkStep.step);
}
exe_lib.addIncludePath(emsdk_dep.path("upstream/emscripten/cache/sysroot/include"));
// Create the output directory because emcc can't do it.
const emccOutputDirExample = b.pathJoin(&.{ emccOutputDir, name, std.fs.path.sep_str });
const mkdir_command = switch (builtin.os.tag) {
.windows => b.addSystemCommand(&.{ "cmd.exe", "/c", "if", "not", "exist", emccOutputDirExample, "mkdir", emccOutputDirExample }),
else => b.addSystemCommand(&.{ "mkdir", "-p", emccOutputDirExample }),
};
const emcc_exe = switch (builtin.os.tag) {
.windows => "emcc.bat",
else => "emcc",
};
const emcc_exe_path = b.pathJoin(&.{ emsdk_dep.path("upstream/emscripten").getPath(b), emcc_exe });
const emcc_command = b.addSystemCommand(&[_][]const u8{emcc_exe_path});
emcc_command.step.dependOn(&mkdir_command.step);
const emccOutputDirExampleWithFile = b.pathJoin(&.{ emccOutputDir, name, std.fs.path.sep_str, emccOutputFile });
emcc_command.addArgs(&[_][]const u8{
"-o",
emccOutputDirExampleWithFile,
"-sFULL-ES3=1",
"-sUSE_GLFW=3",
"-sSTACK_OVERFLOW_CHECK=1",
"-sEXPORTED_RUNTIME_METHODS=['requestFullscreen']",
"-sASYNCIFY",
"-O0",
"--emrun",
"--preload-file",
module_resources,
"--shell-file",
b.path("src/shell.html").getPath(b),
});
const link_items: []const *std.Build.Step.Compile = &.{
raylib,
exe_lib,
};
for (link_items) |item| {
emcc_command.addFileArg(item.getEmittedBin());
emcc_command.step.dependOn(&item.step);
}
const run_step = try emscriptenRunStep(b, emsdk_dep, emccOutputDirExampleWithFile);
run_step.step.dependOn(&emcc_command.step);
run_step.addArg("--no_browser");
const run_option = b.step(name, name);
run_option.dependOn(&run_step.step);
all.dependOn(&emcc_command.step);
}
} else {
const exe = b.addExecutable(.{
.name = name,
.root_module = b.createModule(.{
.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);
}
}
return all;
}
fn hasCSource(module: *std.Build.Module, name: []const u8) bool { fn hasCSource(module: *std.Build.Module, name: []const u8) bool {
for (module.link_objects.items) |o| switch (o) { for (module.link_objects.items) |o| switch (o) {
.c_source_file => |c| if (switch (c.file) { .c_source_file => |c| if (switch (c.file) {

View File

@ -1,6 +1,6 @@
.{ .{
.name = .raylib, .name = .raylib,
.version = "5.5.0", .version = "5.6.0-dev",
.minimum_zig_version = "0.15.1", .minimum_zig_version = "0.15.1",
.fingerprint = 0x13035e5cb8bc1ac2, // Changing this has security and trust implications. .fingerprint = 0x13035e5cb8bc1ac2, // Changing this has security and trust implications.
@ -14,7 +14,10 @@
.emsdk = .{ .emsdk = .{
.url = "git+https://github.com/emscripten-core/emsdk#4.0.9", .url = "git+https://github.com/emscripten-core/emsdk#4.0.9",
.hash = "N-V-__8AAJl1DwBezhYo_VE6f53mPVm00R-Fk28NPW7P14EQ", .hash = "N-V-__8AAJl1DwBezhYo_VE6f53mPVm00R-Fk28NPW7P14EQ",
.lazy = true, },
.zemscripten = .{
.url = "git+https://github.com/zig-gamedev/zemscripten#3fa4b778852226c7346bdcc3c1486e875a9a6d02",
.hash = "zemscripten-0.2.0-dev-sRlDqApRAACspTbAZnuNKWIzfWzSYgYkb2nWAXZ-tqqt",
}, },
}, },

View File

@ -175,7 +175,6 @@ static void DrawTextCenterKeyHelp(const char *key, const char *text, int posX, i
int spaceSize = MeasureText(" ", fontSize); int spaceSize = MeasureText(" ", fontSize);
int pressSize = MeasureText("Press", fontSize); int pressSize = MeasureText("Press", fontSize);
int keySize = MeasureText(key, fontSize); int keySize = MeasureText(key, fontSize);
int textSize = MeasureText(text, fontSize);
int textSizeCurrent = 0; int textSizeCurrent = 0;
DrawText("Press", posX, posY, fontSize, color); DrawText("Press", posX, posY, fontSize, color);

View File

@ -18,6 +18,7 @@
#include "raylib.h" #include "raylib.h"
#include "raymath.h" #include "raymath.h"
#undef FLT_MAX
#define FLT_MAX 340282346638528859811704183484516925440.0f // Maximum value of a float, from bit pattern 01111111011111111111111111111111 #define FLT_MAX 340282346638528859811704183484516925440.0f // Maximum value of a float, from bit pattern 01111111011111111111111111111111
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------

View File

@ -161,9 +161,9 @@ static Mesh GenMeshPoints(int numPoints)
// https://en.wikipedia.org/wiki/Spherical_coordinate_system // https://en.wikipedia.org/wiki/Spherical_coordinate_system
for (int i = 0; i < numPoints; i++) for (int i = 0; i < numPoints; i++)
{ {
float theta = ((float)PI*rand())/RAND_MAX; float theta = ((float)PI*rand())/((float)RAND_MAX);
float phi = (2.0f*PI*rand())/RAND_MAX; float phi = (2.0f*PI*rand())/((float)RAND_MAX);
float r = (10.0f*rand())/RAND_MAX; float r = (10.0f*rand())/((float)RAND_MAX);
mesh.vertices[i*3 + 0] = r*sinf(theta)*cosf(phi); mesh.vertices[i*3 + 0] = r*sinf(theta)*cosf(phi);
mesh.vertices[i*3 + 1] = r*sinf(theta)*sinf(phi); mesh.vertices[i*3 + 1] = r*sinf(theta)*sinf(phi);

View File

@ -15,7 +15,7 @@
* BSD-like license that allows static linking with closed source software * BSD-like license that allows static linking with closed source software
* *
* Copyright (c) 2025-2025 Jeremy Montgomery (@Sir_Irk) and Ramon Santamaria (@raysan5) * Copyright (c) 2025-2025 Jeremy Montgomery (@Sir_Irk) and Ramon Santamaria (@raysan5)
*k *
********************************************************************************************/ ********************************************************************************************/
#include <raylib.h> #include <raylib.h>

View File

@ -164,7 +164,7 @@ static void DrawClock(Clock clock, Vector2 centerPosition)
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.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.minute.value), centerPosition.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); 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);
} }

View File

@ -42,7 +42,7 @@
#define DrawTextW DrawTextWin32 #define DrawTextW DrawTextWin32
#define DrawTextExA DrawTextExAWin32 #define DrawTextExA DrawTextExAWin32
#define DrawTextExW DrawTextExWin32 #define DrawTextExW DrawTextExWin32
#define PlaySoundA PlaySoundAWin32\ #define PlaySoundA PlaySoundAWin32
// include windows // include windows
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>

View File

@ -24,7 +24,7 @@
* Custom flag for rcore on target platform -not used- * Custom flag for rcore on target platform -not used-
* *
* DEPENDENCIES: * DEPENDENCIES:
* - rglfw: Manage graphic device, OpenGL context and inputs (Windows, Linux, OSX, FreeBSD...) * - rglfw: Manage graphic device, OpenGL context and inputs (Windows, Linux, OSX/macOS, FreeBSD...)
* - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs) * - gestures: Gestures system for touch-ready devices (or simulated from mouse inputs)
* *
* *

View File

@ -53,6 +53,7 @@
#include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr() #include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
#include <pthread.h> // POSIX threads management (inputs reading) #include <pthread.h> // POSIX threads management (inputs reading)
#include <dirent.h> // POSIX directory browsing #include <dirent.h> // POSIX directory browsing
#include <limits.h> // INT_MAX
#include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations #include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition #include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
@ -2150,6 +2151,8 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
if (NULL == connector) return -1; if (NULL == connector) return -1;
int nearestIndex = -1; int nearestIndex = -1;
int minUnusedPixels = INT_MAX;
int minFpsDiff = INT_MAX;
for (int i = 0; i < platform.connector->count_modes; i++) for (int i = 0; i < platform.connector->count_modes; i++)
{ {
const drmModeModeInfo *const mode = &platform.connector->modes[i]; const drmModeModeInfo *const mode = &platform.connector->modes[i];
@ -2169,21 +2172,17 @@ static int FindNearestConnectorMode(const drmModeConnector *connector, uint widt
continue; continue;
} }
if (nearestIndex < 0) const int unusedPixels = (mode->hdisplay - width) * (mode->vdisplay - height);
const int fpsDiff = mode->vrefresh - fps;
if ((unusedPixels < minUnusedPixels) ||
((unusedPixels == minUnusedPixels) && (abs(fpsDiff) < abs(minFpsDiff))) ||
((unusedPixels == minUnusedPixels) && (abs(fpsDiff) == abs(minFpsDiff)) && (fpsDiff > 0)))
{ {
nearestIndex = i; nearestIndex = i;
continue; minUnusedPixels = unusedPixels;
minFpsDiff = fpsDiff;
} }
const int widthDiff = abs(mode->hdisplay - width);
const int heightDiff = abs(mode->vdisplay - height);
const int fpsDiff = abs(mode->vrefresh - fps);
const int nearestWidthDiff = abs(platform.connector->modes[nearestIndex].hdisplay - width);
const int nearestHeightDiff = abs(platform.connector->modes[nearestIndex].vdisplay - height);
const int nearestFpsDiff = abs(platform.connector->modes[nearestIndex].vrefresh - fps);
if ((widthDiff < nearestWidthDiff) || (heightDiff < nearestHeightDiff) || (fpsDiff < nearestFpsDiff)) nearestIndex = i;
} }
return nearestIndex; return nearestIndex;

View File

@ -1466,11 +1466,11 @@ RLAPI int GetPixelDataSize(int width, int height, int format); // G
// Font loading/unloading functions // Font loading/unloading functions
RLAPI Font GetFontDefault(void); // Get the default Font RLAPI Font GetFontDefault(void); // Get the default Font
RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM)
RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height RLAPI Font LoadFontEx(const char *fileName, int fontSize, const int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height
RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style)
RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
RLAPI bool IsFontValid(Font font); // Check if a font is valid (font data loaded, WARNING: GPU texture not checked) RLAPI bool IsFontValid(Font font); // Check if a font is valid (font data loaded, WARNING: GPU texture not checked)
RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type); // Load font data for further use RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount, int type); // Load font data for further use
RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM) RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM)
RLAPI void UnloadFont(Font font); // Unload font from GPU memory (VRAM) RLAPI void UnloadFont(Font font); // Unload font from GPU memory (VRAM)
@ -1506,6 +1506,8 @@ RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size);
// Text strings management functions (no UTF-8 strings, only byte chars) // Text strings management functions (no UTF-8 strings, only byte chars)
// WARNING 1: Most of these functions use internal static buffers, it's recommended to store returned data on user-side for re-use // WARNING 1: Most of these functions use internal static buffers, it's recommended to store returned data on user-side for re-use
// WARNING 2: Some strings allocate memory internally for the returned strings, those strings must be free by user using MemFree() // WARNING 2: Some strings allocate memory internally for the returned strings, those strings must be free by user using MemFree()
RLAPI char **LoadTextLines(const char *text, int *count); // Load text as separate lines ('\n')
RLAPI void UnloadTextLines(char **text); // Unload text lines
RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied
RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal
RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending
@ -1522,7 +1524,6 @@ RLAPI char *TextToLower(const char *text);
RLAPI char *TextToPascal(const char *text); // Get Pascal case notation version of provided string RLAPI char *TextToPascal(const char *text); // Get Pascal case notation version of provided string
RLAPI char *TextToSnake(const char *text); // Get Snake case notation version of provided string RLAPI char *TextToSnake(const char *text); // Get Snake case notation version of provided string
RLAPI char *TextToCamel(const char *text); // Get Camel case notation version of provided string RLAPI char *TextToCamel(const char *text); // Get Camel case notation version of provided string
RLAPI int TextToInteger(const char *text); // Get integer value from text RLAPI int TextToInteger(const char *text); // Get integer value from text
RLAPI float TextToFloat(const char *text); // Get float value from text RLAPI float TextToFloat(const char *text); // Get float value from text

View File

@ -3243,6 +3243,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
int mipWidth = width; int mipWidth = width;
int mipHeight = height; int mipHeight = height;
int mipOffset = 0; // Mipmap data offset, only used for tracelog int mipOffset = 0; // Mipmap data offset, only used for tracelog
(void)mipOffset; // Used to avoid gcc warnings about unused variable
// NOTE: Added pointer math separately from function to avoid UBSAN complaining // NOTE: Added pointer math separately from function to avoid UBSAN complaining
unsigned char *dataPtr = NULL; unsigned char *dataPtr = NULL;

View File

@ -147,7 +147,7 @@ static int textLineSpacing = 2; // Text vertical line spacing in
static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file)
#endif #endif
#if defined(SUPPORT_FILEFORMAT_BDF) #if defined(SUPPORT_FILEFORMAT_BDF)
static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, int *codepoints, int codepointCount, int *outFontSize); static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, const int *codepoints, int codepointCount, int *outFontSize);
#endif #endif
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
@ -404,7 +404,7 @@ Font LoadFont(const char *fileName)
// Load Font from TTF or BDF font file with generation parameters // Load Font from TTF or BDF font file with generation parameters
// NOTE: You can pass an array with desired characters, those characters should be available in the font // NOTE: You can pass an array with desired characters, those characters should be available in the font
// if array is NULL, default char set is selected 32..126 // if array is NULL, default char set is selected 32..126
Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount) Font LoadFontEx(const char *fileName, int fontSize, const int *codepoints, int codepointCount)
{ {
Font font = { 0 }; Font font = { 0 };
@ -549,7 +549,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
} }
// Load font from memory buffer, fileType refers to extension: i.e. ".ttf" // Load font from memory buffer, fileType refers to extension: i.e. ".ttf"
Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount) Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount)
{ {
Font font = { 0 }; Font font = { 0 };
@ -620,7 +620,7 @@ bool IsFontValid(Font font)
// Load font data for further use // Load font data for further use
// NOTE: Requires TTF font memory data and can generate SDF data // NOTE: Requires TTF font memory data and can generate SDF data
GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type) GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount, int type)
{ {
// NOTE: Using some SDF generation default values, // NOTE: Using some SDF generation default values,
// trades off precision with ability to handle *smaller* sizes // trades off precision with ability to handle *smaller* sizes
@ -1415,6 +1415,40 @@ Rectangle GetGlyphAtlasRec(Font font, int codepoint)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Text strings management functions // Text strings management functions
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Load text as separate lines ('\n')
// WARNING: There is a limit set for number of lines and line-size
char **LoadTextLines(const char *text, int *count)
{
#define MAX_TEXTLINES_COUNT 512
#define MAX_TEXTLINES_LINE_LEN 512
char **lines = (char **)RL_CALLOC(MAX_TEXTLINES_COUNT, sizeof(char *));
for (int i = 0; i < MAX_TEXTLINES_COUNT; i++) lines[i] = (char *)RL_CALLOC(MAX_TEXTLINES_LINE_LEN, 1);
int textSize = (int)strlen(text);
int k = 0;
for (int i = 0, len = 0; (i < textSize) && (k < MAX_TEXTLINES_COUNT); i++)
{
if ((text[i] == '\n') || (len == (MAX_TEXTLINES_LINE_LEN - 1)))
{
strncpy(lines[k], &text[i - len], len);
len = 0;
k++;
}
else len++;
}
*count += k;
return lines;
}
// Unload text lines
void UnloadTextLines(char **lines)
{
for (int i = 0; i < MAX_TEXTLINES_COUNT; i++) RL_FREE(lines[i]);
RL_FREE(lines);
}
// Get text length in bytes, check for \0 character // Get text length in bytes, check for \0 character
unsigned int TextLength(const char *text) unsigned int TextLength(const char *text)
{ {
@ -2358,7 +2392,7 @@ static unsigned char HexToInt(char hex)
// Load font data for further use // Load font data for further use
// NOTE: Requires BDF font memory data // NOTE: Requires BDF font memory data
static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, int *codepoints, int codepointCount, int *outFontSize) static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, const int *codepoints, int codepointCount, int *outFontSize)
{ {
#define MAX_BUFFER_SIZE 256 #define MAX_BUFFER_SIZE 256

View File

@ -9041,7 +9041,7 @@
"name": "fontSize" "name": "fontSize"
}, },
{ {
"type": "int *", "type": "const int *",
"name": "codepoints" "name": "codepoints"
}, },
{ {
@ -9091,7 +9091,7 @@
"name": "fontSize" "name": "fontSize"
}, },
{ {
"type": "int *", "type": "const int *",
"name": "codepoints" "name": "codepoints"
}, },
{ {
@ -9129,7 +9129,7 @@
"name": "fontSize" "name": "fontSize"
}, },
{ {
"type": "int *", "type": "const int *",
"name": "codepoints" "name": "codepoints"
}, },
{ {
@ -9605,6 +9605,32 @@
} }
] ]
}, },
{
"name": "LoadTextLines",
"description": "Load text as separate lines ('\\n')",
"returnType": "char **",
"params": [
{
"type": "const char *",
"name": "text"
},
{
"type": "int *",
"name": "count"
}
]
},
{
"name": "UnloadTextLines",
"description": "Unload text lines",
"returnType": "void",
"params": [
{
"type": "char **",
"name": "text"
}
]
},
{ {
"name": "TextCopy", "name": "TextCopy",
"description": "Copy one string to another, returns bytes copied", "description": "Copy one string to another, returns bytes copied",

View File

@ -6550,7 +6550,7 @@ return {
params = { params = {
{type = "const char *", name = "fileName"}, {type = "const char *", name = "fileName"},
{type = "int", name = "fontSize"}, {type = "int", name = "fontSize"},
{type = "int *", name = "codepoints"}, {type = "const int *", name = "codepoints"},
{type = "int", name = "codepointCount"} {type = "int", name = "codepointCount"}
} }
}, },
@ -6573,7 +6573,7 @@ return {
{type = "const unsigned char *", name = "fileData"}, {type = "const unsigned char *", name = "fileData"},
{type = "int", name = "dataSize"}, {type = "int", name = "dataSize"},
{type = "int", name = "fontSize"}, {type = "int", name = "fontSize"},
{type = "int *", name = "codepoints"}, {type = "const int *", name = "codepoints"},
{type = "int", name = "codepointCount"} {type = "int", name = "codepointCount"}
} }
}, },
@ -6593,7 +6593,7 @@ return {
{type = "const unsigned char *", name = "fileData"}, {type = "const unsigned char *", name = "fileData"},
{type = "int", name = "dataSize"}, {type = "int", name = "dataSize"},
{type = "int", name = "fontSize"}, {type = "int", name = "fontSize"},
{type = "int *", name = "codepoints"}, {type = "const int *", name = "codepoints"},
{type = "int", name = "codepointCount"}, {type = "int", name = "codepointCount"},
{type = "int", name = "type"} {type = "int", name = "type"}
} }
@ -6845,6 +6845,23 @@ return {
{type = "int *", name = "utf8Size"} {type = "int *", name = "utf8Size"}
} }
}, },
{
name = "LoadTextLines",
description = "Load text as separate lines ('\\n')",
returnType = "char **",
params = {
{type = "const char *", name = "text"},
{type = "int *", name = "count"}
}
},
{
name = "UnloadTextLines",
description = "Unload text lines",
returnType = "void",
params = {
{type = "char **", name = "text"}
}
},
{ {
name = "TextCopy", name = "TextCopy",
description = "Copy one string to another, returns bytes copied", description = "Copy one string to another, returns bytes copied",

File diff suppressed because it is too large Load Diff

View File

@ -679,7 +679,7 @@
<Param type="unsigned int" name="frames" desc="" /> <Param type="unsigned int" name="frames" desc="" />
</Callback> </Callback>
</Callbacks> </Callbacks>
<Functions count="584"> <Functions count="586">
<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="" />
@ -2286,7 +2286,7 @@
<Function name="LoadFontEx" retType="Font" paramCount="4" desc="Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height"> <Function name="LoadFontEx" retType="Font" paramCount="4" desc="Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height">
<Param type="const char *" name="fileName" desc="" /> <Param type="const char *" name="fileName" desc="" />
<Param type="int" name="fontSize" desc="" /> <Param type="int" name="fontSize" desc="" />
<Param type="int *" name="codepoints" desc="" /> <Param type="const int *" name="codepoints" desc="" />
<Param type="int" name="codepointCount" desc="" /> <Param type="int" name="codepointCount" desc="" />
</Function> </Function>
<Function name="LoadFontFromImage" retType="Font" paramCount="3" desc="Load font from Image (XNA style)"> <Function name="LoadFontFromImage" retType="Font" paramCount="3" desc="Load font from Image (XNA style)">
@ -2299,7 +2299,7 @@
<Param type="const unsigned char *" name="fileData" desc="" /> <Param type="const unsigned char *" name="fileData" desc="" />
<Param type="int" name="dataSize" desc="" /> <Param type="int" name="dataSize" desc="" />
<Param type="int" name="fontSize" desc="" /> <Param type="int" name="fontSize" desc="" />
<Param type="int *" name="codepoints" desc="" /> <Param type="const int *" name="codepoints" desc="" />
<Param type="int" name="codepointCount" desc="" /> <Param type="int" name="codepointCount" desc="" />
</Function> </Function>
<Function name="IsFontValid" retType="bool" paramCount="1" desc="Check if a font is valid (font data loaded, WARNING: GPU texture not checked)"> <Function name="IsFontValid" retType="bool" paramCount="1" desc="Check if a font is valid (font data loaded, WARNING: GPU texture not checked)">
@ -2309,7 +2309,7 @@
<Param type="const unsigned char *" name="fileData" desc="" /> <Param type="const unsigned char *" name="fileData" desc="" />
<Param type="int" name="dataSize" desc="" /> <Param type="int" name="dataSize" desc="" />
<Param type="int" name="fontSize" desc="" /> <Param type="int" name="fontSize" desc="" />
<Param type="int *" name="codepoints" desc="" /> <Param type="const int *" name="codepoints" desc="" />
<Param type="int" name="codepointCount" desc="" /> <Param type="int" name="codepointCount" desc="" />
<Param type="int" name="type" desc="" /> <Param type="int" name="type" desc="" />
</Function> </Function>
@ -2435,6 +2435,13 @@
<Param type="int" name="codepoint" desc="" /> <Param type="int" name="codepoint" desc="" />
<Param type="int *" name="utf8Size" desc="" /> <Param type="int *" name="utf8Size" desc="" />
</Function> </Function>
<Function name="LoadTextLines" retType="char **" paramCount="2" desc="Load text as separate lines ('\n')">
<Param type="const char *" name="text" desc="" />
<Param type="int *" name="count" desc="" />
</Function>
<Function name="UnloadTextLines" retType="void" paramCount="1" desc="Unload text lines">
<Param type="char **" name="text" desc="" />
</Function>
<Function name="TextCopy" retType="int" paramCount="2" desc="Copy one string to another, returns bytes copied"> <Function name="TextCopy" retType="int" paramCount="2" desc="Copy one string to another, returns bytes copied">
<Param type="char *" name="dst" desc="" /> <Param type="char *" name="dst" desc="" />
<Param type="const char *" name="src" desc="" /> <Param type="const char *" name="src" desc="" />

View File

@ -148,11 +148,6 @@ static int UpdateRequiredFiles(void);
static rlExampleInfo *LoadExamplesData(const char *fileName, const char *category, bool sort, int *exCount); static rlExampleInfo *LoadExamplesData(const char *fileName, const char *category, bool sort, int *exCount);
static void UnloadExamplesData(rlExampleInfo *exInfo); static void UnloadExamplesData(rlExampleInfo *exInfo);
// Get text lines (by line-breaks '\n')
// WARNING: It does not copy text data, just returns line pointers
static char **LoadTextLines(const char *text, int *count);
static void UnloadTextLines(char **text);
// Load example info from file header // Load example info from file header
static rlExampleInfo *LoadExampleInfo(const char *exFileName); static rlExampleInfo *LoadExampleInfo(const char *exFileName);
static void UnloadExampleInfo(rlExampleInfo *exInfo); static void UnloadExampleInfo(rlExampleInfo *exInfo);
@ -1775,39 +1770,6 @@ static int FileMove(const char *srcPath, const char *dstPath)
return result; return result;
} }
// Load text lines
static char **LoadTextLines(const char *text, int *count)
{
#define MAX_TEXT_LINES 512
#define MAX_TEXT_LINE_LEN 512
char **lines = (char **)RL_CALLOC(MAX_TEXT_LINES, sizeof(char *));
for (int i = 0; i < MAX_TEXT_LINES; i++) lines[i] = (char *)RL_CALLOC(MAX_TEXT_LINE_LEN, 1);
int textSize = (int)strlen(text);
int k = 0;
for (int i = 0, len = 0; (i < textSize) && (k < MAX_TEXT_LINES); i++)
{
if ((text[i] == '\n') || (len == (MAX_TEXT_LINE_LEN - 1)))
{
strncpy(lines[k], &text[i - len], len);
len = 0;
k++;
}
else len++;
}
*count += k;
return lines;
}
// Unload text lines
static void UnloadTextLines(char **lines)
{
for (int i = 0; i < MAX_TEXT_LINES; i++) RL_FREE(lines[i]);
RL_FREE(lines);
}
// Get example info from example file header // Get example info from example file header
// NOTE: Expecting the example to follow raylib_example_template.c // NOTE: Expecting the example to follow raylib_example_template.c
rlExampleInfo *LoadExampleInfo(const char *exFileName) rlExampleInfo *LoadExampleInfo(const char *exFileName)