diff --git a/build.zig b/build.zig index 2dc6258af..eb1eb5cc6 100644 --- a/build.zig +++ b/build.zig @@ -1,14 +1,11 @@ const std = @import("std"); const builtin = @import("builtin"); -const emccOutputDir = "zig-out" ++ std.fs.path.sep_str ++ "htmlout" ++ std.fs.path.sep_str; -const emccOutputFile = "index.html"; - 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 fn shell(raylib_dep: *std.Build.Dependency) std.Build.LazyPath { + return raylib_dep.path("src/shell.html"); } pub const FlagsOptions = struct { @@ -30,7 +27,10 @@ pub const emsdk = struct { pub const SettingsOptions = struct { optimize: std.builtin.OptimizeMode, - es3: bool = true, + es3: bool = false, + glfw3: bool = true, + memory_growth: bool = false, + total_memory: u32 = 134217728, emsdk_allocator: zemscripten.EmsdkAllocator = .emmalloc, }; @@ -40,10 +40,24 @@ pub const emsdk = struct { .emsdk_allocator = options.emsdk_allocator, }); - if (options.es3) + if (options.es3) { emcc_settings.put("FULL_ES3", "1") catch unreachable; - emcc_settings.put("USE_GLFW", "3") catch unreachable; + emcc_settings.put("MIN_WEBGL_VERSION", "2") catch unreachable; + emcc_settings.put("MAX_WEBGL_VERSION", "2") catch unreachable; + } + if (options.glfw3) { + emcc_settings.put("USE_GLFW", "3") catch unreachable; + } + + const total_memory = std.fmt.allocPrint(allocator, "{d}", .{options.total_memory}) catch unreachable; + emcc_settings.put("EXPORTED_RUNTIME_METHODS", "['requestFullscreen']") catch unreachable; + emcc_settings.put("TOTAL_MEMORY", total_memory) catch unreachable; + emcc_settings.put("FORCE_FILESYSTEM", "1") catch unreachable; + emcc_settings.put("EXPORTED_RUNTIME_METHODS", "ccall") catch unreachable; + + if (options.memory_growth) + emcc_settings.put("ALLOW_MEMORY_GROWTH", "1") catch unreachable; return emcc_settings; } @@ -70,45 +84,96 @@ pub const emsdk = struct { } }; -fn setDesktopPlatform(raylib: *std.Build.Step.Compile, platform: PlatformBackend) void { - switch (platform) { - .glfw => raylib.root_module.addCMacro("PLATFORM_DESKTOP_GLFW", ""), - .rgfw => raylib.root_module.addCMacro("PLATFORM_DESKTOP_RGFW", ""), - .sdl => raylib.root_module.addCMacro("PLATFORM_DESKTOP_SDL", ""), - .android => raylib.root_module.addCMacro("PLATFORM_ANDROID", ""), - else => {}, +pub fn linkWindows(mod: *std.Build.Module, opengl: bool, comptime shcore: bool) void { + if (opengl) mod.linkSystemLibrary("opengl32", .{}); + mod.linkSystemLibrary("winmm", .{}); + mod.linkSystemLibrary("gdi32", .{}); + if (shcore) mod.linkSystemLibrary("shcore", .{}); +} + +fn findWaylandScanner(b: *std.Build) void { + _ = b.findProgram(&.{"wayland-scanner"}, &.{}) catch { + std.log.err( + \\ `wayland-scanner` may not be installed on the system. + \\ You can switch to X11 in your `build.zig` by changing `Options.linux_display_backend` + , .{}); + @panic("`wayland-scanner` not found"); + }; +} + +pub fn linkLinux(mod: *std.Build.Module, comptime display_backend: LinuxDisplayBackend) void { + if (display_backend == .None) { + mod.linkSystemLibrary("GL", .{}); + } + + if (display_backend == .X11) { + mod.linkSystemLibrary("X11", .{}); + mod.linkSystemLibrary("Xrandr", .{}); + mod.linkSystemLibrary("Xinerama", .{}); + mod.linkSystemLibrary("Xi", .{}); + mod.linkSystemLibrary("Xcursor", .{}); + } + + if (display_backend == .Wayland) { + mod.linkSystemLibrary("wayland-client", .{}); + mod.linkSystemLibrary("wayland-cursor", .{}); + mod.linkSystemLibrary("wayland-egl", .{}); + mod.linkSystemLibrary("xkbcommon", .{}); } } +pub fn linkBSD(_: *std.Build, mod: *std.Build.Module) void { + mod.linkSystemLibrary("GL", .{}); +} + +pub fn linkMacOS(b: *std.Build, mod: *std.Build.Module) void { + // Include xcode_frameworks for cross compilation + if (b.lazyDependency("xcode_frameworks", .{})) |dep| { + mod.addSystemFrameworkPath(dep.path("Frameworks")); + mod.addSystemIncludePath(dep.path("include")); + mod.addLibraryPath(dep.path("lib")); + } + + mod.linkFramework("Foundation", .{}); + mod.linkFramework("CoreServices", .{}); + mod.linkFramework("CoreGraphics", .{}); + mod.linkFramework("AppKit", .{}); + mod.linkFramework("IOKit", .{}); +} + fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, options: Options) !*std.Build.Step.Compile { + const raylib_mod = b.createModule(.{ + .optimize = optimize, + .target = target, + .link_libc = true, + }); + const raylib = b.addLibrary(.{ .name = "raylib", .linkage = options.linkage, - .root_module = b.createModule(.{ - .optimize = optimize, - .target = target, - .link_libc = true, - }), + .root_module = raylib_mod, }); - raylib.root_module.addCMacro("_GNU_SOURCE", ""); - raylib.root_module.addCMacro("GL_SILENCE_DEPRECATION", "199309L"); + raylib_mod.addCMacro("_GNU_SOURCE", ""); + raylib_mod.addCMacro("GL_SILENCE_DEPRECATION", "199309L"); - var raylib_flags_arr: std.ArrayList([]const u8) = .empty; - defer raylib_flags_arr.deinit(b.allocator); + var arena: std.heap.ArenaAllocator = .init(b.allocator); + defer arena.deinit(); - try raylib_flags_arr.append( - b.allocator, - "-std=gnu99", - ); + var raylib_flags_arr: std.array_list.Managed([]const u8) = .init(arena.allocator()); + var c_source_files: std.array_list.Managed([]const u8) = .init(arena.allocator()); + + try c_source_files.append("src/rcore.c"); + + if (target.result.os.tag == .emscripten) { + try raylib_flags_arr.append("-std=gnu99"); + } else { + try raylib_flags_arr.append("-std=c99"); + } if (options.linkage == .dynamic) { - try raylib_flags_arr.append( - b.allocator, - "-fPIC", - ); - - raylib.root_module.addCMacro("BUILD_LIBTYPE_SHARED", ""); + raylib_mod.pic = true; + raylib_mod.addCMacro("BUILD_LIBTYPE_SHARED", ""); } if (options.config.len > 0) { @@ -120,237 +185,290 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. // Apply config flags supplied by the user while (config_iter.next()) |config_flag| { - try raylib_flags_arr.append(b.allocator, config_flag); + try raylib_flags_arr.append(config_flag); } } - // No GLFW required on PLATFORM_DRM - if (options.platform != .drm) { - raylib.root_module.addIncludePath(b.path("src/external/glfw/include")); - } - - var c_source_files: std.ArrayList([]const u8) = try .initCapacity(b.allocator, 2); - c_source_files.appendSliceAssumeCapacity(&.{"src/rcore.c"}); - + raylib_mod.addCMacro("SUPPORT_MODULE_RSHAPES", &.{@as(u8, @intFromBool(options.rshapes)) + 0x30}); if (options.rshapes) { - raylib.root_module.addCMacro("SUPPORT_MODULE_RSHAPES", "1"); - try c_source_files.append(b.allocator, "src/rshapes.c"); - } else { - raylib.root_module.addCMacro("SUPPORT_MODULE_RSHAPES", "0"); + try c_source_files.append("src/rshapes.c"); } - + raylib_mod.addCMacro("SUPPORT_MODULE_RTEXTURES", &.{@as(u8, @intFromBool(options.rtextures)) + 0x30}); if (options.rtextures) { - raylib.root_module.addCMacro("SUPPORT_MODULE_RTEXTURES", "1"); - try c_source_files.append(b.allocator, "src/rtextures.c"); - } else { - raylib.root_module.addCMacro("SUPPORT_MODULE_RTEXTURES", "0"); + try c_source_files.append("src/rtextures.c"); } - + raylib_mod.addCMacro("SUPPORT_MODULE_RTEXT", &.{@as(u8, @intFromBool(options.rtext)) + 0x30}); if (options.rtext) { - raylib.root_module.addCMacro("SUPPORT_MODULE_RTEXT", "1"); - try c_source_files.append(b.allocator, "src/rtext.c"); - } else { - raylib.root_module.addCMacro("SUPPORT_MODULE_RTEXT", "0"); + try c_source_files.append("src/rtext.c"); } - + raylib_mod.addCMacro("SUPPORT_MODULE_RMODELS", &.{@as(u8, @intFromBool(options.rmodels)) + 0x30}); if (options.rmodels) { - raylib.root_module.addCMacro("SUPPORT_MODULE_RMODELS", "1"); - try c_source_files.append(b.allocator, "src/rmodels.c"); - } else { - raylib.root_module.addCMacro("SUPPORT_MODULE_RMODELS", "0"); + try c_source_files.append("src/rmodels.c"); } - + raylib_mod.addCMacro("SUPPORT_MODULE_RAUDIO", &.{@as(u8, @intFromBool(options.raudio)) + 0x30}); if (options.raudio) { - raylib.root_module.addCMacro("SUPPORT_MODULE_RAUDIO", "1"); - try c_source_files.append(b.allocator, "src/raudio.c"); - } else { - raylib.root_module.addCMacro("SUPPORT_MODULE_RAUDIO", "0"); + try c_source_files.append("src/raudio.c"); } - if (options.opengl_version != .auto) { - raylib.root_module.addCMacro(options.opengl_version.toCMacroStr(), ""); - } - - raylib.root_module.addIncludePath(b.path("src/platforms")); - switch (target.result.os.tag) { - .windows => { - switch (options.platform) { - .glfw => try c_source_files.append(b.allocator, "src/rglfw.c"), - .rgfw, .sdl, .drm, .android => {}, + raylib_mod.addIncludePath(b.path("src/platforms")); + switch (options.platform) { + .glfw => { + var opengl_version: OpenglVersion = options.opengl_version; + if (opengl_version == .gl_soft) { + @panic("The opengl version is not supported by this platform"); } - raylib.root_module.linkSystemLibrary("winmm", .{}); - raylib.root_module.linkSystemLibrary("gdi32", .{}); - raylib.root_module.linkSystemLibrary("opengl32", .{}); + raylib_mod.addIncludePath(b.path("src/external/glfw/include")); - setDesktopPlatform(raylib, options.platform); - }, - .linux => { - if (options.platform == .drm) { - if (options.opengl_version == .auto) { - raylib.root_module.linkSystemLibrary("GLESv2", .{}); - raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", ""); + if (target.result.os.tag != .emscripten) { + if (opengl_version == .auto) { + opengl_version = OpenglVersion.gl_3_3; } - - if (options.opengl_version != .gl_soft) { - raylib.root_module.linkSystemLibrary("EGL", .{}); - raylib.root_module.linkSystemLibrary("gbm", .{}); - } - raylib.root_module.linkSystemLibrary("libdrm", .{ .use_pkg_config = .force }); - - raylib.root_module.addCMacro("PLATFORM_DRM", ""); - raylib.root_module.addCMacro("EGL_NO_X11", ""); - raylib.root_module.addCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", ""); - } else if (target.result.abi.isAndroid()) { - - //these are the only tag options per https://developer.android.com/ndk/guides/other_build_systems - const hostTuple = switch (builtin.target.os.tag) { - .linux => "linux-x86_64", - .windows => "windows-x86_64", - .macos => "darwin-x86_64", - else => @panic("unsupported host OS"), - }; - - 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; - 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 androidSysroot = try std.fs.path.join(b.allocator, &.{ androidNdkPathString, "/toolchains/llvm/prebuilt/", hostTuple, "/sysroot" }); - const androidLibPath = try std.fs.path.join(b.allocator, &.{ androidSysroot, "/usr/lib/", androidTriple }); - const androidApiSpecificPath = try std.fs.path.join(b.allocator, &.{ androidLibPath, androidApiLevel }); - const androidIncludePath = try std.fs.path.join(b.allocator, &.{ androidSysroot, "/usr/include" }); - const androidArchIncludePath = try std.fs.path.join(b.allocator, &.{ androidIncludePath, androidTriple }); - 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/" }); - - raylib.root_module.addLibraryPath(.{ .cwd_relative = androidLibPath }); - raylib.root_module.addLibraryPath(.{ .cwd_relative = androidApiSpecificPath }); - raylib.root_module.addSystemIncludePath(.{ .cwd_relative = androidIncludePath }); - raylib.root_module.addSystemIncludePath(.{ .cwd_relative = androidArchIncludePath }); - raylib.root_module.addSystemIncludePath(.{ .cwd_relative = androidAsmPath }); - raylib.root_module.addSystemIncludePath(.{ .cwd_relative = androidGluePath }); - - var libcData: std.ArrayList(u8) = .empty; - var aw: std.Io.Writer.Allocating = .fromArrayList(b.allocator, &libcData); - try (std.zig.LibCInstallation{ - .include_dir = androidIncludePath, - .sys_include_dir = androidIncludePath, - .crt_dir = androidApiSpecificPath, - }).render(&aw.writer); - const libcFile = b.addWriteFiles().add("android-libc.txt", try libcData.toOwnedSlice(b.allocator)); - raylib.setLibCFile(libcFile); - - if (options.opengl_version == .auto) { - raylib.root_module.linkSystemLibrary("GLESv2", .{}); - raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", ""); - } - raylib.root_module.linkSystemLibrary("EGL", .{}); - - setDesktopPlatform(raylib, .android); - } else { - switch (options.platform) { - .glfw => try c_source_files.append(b.allocator, "src/rglfw.c"), - .rgfw, .sdl, .drm, .android => {}, - } - - if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) { - raylib.root_module.addCMacro("_GLFW_X11", ""); - raylib.root_module.linkSystemLibrary("GLX", .{}); - raylib.root_module.linkSystemLibrary("X11", .{}); - raylib.root_module.linkSystemLibrary("Xcursor", .{}); - raylib.root_module.linkSystemLibrary("Xext", .{}); - raylib.root_module.linkSystemLibrary("Xfixes", .{}); - raylib.root_module.linkSystemLibrary("Xi", .{}); - raylib.root_module.linkSystemLibrary("Xinerama", .{}); - raylib.root_module.linkSystemLibrary("Xrandr", .{}); - raylib.root_module.linkSystemLibrary("Xrender", .{}); - } - - if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) { - _ = b.findProgram(&.{"wayland-scanner"}, &.{}) catch { - std.log.err( - \\ `wayland-scanner` may not be installed on the system. - \\ You can switch to X11 in your `build.zig` by changing `Options.linux_display_backend` - , .{}); - @panic("`wayland-scanner` not found"); - }; - raylib.root_module.addCMacro("_GLFW_WAYLAND", ""); - raylib.root_module.linkSystemLibrary("EGL", .{}); - raylib.root_module.linkSystemLibrary("wayland-client", .{}); - raylib.root_module.linkSystemLibrary("xkbcommon", .{}); - waylandGenerate(b, raylib, "wayland.xml", "wayland-client-protocol"); - waylandGenerate(b, raylib, "xdg-shell.xml", "xdg-shell-client-protocol"); - waylandGenerate(b, raylib, "xdg-decoration-unstable-v1.xml", "xdg-decoration-unstable-v1-client-protocol"); - waylandGenerate(b, raylib, "viewporter.xml", "viewporter-client-protocol"); - waylandGenerate(b, raylib, "relative-pointer-unstable-v1.xml", "relative-pointer-unstable-v1-client-protocol"); - waylandGenerate(b, raylib, "pointer-constraints-unstable-v1.xml", "pointer-constraints-unstable-v1-client-protocol"); - waylandGenerate(b, raylib, "fractional-scale-v1.xml", "fractional-scale-v1-client-protocol"); - waylandGenerate(b, raylib, "xdg-activation-v1.xml", "xdg-activation-v1-client-protocol"); - waylandGenerate(b, raylib, "idle-inhibit-unstable-v1.xml", "idle-inhibit-unstable-v1-client-protocol"); - } - setDesktopPlatform(raylib, options.platform); - } - }, - .freebsd, .openbsd, .netbsd, .dragonfly => { - try c_source_files.append(b.allocator, "src/rglfw.c"); - raylib.root_module.linkSystemLibrary("GL", .{}); - raylib.root_module.linkSystemLibrary("rt", .{}); - raylib.root_module.linkSystemLibrary("dl", .{}); - raylib.root_module.linkSystemLibrary("m", .{}); - raylib.root_module.linkSystemLibrary("X11", .{}); - raylib.root_module.linkSystemLibrary("Xrandr", .{}); - raylib.root_module.linkSystemLibrary("Xinerama", .{}); - raylib.root_module.linkSystemLibrary("Xi", .{}); - raylib.root_module.linkSystemLibrary("Xxf86vm", .{}); - raylib.root_module.linkSystemLibrary("Xcursor", .{}); - - setDesktopPlatform(raylib, options.platform); - }, - .macos => { - // Include xcode_frameworks for cross compilation - if (b.lazyDependency("xcode_frameworks", .{})) |dep| { - raylib.root_module.addSystemFrameworkPath(dep.path("Frameworks")); - raylib.root_module.addSystemIncludePath(dep.path("include")); - raylib.root_module.addLibraryPath(dep.path("lib")); + raylib_mod.addCMacro("PLATFORM_DESKTOP_GLFW", ""); + try c_source_files.append("src/rglfw.c"); } - // On macos rglfw.c include Objective-C files. - try raylib_flags_arr.append(b.allocator, "-ObjC"); - raylib.root_module.addCSourceFile(.{ - .file = b.path("src/rglfw.c"), - .flags = raylib_flags_arr.items, - }); - _ = raylib_flags_arr.pop(); - raylib.root_module.linkFramework("Foundation", .{}); - raylib.root_module.linkFramework("CoreServices", .{}); - raylib.root_module.linkFramework("CoreGraphics", .{}); - raylib.root_module.linkFramework("AppKit", .{}); - raylib.root_module.linkFramework("IOKit", .{}); + switch (target.result.os.tag) { + .windows => linkWindows(raylib_mod, true, false), + .linux => { + if (target.result.abi.isAndroid()) { + @panic("Target is not supported with this platform"); + } - setDesktopPlatform(raylib, options.platform); + linkLinux(raylib_mod, .None); + + if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) { + raylib_mod.addCMacro("_GLFW_X11", ""); + linkLinux(raylib_mod, .X11); + } + + if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) { + findWaylandScanner(b); + + raylib_mod.addCMacro("_GLFW_WAYLAND", ""); + linkLinux(raylib_mod, .Wayland); + try waylandGenerate(b, raylib, "src/external/glfw/deps/wayland/", false); + } + }, + .freebsd, .openbsd, .netbsd, .dragonfly => linkBSD(b, raylib_mod), + .macos => { + // On macos rglfw.c include Objective-C files. + _ = c_source_files.pop(); + try raylib_flags_arr.append("-ObjC"); + raylib_mod.addCSourceFile(.{ + .file = b.path("src/rglfw.c"), + .flags = raylib_flags_arr.items, + }); + _ = raylib_flags_arr.pop(); + + linkMacOS(b, raylib_mod); + }, + .emscripten => { + switch (opengl_version) { + .auto => opengl_version = OpenglVersion.gles_2, + .gles_2, .gles_3, .gl_soft => {}, + else => @panic("opengl version not supported"), + } + + raylib_mod.addCMacro("PLATFORM_WEB", ""); + + const activate_emsdk_step = emsdk.zemscripten.activateEmsdkStep(b); + raylib.step.dependOn(activate_emsdk_step); + }, + else => @panic("Target is not supported with this platform"), + } + raylib_mod.addCMacro(opengl_version.toCMacroStr(), ""); }, - .emscripten => { - const activate_emsdk_step = emsdk.zemscripten.activateEmsdkStep(b); - raylib.step.dependOn(activate_emsdk_step); - raylib.root_module.addCMacro("PLATFORM_WEB", ""); + .rgfw => { + var opengl_version: OpenglVersion = options.opengl_version; + + if (target.result.os.tag != .emscripten) { + if (opengl_version == .auto) { + opengl_version = OpenglVersion.gl_3_3; + } + raylib_mod.addCMacro("PLATFORM_DESKTOP_RGFW", ""); + } + + switch (target.result.os.tag) { + .windows => linkWindows(raylib_mod, true, false), + .linux => { + if (target.result.abi.isAndroid()) { + @panic("Target is not supported with this platform"); + } + + linkLinux(raylib_mod, .None); + + if (options.linux_display_backend == .X11 or options.linux_display_backend == .Both) { + raylib_mod.addCMacro("RGFW_X11", ""); + raylib_mod.addCMacro("RGFW_UNIX", ""); + + linkLinux(raylib_mod, .X11); + } + + if (options.linux_display_backend == .Wayland or options.linux_display_backend == .Both) { + findWaylandScanner(b); + + if (options.linux_display_backend != .Both) { + raylib_mod.addCMacro("RGFW_NO_X11", ""); + } + + raylib_mod.addCMacro("RGFW_WAYLAND", ""); + raylib_mod.addCMacro("EGLAPIENTRY", ""); + + linkLinux(raylib_mod, .Wayland); + + try waylandGenerate(b, raylib, "src/external/RGFW/deps/wayland/", true); + } + }, + .freebsd, .openbsd, .netbsd, .dragonfly => linkBSD(b, raylib_mod), + .macos => linkMacOS(b, raylib_mod), + .emscripten => { + switch (opengl_version) { + .auto => opengl_version = OpenglVersion.gles_2, + .gles_2, .gles_3, .gl_soft => {}, + else => @panic("opengl version not supported"), + } + + raylib_mod.addCMacro("PLATFORM_WEB_RGFW", ""); + const activate_emsdk_step = emsdk.zemscripten.activateEmsdkStep(b); + raylib.step.dependOn(activate_emsdk_step); + }, + else => @panic("Target is not supported with this platform"), + } + + raylib_mod.addCMacro(opengl_version.toCMacroStr(), ""); + }, + .sdl, .sdl2, .sdl3 => { if (options.opengl_version == .auto) { - raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES3", ""); + raylib_mod.addCMacro(OpenglVersion.gl_3_3.toCMacroStr(), ""); + } else { + raylib_mod.addCMacro(options.opengl_version.toCMacroStr(), ""); + } + + raylib_mod.addCMacro("PLATFORM_DESKTOP_SDL", ""); + + if (options.platform == .sdl2) { + raylib_mod.addCMacro("USING_SDL2_PACKAGE", ""); + } + if (options.platform == .sdl3) { + raylib_mod.addCMacro("USING_SDL3_PACKAGE", ""); } }, - else => { - @panic("Unsupported OS"); + .memory => { + if (options.opengl_version != .auto and options.opengl_version != .gl_soft) { + @panic("The opengl version is not supported by this platform"); + } + raylib_mod.addCMacro(OpenglVersion.gl_soft.toCMacroStr(), ""); + raylib_mod.addCMacro("PLATFORM_MEMORY", ""); + }, + .win32 => { + if (target.result.os.tag != .windows) { + @panic("Target is not supported with this platform"); + } + + if (options.opengl_version == .auto) { + raylib_mod.addCMacro(OpenglVersion.gl_3_3.toCMacroStr(), ""); + } else { + raylib_mod.addCMacro(options.opengl_version.toCMacroStr(), ""); + } + + raylib_mod.addCMacro("PLATFORM_DESKTOP_WIN32", ""); + + linkWindows(raylib_mod, options.opengl_version != .gl_soft, true); + }, + .drm => { + if (target.result.os.tag != .linux) { + @panic("Target is not supported with this platform"); + } + + raylib_mod.addCMacro("PLATFORM_DRM", ""); + raylib_mod.addCMacro("EGL_NO_X11", ""); + raylib_mod.addCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", ""); + + try raylib_flags_arr.append("-Werror=implicit-function-declaration"); + + raylib_mod.linkSystemLibrary("libdrm", .{ .use_pkg_config = .force }); + raylib_mod.linkSystemLibrary("drm", .{}); + raylib_mod.linkSystemLibrary("gbm", .{}); + + switch (options.opengl_version) { + .auto, .gles_2 => { + raylib_mod.addCMacro(OpenglVersion.gles_2.toCMacroStr(), ""); + raylib_mod.linkSystemLibrary("GLESv2", .{}); + raylib_mod.linkSystemLibrary("EGL", .{}); + }, + .gl_soft => {}, + else => @panic("The opengl version is not supported by this platform"), + } + }, + .android => { + if (!target.result.abi.isAndroid()) { + @panic("Target is not supported with this platform"); + } + + raylib_mod.addCMacro("PLATFORM_ANDROID", ""); + + raylib_mod.linkSystemLibrary("EGL", .{}); + switch (options.opengl_version) { + .auto, .gles_2 => { + raylib_mod.addCMacro(OpenglVersion.gles_2.toCMacroStr(), ""); + raylib_mod.linkSystemLibrary("GLESv2", .{}); + }, + else => @panic("The opengl version is not supported by this platform"), + } + + //these are the only tag options per https://developer.android.com/ndk/guides/other_build_systems + const hostTuple = switch (builtin.target.os.tag) { + .linux => "linux-x86_64", + .windows => "windows-x86_64", + .macos => "darwin-x86_64", + else => @panic("unsupported host OS"), + }; + + 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; + 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 androidSysroot = try std.fs.path.join(b.allocator, &.{ androidNdkPathString, "/toolchains/llvm/prebuilt/", hostTuple, "/sysroot" }); + const androidLibPath = try std.fs.path.join(b.allocator, &.{ androidSysroot, "/usr/lib/", androidTriple }); + const androidApiSpecificPath = try std.fs.path.join(b.allocator, &.{ androidLibPath, androidApiLevel }); + const androidIncludePath = try std.fs.path.join(b.allocator, &.{ androidSysroot, "/usr/include" }); + const androidArchIncludePath = try std.fs.path.join(b.allocator, &.{ androidIncludePath, androidTriple }); + 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/" }); + + raylib_mod.addLibraryPath(.{ .cwd_relative = androidLibPath }); + raylib_mod.addLibraryPath(.{ .cwd_relative = androidApiSpecificPath }); + raylib_mod.addSystemIncludePath(.{ .cwd_relative = androidIncludePath }); + raylib_mod.addSystemIncludePath(.{ .cwd_relative = androidArchIncludePath }); + raylib_mod.addSystemIncludePath(.{ .cwd_relative = androidAsmPath }); + raylib_mod.addSystemIncludePath(.{ .cwd_relative = androidGluePath }); + + const libc_data = try std.fmt.allocPrint(b.allocator, + \\include_dir={0s}/sysroot/usr/include + \\sys_include_dir={0s}/sysroot/usr/include/aarch64-linux-android + \\crt_dir={0s}/sysroot/usr/lib/aarch64-linux-android/24 + \\static_lib_dir={0s}/sysroot/usr/lib/aarch64-linux-android/24 + \\msvc_lib_dir= + \\kernel32_lib_dir= + \\gcc_dir= + \\ + , .{androidNdkPathString}); + const write_step = b.addWriteFiles(); + const libcFile = write_step.add("android-libc.txt", libc_data); + raylib.setLibCFile(libcFile); }, } - raylib.root_module.addCSourceFiles(.{ + raylib_mod.addCSourceFiles(.{ .files = c_source_files.items, .flags = raylib_flags_arr.items, }); @@ -358,17 +476,33 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std. return raylib; } -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(), options); - var gen_step = b.addWriteFiles(); - raylib.step.dependOn(&gen_step.step); +fn addRaygui(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, raylib: *std.Build.Step.Compile) void { + if (b.lazyDependency("raygui", .{ + .target = target, + .optimize = optimize, + .link_libc = true, + })) |raygui_dep| { + var gen_step = b.addWriteFiles(); + raylib.step.dependOn(&gen_step.step); - const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n"); - raylib.root_module.addCSourceFile(.{ .file = raygui_c_path }); - raylib.root_module.addIncludePath(raygui_dep.path("src")); - raylib.root_module.addIncludePath(raylib_dep.path("src")); + const raygui_c_path = gen_step.add("raygui.c", "#define RAYGUI_IMPLEMENTATION\n#include \"raygui.h\"\n"); + raylib.root_module.addCSourceFile(.{ .file = raygui_c_path }); + raylib.root_module.addIncludePath(raygui_dep.path("src")); + raylib.root_module.addIncludePath(b.path("src")); - raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h"); + raylib.installHeader(raygui_dep.path("src/raygui.h"), "raygui.h"); + + const c = b.addTranslateC(.{ + .root_source_file = raygui_dep.path("src/raygui.h"), + .target = target, + .optimize = optimize, + .link_libc = true, + }); + c.addIncludePath(b.path("src")); + const c_mod = c.createModule(); + c_mod.linkLibrary(raylib); + b.modules.put(b.graph.arena, "raygui", c_mod) catch @panic("OOM"); + } } pub const Options = struct { @@ -377,6 +511,7 @@ pub const Options = struct { rshapes: bool = true, rtext: bool = true, rtextures: bool = true, + raygui: bool = false, platform: PlatformBackend = .glfw, linkage: std.builtin.LinkMode = .static, linux_display_backend: LinuxDisplayBackend = .X11, @@ -396,6 +531,7 @@ pub const Options = struct { .rtext = b.option(bool, "rtext", "Compile with text support") orelse defaults.rtext, .rtextures = b.option(bool, "rtextures", "Compile with textures support") orelse defaults.rtextures, .rshapes = b.option(bool, "rshapes", "Compile with shapes support") orelse defaults.rshapes, + .raygui = b.option(bool, "raygui", "Include raygui") orelse defaults.raygui, .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, .opengl_version = b.option(OpenglVersion, "opengl_version", "OpenGL version to use") orelse defaults.opengl_version, @@ -441,15 +577,38 @@ pub const PlatformBackend = enum { glfw, rgfw, sdl, + sdl2, + sdl3, + memory, + win32, drm, android, }; +fn translateCMod( + comptime header: []const u8, + b: *std.Build, + target: std.Build.ResolvedTarget, + optimize: std.builtin.OptimizeMode, + raylib: *std.Build.Step.Compile, +) void { + const c = b.addTranslateC(.{ + .root_source_file = b.path("src/" ++ header ++ ".h"), + .target = target, + .optimize = optimize, + .link_libc = true, + }); + const c_mod = c.createModule(); + c_mod.linkLibrary(raylib); + b.modules.put(b.graph.arena, header, c_mod) catch @panic("OOM"); +} + pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); + const options: Options = .getOptions(b); - const lib = try compileRaylib(b, target, optimize, Options.getOptions(b)); + const lib = try compileRaylib(b, target, optimize, options); lib.installHeader(b.path("src/raylib.h"), "raylib.h"); lib.installHeader(b.path("src/rcamera.h"), "rcamera.h"); @@ -458,15 +617,24 @@ pub fn build(b: *std.Build) !void { b.installArtifact(lib); - const examples = b.step("examples", "Build/Install all examples"); - examples.dependOn(try addExamples("audio", b, target, optimize, lib)); - examples.dependOn(try addExamples("core", b, target, optimize, lib)); - examples.dependOn(try addExamples("models", b, target, optimize, lib)); - examples.dependOn(try addExamples("others", b, target, optimize, lib)); - examples.dependOn(try addExamples("shaders", b, target, optimize, lib)); - examples.dependOn(try addExamples("shapes", b, target, optimize, lib)); - examples.dependOn(try addExamples("text", b, target, optimize, lib)); - examples.dependOn(try addExamples("textures", b, target, optimize, lib)); + translateCMod("raylib", b, target, optimize, lib); + translateCMod("rcamera", b, target, optimize, lib); + translateCMod("raymath", b, target, optimize, lib); + translateCMod("rlgl", b, target, optimize, lib); + + if (options.raygui) { + addRaygui(b, target, optimize, lib); + } + + const examples = b.step("examples", "build/install all examples"); + examples.dependOn(try addExamples("core", b, target, optimize, lib, options.platform)); + examples.dependOn(try addExamples("audio", b, target, optimize, lib, options.platform)); + examples.dependOn(try addExamples("models", b, target, optimize, lib, options.platform)); + examples.dependOn(try addExamples("shaders", b, target, optimize, lib, options.platform)); + examples.dependOn(try addExamples("shapes", b, target, optimize, lib, options.platform)); + examples.dependOn(try addExamples("text", b, target, optimize, lib, options.platform)); + examples.dependOn(try addExamples("textures", b, target, optimize, lib, options.platform)); + examples.dependOn(try addExamples("others", b, target, optimize, lib, options.platform)); } fn addExamples( @@ -475,6 +643,7 @@ fn addExamples( target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, raylib: *std.Build.Step.Compile, + platform: PlatformBackend, ) !*std.Build.Step { const all = b.step(module, "All " ++ module ++ " examples"); const module_subpath = b.pathJoin(&.{ "examples", module }); @@ -485,118 +654,88 @@ fn addExamples( var iter = dir.iterate(); while (try iter.next(b.graph.io)) |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 filename = try std.fmt.allocPrint(b.allocator, "{s}.c", .{name}); - const path = b.pathJoin(&.{ module_subpath, filename }); - // 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 filetype = std.fs.path.extension(entry.name); + if (!std.mem.eql(u8, filetype, ".c")) continue; + + const filename = std.fs.path.stem(entry.name); + const path = b.pathJoin(&.{ module_subpath, entry.name }); const exe_mod = b.createModule(.{ .target = target, .optimize = optimize, + .link_libc = true, }); - exe_mod.addCSourceFile(.{ .file = b.path(path), .flags = &.{} }); + exe_mod.addCSourceFile(.{ .file = b.path(path) }); exe_mod.linkLibrary(raylib); - const run_step = b.step(name, name); + if (platform == .sdl) { + exe_mod.linkSystemLibrary("SDL2", .{}); + exe_mod.linkSystemLibrary("SDL3", .{}); + } + if (platform == .sdl2) { + exe_mod.linkSystemLibrary("SDL2", .{}); + } + if (platform == .sdl3) { + exe_mod.linkSystemLibrary("SDL3", .{}); + } + + if (std.mem.eql(u8, filename, "rlgl_standalone")) { + if (platform != .glfw) continue; + exe_mod.addIncludePath(b.path("src")); + exe_mod.addIncludePath(b.path("src/external/glfw/include")); + } + if (std.mem.eql(u8, filename, "raylib_opengl_interop")) { + if (platform == .drm) continue; + if (target.result.os.tag == .macos) continue; + exe_mod.addIncludePath(b.path("src/external")); + } + + const run_step = b.step(filename, filename); + + // web exports are completely separate + if (target.query.os_tag == .emscripten) { + exe_mod.addCMacro("PLATFORM_WEB", ""); - if (target.result.os.tag == .emscripten) { const wasm = b.addLibrary(.{ - .name = name, - .linkage = .static, + .name = filename, .root_module = exe_mod, }); - if (std.mem.eql(u8, name, "rlgl_standalone")) { - exe_mod.addIncludePath(b.path("src")); - exe_mod.addIncludePath(b.path("src/external/glfw/include")); - } - if (std.mem.eql(u8, name, "raylib_opengl_interop")) { - exe_mod.addIncludePath(b.path("src/external")); - } - + const install_dir: std.Build.InstallDir = .{ .custom = b.fmt("web/{s}/{s}", .{ module, filename }) }; 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, }); + b.getInstallStep().dependOn(emcc_step); 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); + 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"); - }, - } + exe_mod.addCMacro("PLATFORM_DESKTOP", ""); const exe = b.addExecutable(.{ - .name = name, + .name = filename, .root_module = exe_mod, + .use_lld = target.result.os.tag == .windows, }); + b.installArtifact(exe); - const install_cmd = b.addInstallArtifact(exe, .{}); + const install_cmd = b.addInstallArtifact(exe, .{ .dest_sub_path = b.fmt("{s}/{s}", .{ module, filename }) }); const run_cmd = b.addRunArtifact(exe); run_cmd.cwd = b.path(module_subpath); @@ -606,41 +745,46 @@ fn addExamples( all.dependOn(&install_cmd.step); } } - return all; } fn waylandGenerate( b: *std.Build, raylib: *std.Build.Step.Compile, - comptime protocol: []const u8, - comptime basename: []const u8, -) void { - const waylandDir = "src/external/glfw/deps/wayland"; - const protocolDir = b.pathJoin(&.{ waylandDir, protocol }); - const clientHeader = basename ++ ".h"; - const privateCode = basename ++ "-code.h"; + comptime waylandDir: []const u8, + comptime source: bool, +) !void { + const dir = try b.build_root.handle.openDir(b.graph.io, waylandDir, .{ .iterate = true }); + defer dir.close(b.graph.io); - const client_step = b.addSystemCommand(&.{ "wayland-scanner", "client-header" }); - client_step.addFileArg(b.path(protocolDir)); - raylib.root_module.addIncludePath(client_step.addOutputFileArg(clientHeader).dirname()); + var iter = dir.iterate(); + while (try iter.next(b.graph.io)) |entry| { + if (entry.kind != .file) continue; + const protocolDir = b.pathJoin(&.{ waylandDir, entry.name }); - const private_step = b.addSystemCommand(&.{ "wayland-scanner", "private-code" }); - private_step.addFileArg(b.path(protocolDir)); - raylib.root_module.addIncludePath(private_step.addOutputFileArg(privateCode).dirname()); + const filename = std.fs.path.stem(entry.name); - raylib.step.dependOn(&client_step.step); - raylib.step.dependOn(&private_step.step); -} - -fn hasCSource(module: *std.Build.Module, name: []const u8) bool { - for (module.link_objects.items) |o| switch (o) { - .c_source_file => |c| if (switch (c.file) { - .src_path => |s| std.ascii.endsWithIgnoreCase(s.sub_path, name), - .generated, .cwd_relative, .dependency => false, - }) return true, - .c_source_files => |s| for (s.files) |c| if (std.ascii.endsWithIgnoreCase(c, name)) return true, - else => {}, - }; - return false; + const clientHeader = b.fmt("{s}-client-protocol.h", .{filename}); + const client_step = b.addSystemCommand(&.{ "wayland-scanner", "client-header" }); + client_step.addFileArg(b.path(protocolDir)); + raylib.root_module.addIncludePath(client_step.addOutputFileArg(clientHeader).dirname()); + raylib.step.dependOn(&client_step.step); + + if (comptime source) { + const privateCode = b.fmt("{s}-client-protocol-code.c", .{filename}); + const private_step = b.addSystemCommand(&.{ "wayland-scanner", "private-code" }); + private_step.addFileArg(b.path(protocolDir)); + raylib.root_module.addCSourceFile(.{ + .file = private_step.addOutputFileArg(privateCode), + .flags = &.{ "-std=c99", "-O2" }, + }); + raylib.step.dependOn(&private_step.step); + } else { + const privateCodeHeader = b.fmt("{s}-client-protocol-code.h", .{filename}); + const private_head_step = b.addSystemCommand(&.{ "wayland-scanner", "private-code" }); + private_head_step.addFileArg(b.path(protocolDir)); + raylib.root_module.addIncludePath(private_head_step.addOutputFileArg(privateCodeHeader).dirname()); + raylib.step.dependOn(&private_head_step.step); + } + } } diff --git a/build.zig.zon b/build.zig.zon index dd25fde73..07a1f7400 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -11,6 +11,11 @@ .hash = "N-V-__8AALShqgXkvqYU6f__FrA22SMWmi2TXCJjNTO1m8XJ", .lazy = true, }, + .raygui = .{ + .url = "git+https://github.com/raysan5/raygui#3b2855842ab578a034f827c38cf8f62c042fc983", + .hash = "N-V-__8AAHvybwBw1kyBGn0BW_s1RqIpycNjLf_XbE-fpLUF", + .lazy = true, + }, .emsdk = .{ .url = "git+https://github.com/emscripten-core/emsdk#4.0.9", .hash = "N-V-__8AAJl1DwBezhYo_VE6f53mPVm00R-Fk28NPW7P14EQ", diff --git a/projects/README.md b/projects/README.md index af24f1547..2758cb86e 100644 --- a/projects/README.md +++ b/projects/README.md @@ -13,6 +13,7 @@ IDE | Platform(s) | Source | Example(s) [SublimeText](https://www.sublimetext.com/) | Windows, Linux, macOS | ✔️ | ✔️ [VS2019](https://www.visualstudio.com) | Windows | ✔️ | ✔️ [VSCode](https://code.visualstudio.com/) | Windows, macOS | ❌ | ✔️ +[Zig](https://ziglang.org) | Windows, Linux, macOS, Web | ✔️ | ✔️ scripts | Windows, Linux, macOS | ✔️ | ✔️ *New IDEs config files are welcome!* diff --git a/projects/Zig/README.md b/projects/Zig/README.md new file mode 100644 index 000000000..a7c24e093 --- /dev/null +++ b/projects/Zig/README.md @@ -0,0 +1,84 @@ +# Starting your raylib project with Zig (0.16.0) + +## How to compile and run it + +To compile the project: + +```sh +zig build +``` + +To run the project: + +```sh +zig build run +``` + +## Compile with different optimization + +To change from debug to release build you can do it with the `-Doptimze=` flag. + +``` +Debug +ReleaseSafe +ReleaseFast +ReleaseSmall +``` + +## Choose a different platform + +To compile with a different platform you can use the `-Dplatform=` flag. +Here all the options: + +``` +glfw +rgfw +sdl +sdl2 +sdl3 +memory +win32 +drm +android +``` + +In this example the platform `sdl` and `sdl2` are not supported + +Important for the android platform you also have to compile for the right target + +## Compile for a different target + +To compile for a different [target](https://ziglang.org/download/0.16.0/release-notes.html#Support-Table) you can use the `-Dtarget=` flag. +Not all targets are supported + +## Example: Compile for web and run it + +To compile for the web we use emscripten and you run it like that: + +```sh +zig build -Dtarget=wasm32-emscripten +``` + +To run it we do: + +```sh +zig build run -Dtarget=wasm32-emscripten +``` + +And to make a relase build we do: + +```sh +zig build -Dtarget=wasm32-emscripten -Doptimize=ReleaseFast +``` + +If we want to use rgfw for the web build we could do: + +```sh +zig build -Dplatform=rgfw -Dtarget=wasm32-emscripten -Doptimize=ReleaseFast +``` + +## Compiling the Zig code? Just add `-Dzig` and try out zig ;) + +## More Resources + +See [Zig Build System](https://ziglang.org/learn/build-system/) diff --git a/projects/Zig/build.zig b/projects/Zig/build.zig new file mode 100644 index 000000000..917e97b71 --- /dev/null +++ b/projects/Zig/build.zig @@ -0,0 +1,87 @@ +const std = @import("std"); +const rl = @import("raylib"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + const platform = b.option(rl.PlatformBackend, "platform", "select the platform") orelse rl.PlatformBackend.glfw; + const zig = b.option(bool, "zig", "compile zig code") orelse false; + + const raylib_dep = b.dependency("raylib", .{ + .target = target, + .optimize = optimize, + .platform = platform, + }); + const raylib_artifact = raylib_dep.artifact("raylib"); + + if (platform == .sdl3) { + if (b.lazyDependency("sdl3", .{ .optimize = optimize, .target = target })) |dep| { + raylib_artifact.root_module.linkLibrary(dep.artifact("SDL3")); + } + } + + var exe_mod: *std.Build.Module = undefined; + + if (zig) { + exe_mod = b.createModule(.{ + .root_source_file = b.path("src/core_basic_window.zig"), + .target = target, + .optimize = optimize, + }); + exe_mod.addImport("raylib", raylib_dep.module("raylib")); + } else { + exe_mod = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libc = true, + }); + exe_mod.addCSourceFile(.{ .file = b.path("src/core_basic_window.c") }); + exe_mod.linkLibrary(raylib_artifact); + } + + const run_step = b.step("run", "Run the app"); + + // web exports are completely separate + if (target.query.os_tag == .emscripten) { + const emsdk = rl.emsdk; + const wasm = b.addLibrary(.{ + .name = "core_basic_window_web", + .root_module = exe_mod, + }); + + const install_dir: std.Build.InstallDir = .{ .custom = "web" }; + const emcc_flags = emsdk.emccDefaultFlags(b.allocator, .{ .optimize = optimize }); + const emcc_settings = emsdk.emccDefaultSettings(b.allocator, .{ .optimize = optimize }); + + const emcc_step = emsdk.emccStep(b, raylib_artifact, wasm, .{ + .optimize = optimize, + .flags = emcc_flags, + .settings = emcc_settings, + .shell_file_path = emsdk.shell(raylib_dep), + .install_dir = install_dir, + }); + b.getInstallStep().dependOn(emcc_step); + + 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), + &.{}, + ); + + emrun_step.dependOn(emcc_step); + run_step.dependOn(emrun_step); + } else { + const exe = b.addExecutable(.{ + .name = "core_basic_window", + .root_module = exe_mod, + .use_lld = target.result.os.tag == .windows, + }); + b.installArtifact(exe); + + const run_cmd = b.addRunArtifact(exe); + run_cmd.step.dependOn(b.getInstallStep()); + + run_step.dependOn(&run_cmd.step); + } +} diff --git a/projects/Zig/build.zig.zon b/projects/Zig/build.zig.zon new file mode 100644 index 000000000..77bf4291c --- /dev/null +++ b/projects/Zig/build.zig.zon @@ -0,0 +1,23 @@ +.{ + .name = .example, + .version = "0.0.1", + .minimum_zig_version = "0.16.0", + .paths = .{""}, + + .dependencies = .{ + .raylib = .{ + .path = "../../", + }, + .emsdk = .{ + .url = "git+https://github.com/emscripten-core/emsdk?ref=4.0.9#3bcf1dcd01f040f370e10fe673a092d9ed79ebb5", + .hash = "N-V-__8AAJl1DwBezhYo_VE6f53mPVm00R-Fk28NPW7P14EQ", + }, + .sdl3 = .{ + .url = "git+https://codeberg.org/7Games/zig-sdl3?ref=master#6d418ef3ddae99098414a96a88bf5e5fdb41785e", + .hash = "sdl3-0.1.9-NmT1QwiEJwByePqkmArtppCHQn8Y7kiSWcncT_Mop8ie", + .lazy = true, + }, + }, + + .fingerprint = 0x6eec9b9f1a9d7aca, +} diff --git a/projects/Zig/src/core_basic_window.c b/projects/Zig/src/core_basic_window.c new file mode 100644 index 000000000..cb23a6f87 --- /dev/null +++ b/projects/Zig/src/core_basic_window.c @@ -0,0 +1,83 @@ +/******************************************************************************************* +* +* raylib [core] example - Basic window (adapted for HTML5 platform) +* +* This example is prepared to compile for PLATFORM_WEB and PLATFORM_DESKTOP +* As you will notice, code structure is slightly different to the other examples... +* To compile it for PLATFORM_WEB just uncomment #define PLATFORM_WEB at beginning +* +* This example has been created using raylib 1.3 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +int screenWidth = 800; +int screenHeight = 450; + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +void UpdateDrawFrame(void); // Update and Draw one frame + +//---------------------------------------------------------------------------------- +// Program main entry point +//---------------------------------------------------------------------------------- +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + UpdateDrawFrame(); + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +void UpdateDrawFrame(void) +{ + // Update + //---------------------------------------------------------------------------------- + // TODO: Update your variables here + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- +} diff --git a/projects/Zig/src/core_basic_window.zig b/projects/Zig/src/core_basic_window.zig new file mode 100644 index 000000000..c26efc0d6 --- /dev/null +++ b/projects/Zig/src/core_basic_window.zig @@ -0,0 +1,73 @@ +//******************************************************************************************* +//* +//* raylib [core] example - Basic window (adapted for HTML5 platform) +//* +//* This example is prepared to compile for PLATFORM_WEB and PLATFORM_DESKTOP +//* As you will notice, code structure is slightly different to the other examples... +//* To compile it for PLATFORM_WEB just uncomment #define PLATFORM_WEB at beginning +//* +//* This example has been created using raylib 6.0 (www.raylib.com) +//* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +//* +//* Copyright (c) 2015 Ramon Santamaria (@raysan5) +//* Rewrite in Zig by HaxSam (@haxsam) +//* +//******************************************************************************************* + +const rl = @import("raylib"); +const std = @import("std"); +const builtin = @import("builtin"); + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +const screenWidth: c_int = 800; +const screenHeight: c_int = 450; + +//---------------------------------------------------------------------------------- +// Program main entry point +//---------------------------------------------------------------------------------- +pub fn main() void { + // Initialization + //-------------------------------------------------------------------------------------- + rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); + + if (builtin.os.tag == .emscripten) { + std.os.emscripten.emscripten_set_main_loop(UpdateDrawFrame, 0, 1); + } else { + rl.SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!rl.WindowShouldClose()) // Detect window close button or ESC key + { + UpdateDrawFrame(); + } + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + rl.CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +fn UpdateDrawFrame() callconv(.c) void { + // Update + //---------------------------------------------------------------------------------- + // TODO: Update your variables here + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + rl.BeginDrawing(); + + rl.ClearBackground(rl.RAYWHITE); + + rl.DrawText("Congrats! You created your first window!", 190, 200, 20, rl.LIGHTGRAY); + + rl.EndDrawing(); + //---------------------------------------------------------------------------------- +}