commit 834dad44ee12fa49fbe897eaa17e7bcb57ec47a5 Author: Nathan Anderson Date: Mon Dec 30 09:26:12 2024 -0700 First window rendered, sdl here I come diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..914e310 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.direnv/** +.zig-cache/** diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..de7f030 --- /dev/null +++ b/build.zig @@ -0,0 +1,145 @@ +const std = @import("std"); + +const Build = @import("std").Build; + +pub fn build(b: *Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const exe = b.addExecutable(.{ + .name = "zsdl", + .root_source_file = .{ .src_path = .{ .owner = b, .sub_path = "src/main.zig" } }, + .target = target, + .optimize = optimize, + }); + if (target.query.isNativeOs() and target.result.os.tag == .linux) { + // The SDL package doesn't work for Linux yet, so we rely on system + // packages for now. + exe.linkSystemLibrary("SDL2"); + exe.linkLibC(); + } else { + const sdl_dep = b.dependency("sdl", .{ + .optimize = .ReleaseFast, + .target = target, + }); + exe.linkLibrary(sdl_dep.artifact("SDL2")); + } + + b.installArtifact(exe); + + // Create Check step for zls + const exe_check = b.addExecutable(.{ + .name = "zsdl", + .root_source_file = .{ .src_path = .{ .owner = b, .sub_path = "src/main.zig" } }, + .target = target, + .optimize = optimize, + }); + if (target.query.isNativeOs() and target.result.os.tag == .linux) { + // The SDL package doesn't work for Linux yet, so we rely on system + // packages for now. + exe_check.linkSystemLibrary("SDL2"); + exe_check.linkLibC(); + } else { + const sdl_dep = b.dependency("sdl", .{ + .optimize = .ReleaseFast, + .target = target, + }); + exe_check.linkLibrary(sdl_dep.artifact("SDL2")); + } + const check = b.step("check", "Check if project compiles, used by Zig Language Server"); + check.dependOn(&exe_check.step); + + const run = b.step("run", "Run the demo"); + const run_cmd = b.addRunArtifact(exe); + run.dependOn(&run_cmd.step); +} + +// // Although this function looks imperative, note that its job is to +// // declaratively construct a build graph that will be executed by an external +// // runner. +// pub fn build(b: *std.Build) void { +// // Standard target options allows the person running `zig build` to choose +// // what target to build for. Here we do not override the defaults, which +// // means any target is allowed, and the default is native. Other options +// // for restricting supported target set are available. +// const target = b.standardTargetOptions(.{}); + +// // Standard optimization options allow the person running `zig build` to select +// // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not +// // set a preferred release mode, allowing the user to decide how to optimize. +// const optimize = b.standardOptimizeOption(.{}); + +// const lib = b.addStaticLibrary(.{ +// .name = "zsdl", +// // In this case the main source file is merely a path, however, in more +// // complicated build scripts, this could be a generated file. +// .root_source_file = b.path("src/root.zig"), +// .target = target, +// .optimize = optimize, +// }); + +// // This declares intent for the library to be installed into the standard +// // location when the user invokes the "install" step (the default step when +// // running `zig build`). +// b.installArtifact(lib); + +// const exe = b.addExecutable(.{ +// .name = "zsdl", +// .root_source_file = b.path("src/main.zig"), +// .target = target, +// .optimize = optimize, +// }); + +// // This declares intent for the executable to be installed into the +// // standard location when the user invokes the "install" step (the default +// // step when running `zig build`). +// b.installArtifact(exe); + +// // This *creates* a Run step in the build graph, to be executed when another +// // step is evaluated that depends on it. The next line below will establish +// // such a dependency. +// const run_cmd = b.addRunArtifact(exe); + +// // By making the run step depend on the install step, it will be run from the +// // installation directory rather than directly from within the cache directory. +// // This is not necessary, however, if the application depends on other installed +// // files, this ensures they will be present and in the expected location. +// run_cmd.step.dependOn(b.getInstallStep()); + +// // This allows the user to pass arguments to the application in the build +// // command itself, like this: `zig build run -- arg1 arg2 etc` +// if (b.args) |args| { +// run_cmd.addArgs(args); +// } + +// // This creates a build step. It will be visible in the `zig build --help` menu, +// // and can be selected like this: `zig build run` +// // This will evaluate the `run` step rather than the default, which is "install". +// const run_step = b.step("run", "Run the app"); +// run_step.dependOn(&run_cmd.step); + +// // Creates a step for unit testing. This only builds the test executable +// // but does not run it. +// const lib_unit_tests = b.addTest(.{ +// .root_source_file = b.path("src/root.zig"), +// .target = target, +// .optimize = optimize, +// }); + +// const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); + +// const exe_unit_tests = b.addTest(.{ +// .root_source_file = b.path("src/main.zig"), +// .target = target, +// .optimize = optimize, +// }); + +// const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + +// // Similar to creating the run step earlier, this exposes a `test` step to +// // the `zig build --help` menu, providing a way for the user to request +// // running the unit tests. +// const test_step = b.step("test", "Run unit tests"); +// test_step.dependOn(&run_lib_unit_tests.step); +// test_step.dependOn(&run_exe_unit_tests.step); +// } diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..176bfa3 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,16 @@ +.{ + .name = "zsdl", + .version = "0.0.1", + .minimum_zig_version = "0.13.0", + .dependencies = .{ + .SDL = .{ + .url = "https://github.com/allyourcodebase/SDL/archive/7e4fc30b201d266f197fef4153f7e046bd189a7c.tar.gz", + .hash = "1220c57b0bec66a2378e90cd7a79e36f9e7f60c02acca769ab3e6f974d4ef6766418", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..762544c --- /dev/null +++ b/flake.lock @@ -0,0 +1,92 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1735471104, + "narHash": "sha256-0q9NGQySwDQc7RhAV2ukfnu7Gxa5/ybJ2ANT8DQrQrs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "88195a94f390381c6afcdaa933c2f6ff93959cb4", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1719942202, + "narHash": "sha256-7sP4PzxRsUfRwN8rmFtRvU/nYqTI5YYeIG9P3KJV41g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4b015946c99a5bbe9c7a685e66f165aa44644b7d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "zlsPkg": "zlsPkg" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "zlsPkg": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1, + "narHash": "sha256-40mzryp9AaDiufsbEISP5VJCEpg0DYrdMjpP16oSJj0=", + "path": "./nix/zls", + "type": "path" + }, + "original": { + "path": "./nix/zls", + "type": "path" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..77e9df2 --- /dev/null +++ b/flake.nix @@ -0,0 +1,27 @@ +{ + description = "Zig flake with ZLS"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs.zlsPkg.url = "path:./nix/zls"; + outputs = { + flake-utils, + nixpkgs, + zlsPkg, + ... + }: + flake-utils.lib.eachDefaultSystem (system: let + pkgs = import nixpkgs { + inherit system; + }; + zls = zlsPkg.defaultPackage.${system}; + in { + devShell = pkgs.mkShell { + buildInputs = with pkgs; [ + lldb + SDL2 + zig + zls + ]; + }; + }); +} diff --git a/nix/zls/flake.lock b/nix/zls/flake.lock new file mode 100644 index 0000000..188887d --- /dev/null +++ b/nix/zls/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1719942202, + "narHash": "sha256-7sP4PzxRsUfRwN8rmFtRvU/nYqTI5YYeIG9P3KJV41g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4b015946c99a5bbe9c7a685e66f165aa44644b7d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/nix/zls/flake.nix b/nix/zls/flake.nix new file mode 100644 index 0000000..921bf0b --- /dev/null +++ b/nix/zls/flake.nix @@ -0,0 +1,33 @@ +{ + description = "Zig language server"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + outputs = {self, nixpkgs}: { + defaultPackage.x86_64-linux = + with import nixpkgs { system = "x86_64-linux"; }; + + stdenv.mkDerivation rec { + name = "zls-${version}"; + version = "0.13.0"; + src = pkgs.fetchurl { + url = "https://github.com/zigtools/zls/releases/download/${version}/zls-x86_64-linux.tar.xz"; + sha256 = "sha256-7EwbRcr4jivLnrsWxnBgPMWW5PYhuWGE376DeznNhBA="; + }; + + sourceRoot = "."; + + installPhase = '' + install -m755 -D zls $out/bin/zls + ''; + + meta = with lib; { + homepage = "https://github.com/zigtools/zls/releases"; + description = "Zig language server"; + platforms = platforms.linux; + }; + }; + }; +} diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..05d45b8 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,72 @@ +const c = @cImport({ + @cInclude("SDL2/SDL.h"); +}); + +const std = @import("std"); +const assert = std.debug.assert; + +pub fn main() !void { + if (c.SDL_Init(c.SDL_INIT_VIDEO) != 0) { + c.SDL_Log("Unable to initialize SDL: %s", c.SDL_GetError()); + return error.SDLInitializationFailed; + } + defer c.SDL_Quit(); + + const screen = c.SDL_CreateWindow("My Game Window", c.SDL_WINDOWPOS_UNDEFINED, c.SDL_WINDOWPOS_UNDEFINED, 400, 140, c.SDL_WINDOW_OPENGL) orelse + { + c.SDL_Log("Unable to create window: %s", c.SDL_GetError()); + return error.SDLInitializationFailed; + }; + defer c.SDL_DestroyWindow(screen); + + const renderer = c.SDL_CreateRenderer(screen, -1, 0) orelse { + c.SDL_Log("Unable to create renderer: %s", c.SDL_GetError()); + return error.SDLInitializationFailed; + }; + defer c.SDL_DestroyRenderer(renderer); + + const zig_bmp = @embedFile("zig.bmp"); + const rw = c.SDL_RWFromConstMem(zig_bmp, zig_bmp.len) orelse { + c.SDL_Log("Unable to get RWFromConstMem: %s", c.SDL_GetError()); + return error.SDLInitializationFailed; + }; + defer assert(c.SDL_RWclose(rw) == 0); + + const zig_surface = c.SDL_LoadBMP_RW(rw, 0) orelse { + c.SDL_Log("Unable to load bmp: %s", c.SDL_GetError()); + return error.SDLInitializationFailed; + }; + defer c.SDL_FreeSurface(zig_surface); + + const zig_texture = c.SDL_CreateTextureFromSurface(renderer, zig_surface) orelse { + c.SDL_Log("Unable to create texture from surface: %s", c.SDL_GetError()); + return error.SDLInitializationFailed; + }; + defer c.SDL_DestroyTexture(zig_texture); + + var quit = false; + while (!quit) { + var event: c.SDL_Event = undefined; + while (c.SDL_PollEvent(&event) != 0) { + switch (event.type) { + c.SDL_QUIT => { + quit = true; + }, + else => {}, + } + } + + _ = c.SDL_RenderClear(renderer); + _ = c.SDL_RenderCopy(renderer, zig_texture, null, null); + c.SDL_RenderPresent(renderer); + + c.SDL_Delay(17); + } +} + +test "simple test" { + var list = std.ArrayList(i32).init(std.testing.allocator); + defer list.deinit(); // try commenting this out and see if zig detects the memory leak! + try list.append(42); + try std.testing.expectEqual(@as(i32, 42), list.pop()); +} diff --git a/src/root.zig b/src/root.zig new file mode 100644 index 0000000..ecfeade --- /dev/null +++ b/src/root.zig @@ -0,0 +1,10 @@ +const std = @import("std"); +const testing = std.testing; + +export fn add(a: i32, b: i32) i32 { + return a + b; +} + +test "basic add functionality" { + try testing.expect(add(3, 7) == 10); +} diff --git a/src/zig.bmp b/src/zig.bmp new file mode 100644 index 0000000..bfe7108 Binary files /dev/null and b/src/zig.bmp differ