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 fn visitTextures(allocator: std.mem.Allocator) std.hash_map.StringHashMapUnmanaged(Texture) {
|
||||
pub fn visitTextures(allocator: std.mem.Allocator) AssetMap(Texture) {
|
||||
zstbi.init(allocator);
|
||||
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();
|
||||
while (it.next()) |entry| {
|
||||
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 sglue = sokol.glue;
|
||||
|
||||
const ap = @import("asset_pipeline.zig");
|
||||
const main = @import("main.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 Quaternion = math.Quaternion;
|
||||
const Vector2 = math.Vector2;
|
||||
const Vector3 = math.Vector3;
|
||||
|
||||
var show_console: 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 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 {
|
||||
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(.{
|
||||
.size = @sizeOf([4]shaders.PointLight),
|
||||
.usage = .{
|
||||
@@ -87,6 +45,9 @@ pub fn init() void {
|
||||
.storage_buffer = true,
|
||||
},
|
||||
});
|
||||
point_light_buffer_view = sg.makeView(.{
|
||||
.storage_buffer = .{ .buffer = point_light_buffer },
|
||||
});
|
||||
|
||||
directional_light_buffer = sg.makeBuffer(.{
|
||||
.size = @sizeOf([4]shaders.DirectionalLight),
|
||||
@@ -95,86 +56,33 @@ pub fn init() void {
|
||||
.storage_buffer = true,
|
||||
},
|
||||
});
|
||||
|
||||
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(.{
|
||||
directional_light_buffer_view = sg.makeView(.{
|
||||
.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 {
|
||||
_ = dt;
|
||||
sg.destroyView(directional_light_buffer_view);
|
||||
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) {
|
||||
showConsole();
|
||||
@@ -205,44 +113,85 @@ pub fn update(dt: f64) void {
|
||||
.swapchain = sglue.swapchain(),
|
||||
});
|
||||
|
||||
sg.applyPipeline(pipeline);
|
||||
sg.applyBindings(bindings);
|
||||
tiles.bind();
|
||||
|
||||
const matrix_ws_to_vs = Matrix4x4.identity;
|
||||
const matrix_vs_to_cs = Matrix4x4.identity;
|
||||
const ambient_light = Vector3.init(0.01, 0.01, 0.01);
|
||||
const camera_rotation = Quaternion.mulQuaternion(
|
||||
.initRotationXY(camera_yaw),
|
||||
.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{
|
||||
._MatrixWStoVS = matrix_ws_to_vs.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{
|
||||
._MatrixWStoVS = matrix_ws_to_vs.asArray(),
|
||||
._AmbientLight = ambient_light.asArray(),
|
||||
._PointLightCount = 0,
|
||||
._PointLightCount = @intCast(point_lights.len),
|
||||
._DirectionalLightCount = 0,
|
||||
}));
|
||||
|
||||
sg.applyUniforms(shaders.UB_Material_Uniforms, sg.asRange(&shaders.MaterialUniforms{
|
||||
._TextureIndex = 0,
|
||||
}));
|
||||
var it = Iterator3.init(.init(-10, -10, 0), .init(10, 10, 0), .one);
|
||||
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();
|
||||
}
|
||||
|
||||
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 {
|
||||
const no_mods = mods == 0;
|
||||
|
||||
if (key_code == .ESCAPE and no_mods) {
|
||||
sapp.requestQuit();
|
||||
}
|
||||
|
||||
if (key_code == .GRAVE_ACCENT and no_mods) {
|
||||
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) {
|
||||
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 {
|
||||
|
||||
11
src/main.zig
11
src/main.zig
@@ -47,6 +47,8 @@ fn init() callconv(.c) void {
|
||||
.logger = .{ .func = sokolLogFn },
|
||||
});
|
||||
|
||||
sapp.lockMouse(true);
|
||||
|
||||
game.init();
|
||||
}
|
||||
|
||||
@@ -66,7 +68,7 @@ fn frame() callconv(.c) void {
|
||||
.dpi_scale = sapp.dpiScale(),
|
||||
});
|
||||
|
||||
game.update(dt);
|
||||
game.update(@floatCast(dt));
|
||||
|
||||
// --- 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) {
|
||||
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 Quaternion = @import("math/Quaternion.zig").Quaternion;
|
||||
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 {
|
||||
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 {
|
||||
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 ---
|
||||
@@ -50,12 +50,12 @@ pub const Vector2 = extern struct {
|
||||
|
||||
pub inline fn setX(self: Vector2, x: f32) Vector2 {
|
||||
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 {
|
||||
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 ---
|
||||
@@ -138,8 +138,8 @@ pub const Vector2 = extern struct {
|
||||
const s = @sin(angle_rad);
|
||||
return .{
|
||||
.vector = .{
|
||||
self.x * c - self.y * s,
|
||||
self.x * s + self.x * c,
|
||||
self.getX() * c - self.getY() * s,
|
||||
self.getX() * s + self.getY() * c,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,12 +31,12 @@ pub const Vector3 = extern struct {
|
||||
}
|
||||
|
||||
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 {
|
||||
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 ---
|
||||
@@ -55,17 +55,17 @@ pub const Vector3 = extern struct {
|
||||
|
||||
pub inline fn setX(self: Vector3, x: f32) Vector3 {
|
||||
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 {
|
||||
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 {
|
||||
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 ---
|
||||
|
||||
@@ -31,11 +31,11 @@ pub const Vector4 = extern struct {
|
||||
}
|
||||
|
||||
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 {
|
||||
return .{ .vector = @shuffle(f32, self.vector, undefined, .{ 0, 1, 2 }) };
|
||||
return .{ .vector = @shuffle(f32, self.vector, undefined, [_]i32{ 0, 1, 2 }) };
|
||||
}
|
||||
|
||||
// --- ACCESSORS ---
|
||||
@@ -58,22 +58,22 @@ pub const Vector4 = extern struct {
|
||||
|
||||
pub inline fn setX(self: Vector4, x: f32) Vector4 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 ---
|
||||
|
||||
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