Camera controls, fix some math; lighting probably broken
This commit is contained in:
@@ -17,7 +17,7 @@ pub const Texture = struct {
|
|||||||
|
|
||||||
pub const AssetMap = std.hash_map.StringHashMapUnmanaged;
|
pub const AssetMap = std.hash_map.StringHashMapUnmanaged;
|
||||||
|
|
||||||
pub fn visitTextures(allocator: std.mem.Allocator) std.hash_map.StringHashMapUnmanaged(Texture) {
|
pub fn visitTextures(allocator: std.mem.Allocator) AssetMap(Texture) {
|
||||||
zstbi.init(allocator);
|
zstbi.init(allocator);
|
||||||
defer zstbi.deinit();
|
defer zstbi.deinit();
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ fn rearrange(grid_w: u32, grid_h: u32, tile_w: u32, tile_h: u32, inbuf: []const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinitTextures(allocator: std.mem.Allocator, map: AssetMap(Texture)) void {
|
pub fn deinitTextures(allocator: std.mem.Allocator, map: *AssetMap(Texture)) void {
|
||||||
var it = map.iterator();
|
var it = map.iterator();
|
||||||
while (it.next()) |entry| {
|
while (it.next()) |entry| {
|
||||||
allocator.free(entry.key_ptr.*);
|
allocator.free(entry.key_ptr.*);
|
||||||
|
|||||||
289
src/game.zig
289
src/game.zig
@@ -8,78 +8,36 @@ const sapp = sokol.app;
|
|||||||
const sg = sokol.gfx;
|
const sg = sokol.gfx;
|
||||||
const sglue = sokol.glue;
|
const sglue = sokol.glue;
|
||||||
|
|
||||||
const ap = @import("asset_pipeline.zig");
|
|
||||||
const main = @import("main.zig");
|
const main = @import("main.zig");
|
||||||
const math = @import("math.zig");
|
const math = @import("math.zig");
|
||||||
const Samplers = @import("Samplers.zig");
|
const tiles = @import("tiles.zig");
|
||||||
|
const samplers = @import("samplers.zig");
|
||||||
|
|
||||||
|
const Iterator3 = math.Iterator3;
|
||||||
const Matrix4x4 = math.Matrix4x4;
|
const Matrix4x4 = math.Matrix4x4;
|
||||||
|
const Quaternion = math.Quaternion;
|
||||||
|
const Vector2 = math.Vector2;
|
||||||
const Vector3 = math.Vector3;
|
const Vector3 = math.Vector3;
|
||||||
|
|
||||||
var show_console: bool = false;
|
var show_console: bool = false;
|
||||||
var show_demo_window: bool = false;
|
var show_demo_window: bool = false;
|
||||||
|
|
||||||
var vertex_buffer: sg.Buffer = undefined;
|
|
||||||
var index_buffer: sg.Buffer = undefined;
|
|
||||||
|
|
||||||
var pipeline: sg.Pipeline = undefined;
|
|
||||||
|
|
||||||
var point_light_buffer: sg.Buffer = undefined;
|
var point_light_buffer: sg.Buffer = undefined;
|
||||||
var directional_light_buffer: sg.Buffer = undefined;
|
var directional_light_buffer: sg.Buffer = undefined;
|
||||||
var sampler: sg.Sampler = undefined;
|
|
||||||
var base_color_texture: sg.Image = undefined;
|
|
||||||
var occlusion_roughness_metallic_texture: sg.Image = undefined;
|
|
||||||
var normal_texture: sg.Image = undefined;
|
|
||||||
|
|
||||||
var bindings: sg.Bindings = undefined;
|
pub var point_light_buffer_view: sg.View = undefined;
|
||||||
|
pub var directional_light_buffer_view: sg.View = undefined;
|
||||||
|
|
||||||
var textures: ap.AssetMap(ap.Texture) = undefined;
|
var camera_position: Vector3 = .init(0, 0, 1.62);
|
||||||
|
var camera_pitch: f32 = 0;
|
||||||
|
var camera_yaw: f32 = 0;
|
||||||
|
|
||||||
|
const camera_near_plane = 0.1;
|
||||||
|
const camera_vertical_fov_deg = 90.0;
|
||||||
|
const camera_half_vertical_fov_rad = 0.5 * camera_vertical_fov_deg * std.math.rad_per_deg;
|
||||||
|
const camera_mouse_sensitivity = 0.0015;
|
||||||
|
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
textures = ap.visitTextures(main.allocator);
|
|
||||||
|
|
||||||
const base_color = textures.getPtr("BaseColor").?;
|
|
||||||
const normal = textures.getPtr("Normal").?;
|
|
||||||
const occlusion_roughness_metallic = textures.getPtr("OcclusionRoughnessMetallic").?;
|
|
||||||
|
|
||||||
vertex_buffer = sg.makeBuffer(.{
|
|
||||||
.data = sg.asRange(&[_]f32{
|
|
||||||
// positionOS texCoord normalOS tangentOS
|
|
||||||
-0.5, -0.5, 0, 0, 1, 0, 0, 1, 1, 0, 0, -1,
|
|
||||||
0.5, -0.5, 0, 1, 1, 0, 0, 1, 1, 0, 0, -1,
|
|
||||||
-0.5, 0.5, 0, 0, 0, 0, 0, 1, 1, 0, 0, -1,
|
|
||||||
0.5, 0.5, 0, 1, 0, 0, 0, 1, 1, 0, 0, -1,
|
|
||||||
}),
|
|
||||||
.usage = .{
|
|
||||||
.immutable = true,
|
|
||||||
.vertex_buffer = true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
index_buffer = sg.makeBuffer(.{
|
|
||||||
.data = sg.asRange(&[_]u16{ 0, 1, 2, 2, 1, 3 }),
|
|
||||||
.usage = .{
|
|
||||||
.immutable = true,
|
|
||||||
.index_buffer = true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
pipeline = sg.makePipeline(.{
|
|
||||||
.shader = sg.makeShader(shaders.mainShaderDesc(sg.queryBackend())),
|
|
||||||
.layout = blk: {
|
|
||||||
var ret: sg.VertexLayoutState = .{};
|
|
||||||
ret.attrs[shaders.ATTR_main_positionOS].format = .FLOAT3;
|
|
||||||
ret.attrs[shaders.ATTR_main_texCoord].format = .FLOAT2;
|
|
||||||
ret.attrs[shaders.ATTR_main_normalOS].format = .FLOAT3;
|
|
||||||
ret.attrs[shaders.ATTR_main_tangentOS].format = .FLOAT4;
|
|
||||||
break :blk ret;
|
|
||||||
},
|
|
||||||
.primitive_type = .TRIANGLES,
|
|
||||||
.index_type = .UINT16,
|
|
||||||
.cull_mode = .BACK,
|
|
||||||
.face_winding = .CCW,
|
|
||||||
});
|
|
||||||
|
|
||||||
point_light_buffer = sg.makeBuffer(.{
|
point_light_buffer = sg.makeBuffer(.{
|
||||||
.size = @sizeOf([4]shaders.PointLight),
|
.size = @sizeOf([4]shaders.PointLight),
|
||||||
.usage = .{
|
.usage = .{
|
||||||
@@ -87,6 +45,9 @@ pub fn init() void {
|
|||||||
.storage_buffer = true,
|
.storage_buffer = true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
point_light_buffer_view = sg.makeView(.{
|
||||||
|
.storage_buffer = .{ .buffer = point_light_buffer },
|
||||||
|
});
|
||||||
|
|
||||||
directional_light_buffer = sg.makeBuffer(.{
|
directional_light_buffer = sg.makeBuffer(.{
|
||||||
.size = @sizeOf([4]shaders.DirectionalLight),
|
.size = @sizeOf([4]shaders.DirectionalLight),
|
||||||
@@ -95,86 +56,33 @@ pub fn init() void {
|
|||||||
.storage_buffer = true,
|
.storage_buffer = true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
directional_light_buffer_view = sg.makeView(.{
|
||||||
sampler = Samplers.getOrCreateSampler(.{
|
|
||||||
.wrap_u = .REPEAT,
|
|
||||||
.wrap_v = .REPEAT,
|
|
||||||
.wrap_w = .REPEAT,
|
|
||||||
.min_filter = .LINEAR,
|
|
||||||
.mag_filter = .LINEAR,
|
|
||||||
.mipmap_filter = .LINEAR,
|
|
||||||
}) catch unreachable;
|
|
||||||
|
|
||||||
base_color_texture = sg.makeImage(.{
|
|
||||||
.type = .ARRAY,
|
|
||||||
.usage = .{ .immutable = true },
|
|
||||||
.width = @intCast(base_color.width),
|
|
||||||
.height = @intCast(base_color.height),
|
|
||||||
.num_slices = @intCast(base_color.depth),
|
|
||||||
.pixel_format = .RGBA8,
|
|
||||||
.data = blk: {
|
|
||||||
var ret: sg.ImageData = .{};
|
|
||||||
ret.mip_levels[0] = sg.asRange(base_color.data);
|
|
||||||
break :blk ret;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
occlusion_roughness_metallic_texture = sg.makeImage(.{
|
|
||||||
.type = .ARRAY,
|
|
||||||
.usage = .{ .immutable = true },
|
|
||||||
.width = @intCast(occlusion_roughness_metallic.width),
|
|
||||||
.height = @intCast(occlusion_roughness_metallic.height),
|
|
||||||
.num_slices = @intCast(occlusion_roughness_metallic.depth),
|
|
||||||
.pixel_format = .RGBA8,
|
|
||||||
.data = blk: {
|
|
||||||
var ret: sg.ImageData = .{};
|
|
||||||
ret.mip_levels[0] = sg.asRange(occlusion_roughness_metallic.data);
|
|
||||||
break :blk ret;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
normal_texture = sg.makeImage(.{
|
|
||||||
.type = .ARRAY,
|
|
||||||
.usage = .{ .immutable = true },
|
|
||||||
.width = @intCast(normal.width),
|
|
||||||
.height = @intCast(normal.height),
|
|
||||||
.num_slices = @intCast(normal.depth),
|
|
||||||
.pixel_format = .RGBA8,
|
|
||||||
.data = blk: {
|
|
||||||
var ret: sg.ImageData = .{};
|
|
||||||
ret.mip_levels[0] = sg.asRange(normal.data);
|
|
||||||
break :blk ret;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
bindings = .{};
|
|
||||||
|
|
||||||
bindings.vertex_buffers[0] = vertex_buffer;
|
|
||||||
bindings.index_buffer = index_buffer;
|
|
||||||
|
|
||||||
bindings.views[shaders.VIEW_Point_Lights] = sg.makeView(.{
|
|
||||||
.storage_buffer = .{ .buffer = point_light_buffer },
|
|
||||||
});
|
|
||||||
bindings.views[shaders.VIEW_Directional_Lights] = sg.makeView(.{
|
|
||||||
.storage_buffer = .{ .buffer = directional_light_buffer },
|
.storage_buffer = .{ .buffer = directional_light_buffer },
|
||||||
});
|
});
|
||||||
bindings.views[shaders.VIEW__BaseColorTexture] = sg.makeView(.{
|
|
||||||
.texture = .{ .image = base_color_texture },
|
|
||||||
});
|
|
||||||
bindings.views[shaders.VIEW__OcclusionRoughnessMetallicTexture] = sg.makeView(.{
|
|
||||||
.texture = .{ .image = occlusion_roughness_metallic_texture },
|
|
||||||
});
|
|
||||||
bindings.views[shaders.VIEW__NormalTexture] = sg.makeView(.{
|
|
||||||
.texture = .{ .image = normal_texture },
|
|
||||||
});
|
|
||||||
|
|
||||||
bindings.samplers[0] = sampler;
|
tiles.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit() void {}
|
pub fn deinit() void {
|
||||||
|
tiles.deinit();
|
||||||
|
|
||||||
pub fn update(dt: f64) void {
|
sg.destroyView(directional_light_buffer_view);
|
||||||
_ = dt;
|
sg.destroyBuffer(directional_light_buffer);
|
||||||
|
sg.destroyView(point_light_buffer_view);
|
||||||
|
sg.destroyBuffer(point_light_buffer);
|
||||||
|
|
||||||
|
samplers.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(dt: f32) void {
|
||||||
|
var camera_d = Vector2.init(
|
||||||
|
@as(f32, @floatFromInt(@intFromBool(input_right))) - @as(f32, @floatFromInt(@intFromBool(input_left))),
|
||||||
|
@as(f32, @floatFromInt(@intFromBool(input_forwards))) - @as(f32, @floatFromInt(@intFromBool(input_backwards))),
|
||||||
|
).rotate(camera_yaw).mulScalar(player_speed * dt);
|
||||||
|
|
||||||
|
camera_position = Vector3.add(camera_position, camera_d.asVector3(0));
|
||||||
|
|
||||||
|
const framebuffer_size = Vector2.init(sapp.widthf(), sapp.heightf());
|
||||||
|
|
||||||
if (show_console) {
|
if (show_console) {
|
||||||
showConsole();
|
showConsole();
|
||||||
@@ -205,44 +113,85 @@ pub fn update(dt: f64) void {
|
|||||||
.swapchain = sglue.swapchain(),
|
.swapchain = sglue.swapchain(),
|
||||||
});
|
});
|
||||||
|
|
||||||
sg.applyPipeline(pipeline);
|
tiles.bind();
|
||||||
sg.applyBindings(bindings);
|
|
||||||
|
|
||||||
const matrix_ws_to_vs = Matrix4x4.identity;
|
const camera_rotation = Quaternion.mulQuaternion(
|
||||||
const matrix_vs_to_cs = Matrix4x4.identity;
|
.initRotationXY(camera_yaw),
|
||||||
const ambient_light = Vector3.init(0.01, 0.01, 0.01);
|
.initRotationYZ(camera_pitch),
|
||||||
|
);
|
||||||
|
const camera_aspect_ratio = framebuffer_size.getX() / framebuffer_size.getY();
|
||||||
|
const camera_yscale = 1.0 / @tan(camera_half_vertical_fov_rad);
|
||||||
|
const camera_xscale = camera_yscale / camera_aspect_ratio;
|
||||||
|
|
||||||
|
const matrix_ws_to_vs = Matrix4x4.mulMatrix(
|
||||||
|
Matrix4x4.initRotation(camera_rotation.conjugate()),
|
||||||
|
Matrix4x4.initTranslation(camera_position.negate()),
|
||||||
|
);
|
||||||
|
// zig fmt: off
|
||||||
|
const matrix_vs_to_cs = Matrix4x4.init(
|
||||||
|
camera_xscale, 0, 0, 0,
|
||||||
|
0, 0, camera_near_plane, 1,
|
||||||
|
0, camera_yscale, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
);
|
||||||
|
// zig fmt: on
|
||||||
|
const ambient_light = Vector3.init(0, 0, 0);
|
||||||
|
|
||||||
sg.applyUniforms(shaders.UB_Global_Uniforms_Vertex, sg.asRange(&shaders.GlobalUniformsVertex{
|
sg.applyUniforms(shaders.UB_Global_Uniforms_Vertex, sg.asRange(&shaders.GlobalUniformsVertex{
|
||||||
._MatrixWStoVS = matrix_ws_to_vs.asArray(),
|
._MatrixWStoVS = matrix_ws_to_vs.asArray(),
|
||||||
._MatrixVStoCS = matrix_vs_to_cs.asArray(),
|
._MatrixVStoCS = matrix_vs_to_cs.asArray(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const point_lights: []const shaders.PointLight = &.{
|
||||||
|
.{
|
||||||
|
.positionWS = .{ 0, 0, 1.62 },
|
||||||
|
.color = .{ 11, 11, 10 },
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.positionWS = .{ -10, 10, 1.62 },
|
||||||
|
.color = .{ 5, 0, 0 },
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.positionWS = .{ 0, 10, 1.62 },
|
||||||
|
.color = .{ 0, 5, 0 },
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.positionWS = .{ 10, 10, 1.62 },
|
||||||
|
.color = .{ 0, 0, 5 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
sg.updateBuffer(point_light_buffer, sg.asRange(point_lights));
|
||||||
|
|
||||||
sg.applyUniforms(shaders.UB_Global_Uniforms_Fragment, sg.asRange(&shaders.GlobalUniformsFragment{
|
sg.applyUniforms(shaders.UB_Global_Uniforms_Fragment, sg.asRange(&shaders.GlobalUniformsFragment{
|
||||||
._MatrixWStoVS = matrix_ws_to_vs.asArray(),
|
._MatrixWStoVS = matrix_ws_to_vs.asArray(),
|
||||||
._AmbientLight = ambient_light.asArray(),
|
._AmbientLight = ambient_light.asArray(),
|
||||||
._PointLightCount = 0,
|
._PointLightCount = @intCast(point_lights.len),
|
||||||
._DirectionalLightCount = 0,
|
._DirectionalLightCount = 0,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
sg.applyUniforms(shaders.UB_Material_Uniforms, sg.asRange(&shaders.MaterialUniforms{
|
var it = Iterator3.init(.init(-10, -10, 0), .init(10, 10, 0), .one);
|
||||||
._TextureIndex = 0,
|
var tile_index: u32 = 0;
|
||||||
}));
|
while (it.next()) |pos| : (tile_index = (tile_index + 1) % 16) {
|
||||||
|
tiles.draw(pos, .identity, tile_index);
|
||||||
|
}
|
||||||
|
|
||||||
const matrix_os_to_ws = Matrix4x4.identity;
|
|
||||||
const matrix_os_to_ws_normal = Matrix4x4.identity;
|
|
||||||
|
|
||||||
sg.applyUniforms(shaders.UB_Object_Uniforms, sg.asRange(&shaders.ObjectUniforms{
|
|
||||||
._MatrixOStoWS = matrix_os_to_ws.asArray(),
|
|
||||||
._MatrixOStoWSNormal = matrix_os_to_ws_normal.asArray(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
sg.draw(0, 6, 1);
|
|
||||||
sg.endPass();
|
sg.endPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var input_forwards: bool = false;
|
||||||
|
var input_backwards: bool = false;
|
||||||
|
var input_left: bool = false;
|
||||||
|
var input_right: bool = false;
|
||||||
|
const player_speed = 5.0;
|
||||||
|
|
||||||
pub fn onKeyDown(key_code: sapp.Keycode, mods: u32) void {
|
pub fn onKeyDown(key_code: sapp.Keycode, mods: u32) void {
|
||||||
const no_mods = mods == 0;
|
const no_mods = mods == 0;
|
||||||
|
|
||||||
|
if (key_code == .ESCAPE and no_mods) {
|
||||||
|
sapp.requestQuit();
|
||||||
|
}
|
||||||
|
|
||||||
if (key_code == .GRAVE_ACCENT and no_mods) {
|
if (key_code == .GRAVE_ACCENT and no_mods) {
|
||||||
show_console = !show_console;
|
show_console = !show_console;
|
||||||
}
|
}
|
||||||
@@ -250,6 +199,48 @@ pub fn onKeyDown(key_code: sapp.Keycode, mods: u32) void {
|
|||||||
if (key_code == .F1 and no_mods) {
|
if (key_code == .F1 and no_mods) {
|
||||||
show_demo_window = true;
|
show_demo_window = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key_code == .W) {
|
||||||
|
input_forwards = true;
|
||||||
|
input_backwards = false;
|
||||||
|
}
|
||||||
|
if (key_code == .S) {
|
||||||
|
input_backwards = true;
|
||||||
|
input_forwards = false;
|
||||||
|
}
|
||||||
|
if (key_code == .A) {
|
||||||
|
input_left = true;
|
||||||
|
input_right = false;
|
||||||
|
}
|
||||||
|
if (key_code == .D) {
|
||||||
|
input_right = true;
|
||||||
|
input_left = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn onKeyUp(key_code: sapp.Keycode, mods: u32) void {
|
||||||
|
_ = mods;
|
||||||
|
|
||||||
|
if (key_code == .W) {
|
||||||
|
input_forwards = false;
|
||||||
|
}
|
||||||
|
if (key_code == .S) {
|
||||||
|
input_backwards = false;
|
||||||
|
}
|
||||||
|
if (key_code == .A) {
|
||||||
|
input_left = false;
|
||||||
|
}
|
||||||
|
if (key_code == .D) {
|
||||||
|
input_right = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn onMouseMove(dx: f32, dy: f32) void {
|
||||||
|
camera_pitch -= dy * camera_mouse_sensitivity;
|
||||||
|
camera_yaw -= dx * camera_mouse_sensitivity;
|
||||||
|
|
||||||
|
camera_pitch = std.math.clamp(camera_pitch, -0.5 * std.math.pi, 0.5 * std.math.pi);
|
||||||
|
camera_yaw = @mod(camera_yaw, 2 * std.math.pi);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn showConsole() void {
|
fn showConsole() void {
|
||||||
|
|||||||
11
src/main.zig
11
src/main.zig
@@ -47,6 +47,8 @@ fn init() callconv(.c) void {
|
|||||||
.logger = .{ .func = sokolLogFn },
|
.logger = .{ .func = sokolLogFn },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sapp.lockMouse(true);
|
||||||
|
|
||||||
game.init();
|
game.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +68,7 @@ fn frame() callconv(.c) void {
|
|||||||
.dpi_scale = sapp.dpiScale(),
|
.dpi_scale = sapp.dpiScale(),
|
||||||
});
|
});
|
||||||
|
|
||||||
game.update(dt);
|
game.update(@floatCast(dt));
|
||||||
|
|
||||||
// --- BEGIN IMGUI PASS ---
|
// --- BEGIN IMGUI PASS ---
|
||||||
|
|
||||||
@@ -90,6 +92,13 @@ fn event(_ev: [*c]const sapp.Event) callconv(.c) void {
|
|||||||
if (ev.type == .KEY_DOWN and !ev.key_repeat) {
|
if (ev.type == .KEY_DOWN and !ev.key_repeat) {
|
||||||
game.onKeyDown(ev.key_code, ev.modifiers);
|
game.onKeyDown(ev.key_code, ev.modifiers);
|
||||||
}
|
}
|
||||||
|
if (ev.type == .KEY_UP and !ev.key_repeat) {
|
||||||
|
game.onKeyUp(ev.key_code, ev.modifiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev.type == .MOUSE_MOVE) {
|
||||||
|
game.onMouseMove(ev.mouse_dx, ev.mouse_dy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pub const Iterator3 = @import("math/Iterator3.zig");
|
||||||
pub const Matrix4x4 = @import("math/Matrix4x4.zig").Matrix4x4;
|
pub const Matrix4x4 = @import("math/Matrix4x4.zig").Matrix4x4;
|
||||||
pub const Quaternion = @import("math/Quaternion.zig").Quaternion;
|
pub const Quaternion = @import("math/Quaternion.zig").Quaternion;
|
||||||
pub const Vector2 = @import("math/Vector2.zig").Vector2;
|
pub const Vector2 = @import("math/Vector2.zig").Vector2;
|
||||||
|
|||||||
38
src/math/Iterator3.zig
Normal file
38
src/math/Iterator3.zig
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
const Vector3 = @import("Vector3.zig").Vector3;
|
||||||
|
|
||||||
|
min: Vector3,
|
||||||
|
max: Vector3,
|
||||||
|
step: Vector3,
|
||||||
|
current: ?Vector3,
|
||||||
|
|
||||||
|
pub fn init(min: Vector3, max: Vector3, step: Vector3) @This() {
|
||||||
|
return .{
|
||||||
|
.min = min,
|
||||||
|
.max = max,
|
||||||
|
.step = step,
|
||||||
|
.current = min,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(self: *@This()) ?Vector3 {
|
||||||
|
const current = self.current orelse return null;
|
||||||
|
|
||||||
|
var next_current = current;
|
||||||
|
|
||||||
|
next_current = next_current.setX(next_current.getX() + self.step.getX());
|
||||||
|
if (next_current.getX() > self.max.getX()) {
|
||||||
|
next_current = next_current.setX(self.min.getX());
|
||||||
|
next_current = next_current.setY(next_current.getY() + self.step.getY());
|
||||||
|
if (next_current.getY() > self.max.getY()) {
|
||||||
|
next_current = next_current.setY(self.min.getY());
|
||||||
|
next_current = next_current.setZ(next_current.getZ() + self.step.getZ());
|
||||||
|
if (next_current.getZ() > self.max.getZ()) {
|
||||||
|
self.current = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current = next_current;
|
||||||
|
return next_current;
|
||||||
|
}
|
||||||
@@ -30,12 +30,12 @@ pub const Vector2 = extern struct {
|
|||||||
|
|
||||||
pub inline fn asVector3(self: Vector2, z: f32) Vector3 {
|
pub inline fn asVector3(self: Vector2, z: f32) Vector3 {
|
||||||
const z_vector: @Vector(3, f32) = .{ undefined, undefined, z };
|
const z_vector: @Vector(3, f32) = .{ undefined, undefined, z };
|
||||||
return .{ .vector = @shuffle(f32, self.vector, z_vector, .{ 0, 1, ~@as(i32, -2) }) };
|
return .{ .vector = @shuffle(f32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2) }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn asVector4(self: Vector4, z: f32, w: f32) Vector4 {
|
pub inline fn asVector4(self: Vector4, z: f32, w: f32) Vector4 {
|
||||||
const zw_vector: @Vector(4, f32) = .{ undefined, undefined, z, w };
|
const zw_vector: @Vector(4, f32) = .{ undefined, undefined, z, w };
|
||||||
return .{ .vector = @shuffle(f32, self.vector, zw_vector, .{ 0, 1, ~@as(i32, -2), ~@as(i32, -3) }) };
|
return .{ .vector = @shuffle(f32, self.vector, zw_vector, [_]i32{ 0, 1, ~@as(i32, 2), ~@as(i32, 3) }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- ACCESSORS ---
|
// --- ACCESSORS ---
|
||||||
@@ -50,12 +50,12 @@ pub const Vector2 = extern struct {
|
|||||||
|
|
||||||
pub inline fn setX(self: Vector2, x: f32) Vector2 {
|
pub inline fn setX(self: Vector2, x: f32) Vector2 {
|
||||||
const x_vector: Vector = @splat(x);
|
const x_vector: Vector = @splat(x);
|
||||||
return .{ .vector = @shuffle(f32, self, x_vector, .{ ~@as(i32, 0), 1 }) };
|
return .{ .vector = @shuffle(f32, self.vector, x_vector, .{ ~@as(i32, 0), 1 }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn setY(self: Vector2, y: f32) Vector2 {
|
pub inline fn setY(self: Vector2, y: f32) Vector2 {
|
||||||
const y_vector: Vector = @splat(y);
|
const y_vector: Vector = @splat(y);
|
||||||
return .{ .vector = @shuffle(f32, self, y_vector, .{ 0, ~@as(i32, 1) }) };
|
return .{ .vector = @shuffle(f32, self.vector, y_vector, .{ 0, ~@as(i32, 1) }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- COMPONENT-WISE ---
|
// --- COMPONENT-WISE ---
|
||||||
@@ -138,8 +138,8 @@ pub const Vector2 = extern struct {
|
|||||||
const s = @sin(angle_rad);
|
const s = @sin(angle_rad);
|
||||||
return .{
|
return .{
|
||||||
.vector = .{
|
.vector = .{
|
||||||
self.x * c - self.y * s,
|
self.getX() * c - self.getY() * s,
|
||||||
self.x * s + self.x * c,
|
self.getX() * s + self.getY() * c,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ pub const Vector3 = extern struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn asVector2(self: Vector3) Vector2 {
|
pub inline fn asVector2(self: Vector3) Vector2 {
|
||||||
return .{ .vector = @shuffle(f32, self.vector, undefined, .{ 0, 1 }) };
|
return .{ .vector = @shuffle(f32, self.vector, undefined, [_]i32{ 0, 1 }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn asVector4(self: Vector3, w: f32) Vector4 {
|
pub inline fn asVector4(self: Vector3, w: f32) Vector4 {
|
||||||
const w_vector: @Vector(4, f32) = .{ undefined, undefined, undefined, w };
|
const w_vector: @Vector(4, f32) = .{ undefined, undefined, undefined, w };
|
||||||
return .{ .vector = @shuffle(f32, self.vector, w_vector, .{ 0, 1, 2, ~@as(i32, -3) }) };
|
return .{ .vector = @shuffle(f32, self.vector, w_vector, [_]i32{ 0, 1, 2, ~@as(i32, 3) }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- ACCESSORS ---
|
// --- ACCESSORS ---
|
||||||
@@ -55,17 +55,17 @@ pub const Vector3 = extern struct {
|
|||||||
|
|
||||||
pub inline fn setX(self: Vector3, x: f32) Vector3 {
|
pub inline fn setX(self: Vector3, x: f32) Vector3 {
|
||||||
const x_vector: Vector = @splat(x);
|
const x_vector: Vector = @splat(x);
|
||||||
return .{ .vector = @shuffle(f32, self, x_vector, .{ ~@as(i32, 0), 1, 2 }) };
|
return .{ .vector = @shuffle(f32, self.vector, x_vector, [_]i32{ ~@as(i32, 0), 1, 2 }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn setY(self: Vector3, y: f32) Vector3 {
|
pub inline fn setY(self: Vector3, y: f32) Vector3 {
|
||||||
const y_vector: Vector = @splat(y);
|
const y_vector: Vector = @splat(y);
|
||||||
return .{ .vector = @shuffle(f32, self, y_vector, .{ 0, ~@as(i32, 1), 2 }) };
|
return .{ .vector = @shuffle(f32, self.vector, y_vector, [_]i32{ 0, ~@as(i32, 1), 2 }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn setZ(self: Vector3, z: f32) Vector3 {
|
pub inline fn setZ(self: Vector3, z: f32) Vector3 {
|
||||||
const z_vector: Vector = @splat(z);
|
const z_vector: Vector = @splat(z);
|
||||||
return .{ .vector = @shuffle(f32, self, z_vector, .{ 0, 1, ~@as(i32, 2) }) };
|
return .{ .vector = @shuffle(f32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2) }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- COMPONENT-WISE ---
|
// --- COMPONENT-WISE ---
|
||||||
|
|||||||
@@ -31,11 +31,11 @@ pub const Vector4 = extern struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn asVector2(self: Vector4) Vector2 {
|
pub inline fn asVector2(self: Vector4) Vector2 {
|
||||||
return .{ .vector = @shuffle(f32, self.vector, undefined, .{ 0, 1 }) };
|
return .{ .vector = @shuffle(f32, self.vector, undefined, [_]i32{ 0, 1 }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn asVector3(self: Vector4) Vector3 {
|
pub inline fn asVector3(self: Vector4) Vector3 {
|
||||||
return .{ .vector = @shuffle(f32, self.vector, undefined, .{ 0, 1, 2 }) };
|
return .{ .vector = @shuffle(f32, self.vector, undefined, [_]i32{ 0, 1, 2 }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- ACCESSORS ---
|
// --- ACCESSORS ---
|
||||||
@@ -58,22 +58,22 @@ pub const Vector4 = extern struct {
|
|||||||
|
|
||||||
pub inline fn setX(self: Vector4, x: f32) Vector4 {
|
pub inline fn setX(self: Vector4, x: f32) Vector4 {
|
||||||
const x_vector: Vector = @splat(x);
|
const x_vector: Vector = @splat(x);
|
||||||
return .{ .vector = @shuffle(f32, self, x_vector, .{ ~@as(i32, 0), 1, 2, 3 }) };
|
return .{ .vector = @shuffle(f32, self.vector, x_vector, [_]i32{ ~@as(i32, 0), 1, 2, 3 }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn setY(self: Vector4, y: f32) Vector4 {
|
pub inline fn setY(self: Vector4, y: f32) Vector4 {
|
||||||
const y_vector: Vector = @splat(y);
|
const y_vector: Vector = @splat(y);
|
||||||
return .{ .vector = @shuffle(f32, self, y_vector, .{ 0, ~@as(i32, 1), 2, 3 }) };
|
return .{ .vector = @shuffle(f32, self.vector, y_vector, [_]i32{ 0, ~@as(i32, 1), 2, 3 }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn setZ(self: Vector4, z: f32) Vector4 {
|
pub inline fn setZ(self: Vector4, z: f32) Vector4 {
|
||||||
const z_vector: Vector = @splat(z);
|
const z_vector: Vector = @splat(z);
|
||||||
return .{ .vector = @shuffle(f32, self, z_vector, .{ 0, 1, ~@as(i32, 2), 3 }) };
|
return .{ .vector = @shuffle(f32, self.vector, z_vector, [_]i32{ 0, 1, ~@as(i32, 2), 3 }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn setW(self: Vector4, w: f32) Vector4 {
|
pub inline fn setW(self: Vector4, w: f32) Vector4 {
|
||||||
const w_vector: Vector = @splat(w);
|
const w_vector: Vector = @splat(w);
|
||||||
return .{ .vector = @shuffle(f32, self, w_vector, .{ 0, 1, 2, ~@as(i32, 3) }) };
|
return .{ .vector = @shuffle(f32, self.vector, w_vector, [_]i32{ 0, 1, 2, ~@as(i32, 3) }) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- COMPONENT-WISE ---
|
// --- COMPONENT-WISE ---
|
||||||
|
|||||||
186
src/tiles.zig
Normal file
186
src/tiles.zig
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
const shaders = @import("shaders");
|
||||||
|
const sokol = @import("sokol");
|
||||||
|
|
||||||
|
const sg = sokol.gfx;
|
||||||
|
|
||||||
|
const ap = @import("asset_pipeline.zig");
|
||||||
|
const game = @import("game.zig");
|
||||||
|
const main = @import("main.zig");
|
||||||
|
const math = @import("math.zig");
|
||||||
|
const samplers = @import("samplers.zig");
|
||||||
|
|
||||||
|
const Matrix4x4 = math.Matrix4x4;
|
||||||
|
const Quaternion = math.Quaternion;
|
||||||
|
const Vector3 = math.Vector3;
|
||||||
|
|
||||||
|
var vertex_buffer: sg.Buffer = undefined;
|
||||||
|
var index_buffer: sg.Buffer = undefined;
|
||||||
|
|
||||||
|
var pipeline: sg.Pipeline = undefined;
|
||||||
|
|
||||||
|
var base_color_texture: sg.Image = undefined;
|
||||||
|
var base_color_texture_view: sg.View = undefined;
|
||||||
|
|
||||||
|
var occlusion_roughness_metallic_texture: sg.Image = undefined;
|
||||||
|
var occlusion_roughness_metallic_texture_view: sg.View = undefined;
|
||||||
|
|
||||||
|
var normal_texture: sg.Image = undefined;
|
||||||
|
var normal_texture_view: sg.View = undefined;
|
||||||
|
|
||||||
|
var bindings: sg.Bindings = undefined;
|
||||||
|
|
||||||
|
pub fn init() void {
|
||||||
|
var textures = ap.visitTextures(main.temp_allocator);
|
||||||
|
defer ap.deinitTextures(main.temp_allocator, &textures);
|
||||||
|
|
||||||
|
const base_color_image = textures.getPtr("BaseColor").?;
|
||||||
|
const normal_image = textures.getPtr("Normal").?;
|
||||||
|
const occlusion_roughness_metallic_image = textures.getPtr("OcclusionRoughnessMetallic").?;
|
||||||
|
|
||||||
|
vertex_buffer = sg.makeBuffer(.{
|
||||||
|
.data = sg.asRange(&[_]f32{
|
||||||
|
// positionOS texCoord normalOS tangentOS
|
||||||
|
-0.5, -0.5, 0, 0, 1, 0, 0, 1, 1, 0, 0, -1,
|
||||||
|
0.5, -0.5, 0, 1, 1, 0, 0, 1, 1, 0, 0, -1,
|
||||||
|
-0.5, 0.5, 0, 0, 0, 0, 0, 1, 1, 0, 0, -1,
|
||||||
|
0.5, 0.5, 0, 1, 0, 0, 0, 1, 1, 0, 0, -1,
|
||||||
|
}),
|
||||||
|
.usage = .{
|
||||||
|
.immutable = true,
|
||||||
|
.vertex_buffer = true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
index_buffer = sg.makeBuffer(.{
|
||||||
|
.data = sg.asRange(&[_]u16{ 0, 1, 2, 2, 1, 3 }),
|
||||||
|
.usage = .{
|
||||||
|
.immutable = true,
|
||||||
|
.index_buffer = true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
pipeline = sg.makePipeline(.{
|
||||||
|
.shader = sg.makeShader(shaders.mainShaderDesc(sg.queryBackend())),
|
||||||
|
.layout = blk: {
|
||||||
|
var ret: sg.VertexLayoutState = .{};
|
||||||
|
ret.attrs[shaders.ATTR_main_positionOS].format = .FLOAT3;
|
||||||
|
ret.attrs[shaders.ATTR_main_texCoord].format = .FLOAT2;
|
||||||
|
ret.attrs[shaders.ATTR_main_normalOS].format = .FLOAT3;
|
||||||
|
ret.attrs[shaders.ATTR_main_tangentOS].format = .FLOAT4;
|
||||||
|
break :blk ret;
|
||||||
|
},
|
||||||
|
.depth = .{
|
||||||
|
.compare = .GREATER,
|
||||||
|
},
|
||||||
|
.primitive_type = .TRIANGLES,
|
||||||
|
.index_type = .UINT16,
|
||||||
|
.cull_mode = .BACK,
|
||||||
|
.face_winding = .CCW,
|
||||||
|
});
|
||||||
|
|
||||||
|
const sampler = samplers.getOrCreateSampler(.{
|
||||||
|
.wrap_u = .REPEAT,
|
||||||
|
.wrap_v = .REPEAT,
|
||||||
|
.wrap_w = .REPEAT,
|
||||||
|
.min_filter = .LINEAR,
|
||||||
|
.mag_filter = .LINEAR,
|
||||||
|
.mipmap_filter = .LINEAR,
|
||||||
|
}) catch unreachable;
|
||||||
|
|
||||||
|
base_color_texture = sg.makeImage(.{
|
||||||
|
.type = .ARRAY,
|
||||||
|
.usage = .{ .immutable = true },
|
||||||
|
.width = @intCast(base_color_image.width),
|
||||||
|
.height = @intCast(base_color_image.height),
|
||||||
|
.num_slices = @intCast(base_color_image.depth),
|
||||||
|
.pixel_format = .RGBA8,
|
||||||
|
.data = blk: {
|
||||||
|
var ret: sg.ImageData = .{};
|
||||||
|
ret.mip_levels[0] = sg.asRange(base_color_image.data);
|
||||||
|
break :blk ret;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
base_color_texture_view = sg.makeView(.{
|
||||||
|
.texture = .{ .image = base_color_texture },
|
||||||
|
});
|
||||||
|
|
||||||
|
occlusion_roughness_metallic_texture = sg.makeImage(.{
|
||||||
|
.type = .ARRAY,
|
||||||
|
.usage = .{ .immutable = true },
|
||||||
|
.width = @intCast(occlusion_roughness_metallic_image.width),
|
||||||
|
.height = @intCast(occlusion_roughness_metallic_image.height),
|
||||||
|
.num_slices = @intCast(occlusion_roughness_metallic_image.depth),
|
||||||
|
.pixel_format = .RGBA8,
|
||||||
|
.data = blk: {
|
||||||
|
var ret: sg.ImageData = .{};
|
||||||
|
ret.mip_levels[0] = sg.asRange(occlusion_roughness_metallic_image.data);
|
||||||
|
break :blk ret;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
occlusion_roughness_metallic_texture_view = sg.makeView(.{
|
||||||
|
.texture = .{ .image = occlusion_roughness_metallic_texture },
|
||||||
|
});
|
||||||
|
|
||||||
|
normal_texture = sg.makeImage(.{
|
||||||
|
.type = .ARRAY,
|
||||||
|
.usage = .{ .immutable = true },
|
||||||
|
.width = @intCast(normal_image.width),
|
||||||
|
.height = @intCast(normal_image.height),
|
||||||
|
.num_slices = @intCast(normal_image.depth),
|
||||||
|
.pixel_format = .RGBA8,
|
||||||
|
.data = blk: {
|
||||||
|
var ret: sg.ImageData = .{};
|
||||||
|
ret.mip_levels[0] = sg.asRange(normal_image.data);
|
||||||
|
break :blk ret;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
normal_texture_view = sg.makeView(.{
|
||||||
|
.texture = .{ .image = normal_texture },
|
||||||
|
});
|
||||||
|
|
||||||
|
bindings = .{};
|
||||||
|
|
||||||
|
bindings.vertex_buffers[0] = vertex_buffer;
|
||||||
|
bindings.index_buffer = index_buffer;
|
||||||
|
|
||||||
|
bindings.views[shaders.VIEW_Point_Lights] = game.point_light_buffer_view;
|
||||||
|
bindings.views[shaders.VIEW_Directional_Lights] = game.directional_light_buffer_view;
|
||||||
|
bindings.views[shaders.VIEW__BaseColorTexture] = base_color_texture_view;
|
||||||
|
bindings.views[shaders.VIEW__OcclusionRoughnessMetallicTexture] = occlusion_roughness_metallic_texture_view;
|
||||||
|
bindings.views[shaders.VIEW__NormalTexture] = normal_texture_view;
|
||||||
|
|
||||||
|
bindings.samplers[shaders.SMP__Sampler] = sampler;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit() void {
|
||||||
|
sg.destroyView(normal_texture_view);
|
||||||
|
sg.destroyImage(normal_texture);
|
||||||
|
sg.destroyView(occlusion_roughness_metallic_texture_view);
|
||||||
|
sg.destroyImage(occlusion_roughness_metallic_texture);
|
||||||
|
sg.destroyView(base_color_texture_view);
|
||||||
|
sg.destroyImage(base_color_texture);
|
||||||
|
sg.destroyPipeline(pipeline);
|
||||||
|
sg.destroyBuffer(index_buffer);
|
||||||
|
sg.destroyBuffer(vertex_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind() void {
|
||||||
|
sg.applyPipeline(pipeline);
|
||||||
|
sg.applyBindings(bindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(translation: Vector3, rotation: Quaternion, texture_index: u32) void {
|
||||||
|
const matrix_os_to_ws = Matrix4x4.initTranslationRotationScale(translation, rotation, .one);
|
||||||
|
const matrix_os_to_ws_normal = Matrix4x4.inverseTransposeAffine(matrix_os_to_ws);
|
||||||
|
|
||||||
|
sg.applyUniforms(shaders.UB_Material_Uniforms, sg.asRange(&shaders.MaterialUniforms{
|
||||||
|
._TextureIndex = @intCast(texture_index),
|
||||||
|
}));
|
||||||
|
|
||||||
|
sg.applyUniforms(shaders.UB_Object_Uniforms, sg.asRange(&shaders.ObjectUniforms{
|
||||||
|
._MatrixOStoWS = matrix_os_to_ws.asArray(),
|
||||||
|
._MatrixOStoWSNormal = matrix_os_to_ws_normal.asArray(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
sg.draw(0, 6, 1);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user