Compare commits

..

2 Commits

  1. 20
      README.md
  2. 10
      build.zig
  3. 1
      build.zig.zon
  4. 1
      libs/zig-gamedev
  5. 52
      src/main.zig
  6. 46
      src/shader.wgsl

@ -1,7 +1,19 @@
# Zig Bloxel Game # Zig Bloxel Game
This is a small project attempting to create a "bloxel" game (think Minecraft) using the relatively new [Zig] programming language with the help of [Mach] and [Flecs]. This is a small project attempting to create a "bloxel" game (think Minecraft) using the relatively new [Zig] programming language with the help of [Mach], [Flecs] and [zig-gamedev]. Due to Zig being a quickly evolving language, Mach and zig-gamedev, and as a result this project, target version `0.12.0-dev.2063+804cee3b9` of Zig.
[Zig]: https://ziglang.org/ [Zig]: https://ziglang.org/
[Mach]: https://machengine.org/ [Mach]: https://github.com/hexops/mach-core
[Flecs]: https://flecs.dev/ [Flecs]: https://github.com/SanderMertens/flecs
[zig-gamedev]: https://github.com/zig-gamedev/zig-gamedev
## Dependencies
```sh
mkdir -p libs && cd libs
# Clone zig-gamedev sparsely, only grabbing top-level files.
git clone --sparse --filter=blob:none https://github.com/zig-gamedev/zig-gamedev.git
# However, we also care about zmath, so check that out too.
cd zig-gamedev
git sparse-checkout add libs/zmath
```

@ -1,10 +1,15 @@
const std = @import("std"); const std = @import("std");
const mach_core = @import("mach_core"); const mach_core = @import("mach_core");
const zmath = @import("zmath");
pub fn build(b: *std.Build) !void { pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{}); const optimize = b.standardOptimizeOption(.{});
const zmath_pkg = zmath.package(b, target, optimize, .{
.options = .{ .enable_cross_platform_determinism = true },
});
const mach_core_dep = b.dependency("mach_core", .{ const mach_core_dep = b.dependency("mach_core", .{
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
@ -14,7 +19,9 @@ pub fn build(b: *std.Build) !void {
.src = "src/main.zig", .src = "src/main.zig",
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
.deps = &.{}, .deps = &.{
.{ .name = "zmath", .module = zmath_pkg.zmath },
},
}); });
if (b.args) |args| app.run.addArgs(args); if (b.args) |args| app.run.addArgs(args);
@ -26,6 +33,7 @@ pub fn build(b: *std.Build) !void {
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
unit_tests.root_module.addImport("zmath", zmath_pkg.zmath);
const run_unit_tests = b.addRunArtifact(unit_tests); const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests"); const test_step = b.step("test", "Run unit tests");

@ -14,5 +14,6 @@
.url = "https://pkg.machengine.org/mach-core/6a62bcc90e0d072d632788a6575d77942bd09a19.tar.gz", .url = "https://pkg.machengine.org/mach-core/6a62bcc90e0d072d632788a6575d77942bd09a19.tar.gz",
.hash = "12209d39954fcda0be158461c10f64d14d5c7d097bd6d26785b332d75ffefa7dd7a0", .hash = "12209d39954fcda0be158461c10f64d14d5c7d097bd6d26785b332d75ffefa7dd7a0",
}, },
.zmath = .{ .path = "libs/zig-gamedev/libs/zmath" },
}, },
} }

@ -0,0 +1 @@
Subproject commit 25e1794d608d6a1d13e84a42d98c950fd250050d

@ -2,10 +2,18 @@ const std = @import("std");
const core = @import("mach-core"); const core = @import("mach-core");
const gpu = core.gpu; const gpu = core.gpu;
const zm = @import("zmath");
const vec = zm.f32x4;
const Mat = zm.Mat;
pub const App = @This(); pub const App = @This();
app_timer: core.Timer,
title_timer: core.Timer, title_timer: core.Timer,
pipeline: *gpu.RenderPipeline, pipeline: *gpu.RenderPipeline,
mvp_uniform_buffer: *gpu.Buffer,
mvp_bind_group: *gpu.BindGroup,
pub fn init(app: *App) !void { pub fn init(app: *App) !void {
try core.init(.{}); try core.init(.{});
@ -32,13 +40,32 @@ pub fn init(app: *App) !void {
.fragment = &fragment, .fragment = &fragment,
}; };
app.app_timer = try core.Timer.start();
app.title_timer = try core.Timer.start(); app.title_timer = try core.Timer.start();
app.pipeline = core.device.createRenderPipeline(&pipeline_descriptor); app.pipeline = core.device.createRenderPipeline(&pipeline_descriptor);
app.mvp_uniform_buffer = core.device.createBuffer(&.{
.usage = .{ .copy_dst = true, .uniform = true },
.size = @sizeOf(zm.Mat),
.mapped_at_creation = .false,
});
app.mvp_bind_group = core.device.createBindGroup(
&gpu.BindGroup.Descriptor.init(.{
.layout = app.pipeline.getBindGroupLayout(0),
.entries = &.{
gpu.BindGroup.Entry.buffer(0, app.mvp_uniform_buffer, 0, @sizeOf(zm.Mat)),
},
}),
);
} }
pub fn deinit(app: *App) void { pub fn deinit(app: *App) void {
defer core.deinit(); defer core.deinit();
defer app.pipeline.release(); defer app.pipeline.release();
defer app.mvp_uniform_buffer.release();
defer app.mvp_bind_group.release();
} }
pub fn update(app: *App) !bool { pub fn update(app: *App) !bool {
@ -50,6 +77,24 @@ pub fn update(app: *App) !bool {
} }
} }
// Set up a view matrix from the camera transform.
// This moves everything to be relative to the camera.
// TODO: Actually implement camera transform instead of hardcoding a look-at matrix.
// const view_matrix = zm.inverse(app.camera_transform);
const time = app.app_timer.read();
const x = @cos(time * std.math.tau / 10);
const y = @sin(time * std.math.tau / 10);
const view_matrix = zm.lookAtLh(vec(x, y, -2, 1), vec(0, 0, 0, 1), vec(0, 1, 0, 1));
// Set up a projection matrix using the size of the window.
// The perspective projection will make things further away appear smaller.
const width: f32 = @floatFromInt(core.descriptor.width);
const height: f32 = @floatFromInt(core.descriptor.height);
const field_of_view = std.math.degreesToRadians(f32, 45.0);
const proj_matrix = zm.perspectiveFovLh(field_of_view, width / height, 0.1, 10);
const view_proj_matrix = zm.mul(view_matrix, proj_matrix);
// Get back buffer texture to render to. // Get back buffer texture to render to.
const back_buffer_view = core.swap_chain.getCurrentTextureView().?; const back_buffer_view = core.swap_chain.getCurrentTextureView().?;
defer back_buffer_view.release(); defer back_buffer_view.release();
@ -70,15 +115,18 @@ pub fn update(app: *App) !bool {
const encoder = core.device.createCommandEncoder(null); const encoder = core.device.createCommandEncoder(null);
defer encoder.release(); defer encoder.release();
encoder.writeBuffer(app.mvp_uniform_buffer, 0, &[_]zm.Mat{zm.transpose(view_proj_matrix)});
{ {
const pass = encoder.beginRenderPass(&render_pass_info); const pass = encoder.beginRenderPass(&render_pass_info);
defer pass.release(); defer pass.release();
defer pass.end(); defer pass.end();
pass.setPipeline(app.pipeline); pass.setPipeline(app.pipeline);
pass.setBindGroup(0, app.mvp_bind_group, &.{});
// Draw a triangle with the help of a specialized shader. // Draw three triangles with the help of a specialized shader.
pass.draw(3, 1, 0, 0); pass.draw(9, 1, 0, 0);
} }
// Finish recording commands, creating a `WGPUCommandBuffer`. // Finish recording commands, creating a `WGPUCommandBuffer`.

@ -1,14 +1,44 @@
@group(0) @binding(0) var<uniform> mvp_matrix: mat4x4<f32>;
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) color: vec4<f32>,
};
struct FragmentOutput {
@location(0) pixel_color: vec4<f32>
};
@vertex fn vertex_main( @vertex fn vertex_main(
@builtin(vertex_index) index: u32 @builtin(vertex_index) index: u32
) -> @builtin(position) vec4<f32> { ) -> VertexOutput {
let pos = array<vec2<f32>, 3>( let color = array<vec3<f32>, 3>(
vec2<f32>( 0.0, 0.5), vec3<f32>(1.0, 0.0, 0.0),
vec2<f32>(-0.5, -0.5), vec3<f32>(0.0, 1.0, 0.0),
vec2<f32>( 0.5, -0.5) vec3<f32>(0.0, 0.0, 1.0),
); );
return vec4<f32>(pos[index], 0.0, 1.0); let pos = array<vec2<f32>, 9>(
vec2<f32>(-1.0, 0.5 + 0.25),
vec2<f32>(-1.5, -0.5 + 0.25),
vec2<f32>(-0.5, -0.5 + 0.25),
vec2<f32>( 0.0, 0.5 - 0.25),
vec2<f32>(-0.5, -0.5 - 0.25),
vec2<f32>( 0.5, -0.5 - 0.25),
vec2<f32>( 1.0, 0.5),
vec2<f32>( 0.5, -0.5),
vec2<f32>( 1.5, -0.5),
);
var out: VertexOutput;
out.position = vec4<f32>(pos[index], 0.0, 1.0) * mvp_matrix;
out.color = vec4<f32>(color[index / 3], 1.0);
return out;
} }
@fragment fn frag_main() -> @location(0) vec4<f32> { @fragment fn frag_main(in: VertexOutput) -> FragmentOutput {
return vec4<f32>(1.0, 0.0, 0.0, 1.0); var out: FragmentOutput;
out.pixel_color = in.color;
return out;
} }

Loading…
Cancel
Save