From 15e1670ec3ed958b4e1f702784fbcc2bcce0f3d0 Mon Sep 17 00:00:00 2001 From: geemili Date: Fri, 23 Feb 2024 14:44:27 -0700 Subject: [PATCH] get medium cards rendering --- .gitignore | 2 + build.zig | 55 +++++++++++ build.zig.zon | 36 +++++++ src/cardsLarge_tilemap.png | Bin 0 -> 3512 bytes src/cardsMedium_tilemap.png | Bin 0 -> 3454 bytes src/cardsSmall_tilemap.png | Bin 0 -> 1504 bytes src/main.zig | 182 ++++++++++++++++++++++++++++++++++++ 7 files changed, 275 insertions(+) create mode 100644 .gitignore create mode 100644 build.zig create mode 100644 build.zig.zon create mode 100644 src/cardsLarge_tilemap.png create mode 100644 src/cardsMedium_tilemap.png create mode 100644 src/cardsSmall_tilemap.png create mode 100644 src/main.zig diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ee7098f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +zig-out/ +zig-cache/ diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..1cb0cfd --- /dev/null +++ b/build.zig @@ -0,0 +1,55 @@ +const std = @import("std"); + +// 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 seizer = b.dependency("seizer", .{ + .target = target, + .optimize = optimize, + }); + + const exe = b.addExecutable(.{ + .name = "seizer-rummy", + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + exe.root_module.addImport("seizer", seizer.module("seizer")); + b.installArtifact(exe); + + const run_cmd = b.addRunArtifact(exe); + run_cmd.step.dependOn(b.getInstallStep()); + + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + const exe_unit_tests = b.addTest(.{ + .root_source_file = .{ .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_exe_unit_tests.step); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..cddf7e0 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,36 @@ +.{ + .name = "seizer-rummy", + // This is a [Semantic Version](https://semver.org/). + // In a future version of Zig it will be used for package deduplication. + .version = "0.0.0", + + // This field is optional. + // This is currently advisory only; Zig does not yet do anything + // with this value. + //.minimum_zig_version = "0.11.0", + + // This field is optional. + // Each dependency must either provide a `url` and `hash`, or a `path`. + // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. + // Once all dependencies are fetched, `zig build` no longer requires + // internet connectivity. + .dependencies = .{ + .seizer = .{ + .url = "https://github.com/leroycep/seizer/archive/dd1f9f6c94e91edfd96f0075c5f5d33aa30758f4.tar.gz", + .hash = "122009caed9e40d713c847b24c2abf8540299e32fb5e77f73ab2acdf5c27bc3e4c90", + }, + }, + .paths = .{ + // This makes *all* files, recursively, included in this package. It is generally + // better to explicitly list the files and directories instead, to insure that + // fetching from tarballs, file system paths, and version control all result + // in the same contents hash. + "", + // For example... + //"build.zig", + //"build.zig.zon", + //"src", + //"LICENSE", + //"README.md", + }, +} diff --git a/src/cardsLarge_tilemap.png b/src/cardsLarge_tilemap.png new file mode 100644 index 0000000000000000000000000000000000000000..69773596829c04d7db5cde0213b3cb20d592bf6e GIT binary patch literal 3512 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 1; + } +}; +const Card = packed struct(u6) { + suit: Suit, + rank: u4, +}; + +/// A texture with a regular grid of sprites +const TileSheet = struct { + texture: seizer.Texture, + tile_size: [2]u32, + + pub const InitOptions = struct { + allocator: std.mem.Allocator, + image_file_contents: []const u8, + tile_size: [2]u32, + texture_options: seizer.Texture.InitFromFileOptions = .{}, + }; + + pub fn init(options: InitOptions) !@This() { + const texture = try seizer.Texture.initFromFileContents( + options.allocator, + options.image_file_contents, + options.texture_options, + ); + return @This(){ + .texture = texture, + .tile_size = options.tile_size, + }; + } + + pub fn deinit(this: *@This()) void { + this.texture.deinit(); + } + + pub fn renderTile(this: @This(), canvas: *seizer.Canvas, tile_id: u32, pos: [2]f32, options: struct { + size: ?[2]f32 = null, + }) void { + const texture_sizef = [2]f32{ + @floatFromInt(this.texture.size[0]), + @floatFromInt(this.texture.size[1]), + }; + const tile_sizef = [2]f32{ + @floatFromInt(this.tile_size[0]), + @floatFromInt(this.tile_size[1]), + }; + const size_in_tiles = [2]u32{ + @as(u32, @intCast(this.texture.size[0])) / this.tile_size[0], + @as(u32, @intCast(this.texture.size[1])) / this.tile_size[1], + }; + const pos_in_tiles = [2]u32{ + tile_id % size_in_tiles[0], + tile_id / size_in_tiles[0], + }; + const pos_in_tilesf = [2]f32{ + @floatFromInt(pos_in_tiles[0]), + @floatFromInt(pos_in_tiles[1]), + }; + const uv = seizer.geometry.AABB(f32){ + .min = .{ + (pos_in_tilesf[0] * tile_sizef[0]) / texture_sizef[0], + (pos_in_tilesf[1] * tile_sizef[1]) / texture_sizef[1], + }, + .max = .{ + ((pos_in_tilesf[0] + 1) * tile_sizef[0]) / texture_sizef[0], + ((pos_in_tilesf[1] + 1) * tile_sizef[1]) / texture_sizef[1], + }, + }; + _ = canvas.printText(.{ 0, 0 }, "uv = {}", .{uv}, .{}); + canvas.rect(pos, options.size orelse tile_sizef, .{ + .texture = this.texture.glTexture, + .uv = uv, + }); + } +}; +// const cards_medium_spritesheet = + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + + // GLFW setup + try seizer.backend.glfw.loadDynamicLibraries(gpa.allocator()); + + _ = seizer.backend.glfw.c.glfwSetErrorCallback(&seizer.backend.glfw.defaultErrorCallback); + + const glfw_init_res = seizer.backend.glfw.c.glfwInit(); + if (glfw_init_res != 1) { + std.debug.print("glfw init error: {}\n", .{glfw_init_res}); + std.process.exit(1); + } + defer seizer.backend.glfw.c.glfwTerminate(); + + seizer.backend.glfw.c.glfwWindowHint(seizer.backend.glfw.c.GLFW_OPENGL_DEBUG_CONTEXT, seizer.backend.glfw.c.GLFW_TRUE); + seizer.backend.glfw.c.glfwWindowHint(seizer.backend.glfw.c.GLFW_CLIENT_API, seizer.backend.glfw.c.GLFW_OPENGL_ES_API); + seizer.backend.glfw.c.glfwWindowHint(seizer.backend.glfw.c.GLFW_CONTEXT_VERSION_MAJOR, 3); + seizer.backend.glfw.c.glfwWindowHint(seizer.backend.glfw.c.GLFW_CONTEXT_VERSION_MINOR, 0); + + // Open window + const window = seizer.backend.glfw.c.glfwCreateWindow(720, 720, "Rummy", null, null) orelse return error.GlfwCreateWindow; + errdefer seizer.backend.glfw.c.glfwDestroyWindow(window); + + seizer.backend.glfw.c.glfwMakeContextCurrent(window); + + gl_binding.init(seizer.backend.glfw.GlBindingLoader); + gl.makeBindingCurrent(&gl_binding); + + // Set up input callbacks + _ = seizer.backend.glfw.c.glfwSetFramebufferSizeCallback(window, &glfw_framebuffer_size_callback); + + var card_tilemap = try TileSheet.init(.{ + .allocator = gpa.allocator(), + .image_file_contents = @embedFile("./cardsMedium_tilemap.png"), + .tile_size = .{ 32, 32 }, + .texture_options = .{ + .min_filter = .nearest, + .mag_filter = .nearest, + }, + }); + defer card_tilemap.deinit(); + + var canvas = try seizer.Canvas.init(gpa.allocator(), .{}); + defer canvas.deinit(gpa.allocator()); + + while (seizer.backend.glfw.c.glfwWindowShouldClose(window) != seizer.backend.glfw.c.GLFW_TRUE) { + seizer.backend.glfw.c.glfwPollEvents(); + + gl.clearColor(0.7, 0.5, 0.5, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT); + + var window_size: [2]c_int = undefined; + seizer.backend.glfw.c.glfwGetWindowSize(window, &window_size[0], &window_size[1]); + + var framebuffer_size: [2]c_int = undefined; + seizer.backend.glfw.c.glfwGetFramebufferSize(window, &framebuffer_size[0], &framebuffer_size[1]); + + canvas.begin(.{ + .window_size = [2]f32{ + @floatFromInt(window_size[0]), + @floatFromInt(window_size[1]), + }, + .framebuffer_size = [2]f32{ + @floatFromInt(framebuffer_size[0]), + @floatFromInt(framebuffer_size[1]), + }, + }); + card_tilemap.renderTile(&canvas, 1, .{ 10, 10 }, .{}); + // canvas.rect(.{ 10, 10 }, .{ @as(f32, @floatFromInt(card_tilemap.size[0])) / 15.0, @as(f32, @floatFromInt(card_tilemap.size[1])) / 10.0 }, .{ + // .texture = card_tilemap.glTexture, + // .uv = .{ .min = .{ 0, 0 }, .max = .{ 1.0 / 15.0, 1.0 / 10.0 } }, + // }); + _ = canvas.writeText(.{ 50, 50 }, "Hello, world!", .{}); + _ = canvas.printText(.{ 50, 100 }, "window_size = {}, {}\nframebuffer_size = {}, {}", .{ window_size[0], window_size[1], framebuffer_size[0], framebuffer_size[1] }, .{}); + canvas.end(); + + seizer.backend.glfw.c.glfwSwapBuffers(window); + } +} + +fn glfw_framebuffer_size_callback(window: ?*seizer.backend.glfw.c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void { + _ = window; + gl.viewport( + 0, + 0, + @intCast(width), + @intCast(height), + ); +} + +const seizer = @import("seizer"); +const gl = seizer.gl; +const std = @import("std");