Vulkan port
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +1,2 @@
|
|||||||
|
*.hdr filter=lfs diff=lfs merge=lfs -text
|
||||||
*.png filter=lfs diff=lfs merge=lfs -text
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@vs vertex
|
@vs vs_main
|
||||||
|
|
||||||
layout(location = 0) in vec3 positionOS;
|
layout(location = 0) in vec3 positionOS;
|
||||||
layout(location = 1) in vec2 texCoord;
|
layout(location = 1) in vec2 texCoord;
|
||||||
@@ -43,7 +43,7 @@ void main() {
|
|||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@fs fragment
|
@fs fs_main
|
||||||
|
|
||||||
struct Point_Light {
|
struct Point_Light {
|
||||||
vec3 positionWS;
|
vec3 positionWS;
|
||||||
@@ -217,4 +217,60 @@ void main() {
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@program main vertex fragment
|
@cs cs_equirectangular_to_cubemap
|
||||||
|
|
||||||
|
layout(binding = 0) uniform Layer_Index {
|
||||||
|
int _LayerIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(binding = 0) uniform texture2D _EquirectangularTexture;
|
||||||
|
layout(binding = 1, rgba16f) uniform writeonly image2DArray _CubemapImage;
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler _EquirectangularSampler;
|
||||||
|
|
||||||
|
const float INV_PI = 0.31830987;
|
||||||
|
const float HALF_INV_PI = 0.15915494;
|
||||||
|
|
||||||
|
layout(local_size_x = 8, local_size_y = 8) in;
|
||||||
|
void main() {
|
||||||
|
vec2 size = vec2(imageSize(_CubemapImage).xy);
|
||||||
|
vec2 texCoord = (vec2(gl_GlobalInvocationID.xy) + vec2(0.5)) / size;
|
||||||
|
|
||||||
|
texCoord = texCoord * vec2(2.0) - vec2(1.0); // Map to range [-1, 1]
|
||||||
|
|
||||||
|
vec3 cubeCoord;
|
||||||
|
if (_LayerIndex == 0) {
|
||||||
|
// Positive X
|
||||||
|
cubeCoord = vec3(1, -texCoord.y, -texCoord.x);
|
||||||
|
} else if (_LayerIndex == 1) {
|
||||||
|
// Negative X
|
||||||
|
cubeCoord = vec3(-1, -texCoord.y, texCoord.x);
|
||||||
|
} else if (_LayerIndex == 2) {
|
||||||
|
// Positive Y
|
||||||
|
cubeCoord = vec3(texCoord.x, 1, texCoord.y);
|
||||||
|
} else if (_LayerIndex == 3) {
|
||||||
|
// Negative Y
|
||||||
|
cubeCoord = vec3(texCoord.x, -1, -texCoord.y);
|
||||||
|
} else if (_LayerIndex == 4) {
|
||||||
|
// Positive Z
|
||||||
|
cubeCoord = vec3(texCoord.x, -texCoord.y, 1);
|
||||||
|
} else if (_LayerIndex == 5) {
|
||||||
|
// Negative Z
|
||||||
|
cubeCoord = vec3(-texCoord.x, -texCoord.y, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 cubeDir = normalize(cubeCoord);
|
||||||
|
|
||||||
|
float theta = atan(cubeDir.y, cubeDir.x);
|
||||||
|
float phi = asin(cubeDir.z);
|
||||||
|
|
||||||
|
vec2 equirectCoord = vec2(theta * HALF_INV_PI, phi * INV_PI) + vec2(0.5);
|
||||||
|
|
||||||
|
vec4 irradiance = texture(sampler2D(_EquirectangularTexture, _EquirectangularSampler), equirectCoord);
|
||||||
|
imageStore(_CubemapImage, ivec3(ivec2(gl_GlobalInvocationID.xy), _LayerIndex), irradiance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@program main vs_main fs_main
|
||||||
|
@program equirectangular_to_cubemap cs_equirectangular_to_cubemap
|
||||||
|
|||||||
BIN
assets/skybox.hdr
(Stored with Git LFS)
Normal file
BIN
assets/skybox.hdr
(Stored with Git LFS)
Normal file
Binary file not shown.
55
build.zig
55
build.zig
@@ -1,13 +1,22 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const cimgui = @import("cimgui");
|
const zon = @import("build.zig.zon");
|
||||||
const sokol = @import("sokol");
|
|
||||||
|
|
||||||
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 cimgui_conf = cimgui.getConfig(false);
|
const vulkan_dep = b.dependency("vulkan_zig", .{ .registry = b.path("vendor/vk.xml") });
|
||||||
|
const zglfw_dep = b.dependency("zglfw", .{ .import_vulkan = true });
|
||||||
|
const zstbi_dep = b.dependency("zstbi", .{});
|
||||||
|
|
||||||
|
const vulkan_mod = vulkan_dep.module("vulkan-zig");
|
||||||
|
const zglfw_mod = zglfw_dep.module("root");
|
||||||
|
const zstbi_mod = zstbi_dep.module("root");
|
||||||
|
|
||||||
|
zglfw_mod.addImport("vulkan", vulkan_mod);
|
||||||
|
|
||||||
|
const zglfw_lib = zglfw_dep.artifact("glfw");
|
||||||
|
|
||||||
const exe_mod = b.createModule(.{
|
const exe_mod = b.createModule(.{
|
||||||
.root_source_file = b.path("src/main.zig"),
|
.root_source_file = b.path("src/main.zig"),
|
||||||
@@ -15,40 +24,14 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
|
||||||
const cimgui_dep = b.dependency("cimgui", .{
|
exe_mod.addImport("vulkan", vulkan_mod);
|
||||||
.target = target,
|
exe_mod.addImport("zglfw", zglfw_mod);
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
const sokol_dep = b.dependency("sokol", .{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
.with_sokol_imgui = true,
|
|
||||||
});
|
|
||||||
sokol_dep.artifact("sokol_clib").addIncludePath(cimgui_dep.path(cimgui_conf.include_dir));
|
|
||||||
|
|
||||||
const zstbi_dep = b.dependency("zstbi", .{});
|
|
||||||
|
|
||||||
const sokol_mod = sokol_dep.module("sokol");
|
|
||||||
const shdc_dep = sokol_dep.builder.dependency("shdc", .{});
|
|
||||||
|
|
||||||
const shaders_mod = try sokol.shdc.createModule(b, "shaders", sokol_mod, .{
|
|
||||||
.shdc_dep = shdc_dep,
|
|
||||||
.input = "assets/shaders.glsl",
|
|
||||||
.output = "shaders.zig",
|
|
||||||
.slang = .{
|
|
||||||
.glsl430 = true,
|
|
||||||
.hlsl5 = true,
|
|
||||||
.metal_macos = true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const zstbi_mod = zstbi_dep.module("root");
|
|
||||||
|
|
||||||
exe_mod.addImport("cimgui", cimgui_dep.module(cimgui_conf.module_name));
|
|
||||||
exe_mod.addImport("shaders", shaders_mod);
|
|
||||||
exe_mod.addImport("sokol", sokol_mod);
|
|
||||||
exe_mod.addImport("zstbi", zstbi_mod);
|
exe_mod.addImport("zstbi", zstbi_mod);
|
||||||
|
exe_mod.linkLibrary(zglfw_lib);
|
||||||
|
|
||||||
|
const options = b.addOptions();
|
||||||
|
options.addOption([]const u8, "version", zon.version);
|
||||||
|
exe_mod.addOptions("config", options);
|
||||||
|
|
||||||
const exe = b.addExecutable(.{
|
const exe = b.addExecutable(.{
|
||||||
.name = "voxel-game",
|
.name = "voxel-game",
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
.minimum_zig_version = "0.15.2",
|
.minimum_zig_version = "0.15.2",
|
||||||
|
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.sokol = .{
|
.vulkan_zig = .{
|
||||||
.url = "git+https://github.com/floooh/sokol-zig.git#1c217971533e3aa634ecbfbe13ff776e05701e0a",
|
.url = "git+https://github.com/Snektron/vulkan-zig.git#1446b0b994c2362264cc24513d7c7ec31b469c50",
|
||||||
.hash = "sokol-0.1.0-pb1HK3TYLgCx8lOxdLVWIVDcAzacxO8YDfyw2Er-_2nN",
|
.hash = "vulkan-0.0.0-r7Ytx_VDAwAiMl0YSu2UOkVMIGJN7CeIQaxJR-hUSfD6",
|
||||||
},
|
},
|
||||||
.cimgui = .{
|
.zglfw = .{
|
||||||
.url = "git+https://github.com/floooh/dcimgui.git#d5fb4e3d27b79062dc5981db3631dadc4f204654",
|
.url = "git+https://github.com/zig-gamedev/zglfw.git#6034a5623312c58bf5e64c1a2b686691c28575f4",
|
||||||
.hash = "cimgui-0.1.0-44Clkd6YlAAYULKHDwsDX9EPmka-VAVEjUl-o6ve307E",
|
.hash = "zglfw-0.10.0-dev-zgVDNPKyIQCBi-wv_vxkvIQq1u0bP4D56Wszx_2mszc7",
|
||||||
},
|
},
|
||||||
.zstbi = .{
|
.zstbi = .{
|
||||||
.url = "git+https://github.com/zig-gamedev/zstbi#2c4b3100ccb7aed90ecc9439030899764e2a8d47",
|
.url = "git+https://github.com/zig-gamedev/zstbi#2c4b3100ccb7aed90ecc9439030899764e2a8d47",
|
||||||
|
|||||||
@@ -15,6 +15,18 @@ pub const Texture = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const TextureHdr = struct {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
depth: u32,
|
||||||
|
data: []f16,
|
||||||
|
|
||||||
|
pub fn deinit(self: *TextureHdr, allocator: std.mem.Allocator) void {
|
||||||
|
allocator.free(self.data);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const AssetMap = std.hash_map.StringHashMapUnmanaged;
|
pub const AssetMap = std.hash_map.StringHashMapUnmanaged;
|
||||||
|
|
||||||
pub fn visitTextures(allocator: std.mem.Allocator) AssetMap(Texture) {
|
pub fn visitTextures(allocator: std.mem.Allocator) AssetMap(Texture) {
|
||||||
@@ -63,7 +75,7 @@ pub fn visitTextures(allocator: std.mem.Allocator) AssetMap(Texture) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn visitTexture(allocator: std.mem.Allocator, dir: std.fs.Dir, filename: []const u8) !Texture {
|
fn visitTexture(allocator: std.mem.Allocator, dir: std.fs.Dir, filename: []const u8) !Texture {
|
||||||
std.log.info("Processing \"{s}\"...", .{filename});
|
std.log.info("Processing \"{s}\"...", .{filename});
|
||||||
|
|
||||||
const file = dir.openFile(filename, .{}) catch |err| {
|
const file = dir.openFile(filename, .{}) catch |err| {
|
||||||
@@ -117,6 +129,50 @@ pub fn visitTexture(allocator: std.mem.Allocator, dir: std.fs.Dir, filename: []c
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn visitSkybox(allocator: std.mem.Allocator) !TextureHdr {
|
||||||
|
zstbi.init(allocator);
|
||||||
|
defer zstbi.deinit();
|
||||||
|
|
||||||
|
const cwd = std.fs.cwd();
|
||||||
|
const filename = "assets/skybox.hdr";
|
||||||
|
std.log.info("Processing \"{s}\"...", .{filename});
|
||||||
|
|
||||||
|
const file = cwd.openFile(filename, .{}) catch |err| {
|
||||||
|
std.log.err("Could not open \"{s}\" file: {s}", .{ filename, @errorName(err) });
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
defer file.close();
|
||||||
|
|
||||||
|
const file_buf = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| {
|
||||||
|
std.log.err("Could not read \"{s}\" file contents due to an error: {s}", .{ filename, @errorName(err) });
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
defer allocator.free(file_buf);
|
||||||
|
|
||||||
|
var img = zstbi.Image.loadFromMemory(file_buf, 4) catch |err| {
|
||||||
|
std.log.err("Error reading \"{s}\" as an image file: {s}", .{ filename, @errorName(err) });
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
defer img.deinit();
|
||||||
|
|
||||||
|
std.log.debug("size: {}×{} | components: {} | hdr: {}", .{ img.width, img.height, img.num_components, img.is_hdr });
|
||||||
|
|
||||||
|
const data = allocator.alloc(f16, 4 * img.width * img.height) catch |err| {
|
||||||
|
std.log.err("Ran out of memory while trying to allocate output buffer", .{});
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
errdefer allocator.free(data);
|
||||||
|
|
||||||
|
@memcpy(data, std.mem.bytesAsSlice(f16, img.data));
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.width = img.width,
|
||||||
|
.height = img.height,
|
||||||
|
.depth = 1,
|
||||||
|
.data = data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn rearrange(grid_w: u32, grid_h: u32, tile_w: u32, tile_h: u32, inbuf: []const u8, outbuf: []u8) void {
|
fn rearrange(grid_w: u32, grid_h: u32, tile_w: u32, tile_h: u32, inbuf: []const u8, outbuf: []u8) void {
|
||||||
std.log.debug("rearrange: {}×{} grid of {}×{} tiles", .{ grid_w, grid_h, tile_w, tile_h });
|
std.log.debug("rearrange: {}×{} grid of {}×{} tiles", .{ grid_w, grid_h, tile_w, tile_h });
|
||||||
|
|
||||||
|
|||||||
22
src/const.zig
Normal file
22
src/const.zig
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Vector2 = @import("math.zig").Vector2;
|
||||||
|
|
||||||
|
pub const app_name = "voxel-game";
|
||||||
|
pub const app_version_string = @import("config").version;
|
||||||
|
pub const app_version = std.SemanticVersion.parse(app_version_string) catch unreachable;
|
||||||
|
|
||||||
|
pub const min_framerate = 30.0;
|
||||||
|
pub const min_frametime = 1.0 / min_framerate;
|
||||||
|
|
||||||
|
pub const default_window_width = 1280;
|
||||||
|
pub const default_window_height = 720;
|
||||||
|
pub const default_window_size = Vector2.init(default_window_width, default_window_height);
|
||||||
|
|
||||||
|
pub const min_window_width = 640;
|
||||||
|
pub const min_window_height = 360;
|
||||||
|
pub const min_window_size = Vector2.init(default_window_width, default_window_height);
|
||||||
|
|
||||||
|
pub const window_title = "Voxel Game";
|
||||||
|
|
||||||
|
pub const temp_allocator_capacity = 16 * 1024 * 1024;
|
||||||
250
src/engine.zig
Normal file
250
src/engine.zig
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const glfw = @import("zglfw");
|
||||||
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
|
const c = @import("const.zig");
|
||||||
|
const main = @import("main.zig");
|
||||||
|
|
||||||
|
pub const required_instance_layers = [_][*:0]const u8{
|
||||||
|
"VK_LAYER_KHRONOS_validation",
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const required_device_extensions = [_][*:0]const u8{
|
||||||
|
vk.extensions.khr_swapchain.name,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const vk_log_scope = .vulkan;
|
||||||
|
pub const log = std.log.scoped(vk_log_scope);
|
||||||
|
|
||||||
|
pub var vkb: vk.BaseWrapper = undefined;
|
||||||
|
pub var vki: vk.InstanceProxy = undefined;
|
||||||
|
pub var vkd: vk.DeviceProxy = undefined;
|
||||||
|
|
||||||
|
pub var dum: vk.DebugUtilsMessengerEXT = undefined;
|
||||||
|
pub var surface: vk.SurfaceKHR = undefined;
|
||||||
|
pub var graphics_queue: vk.Queue = undefined;
|
||||||
|
pub var present_queue: vk.Queue = undefined;
|
||||||
|
pub var memory_properties: vk.PhysicalDeviceMemoryProperties = undefined;
|
||||||
|
|
||||||
|
pub fn init() !void {
|
||||||
|
vkb = vk.BaseWrapper.load(glfw.getInstanceProcAddress);
|
||||||
|
|
||||||
|
var vk_instance_extensions = blk: {
|
||||||
|
var ret: std.ArrayList([*:0]const u8) = .empty;
|
||||||
|
try ret.append(main.allocator, vk.extensions.ext_debug_utils.name);
|
||||||
|
try ret.append(main.allocator, vk.extensions.khr_portability_enumeration.name);
|
||||||
|
try ret.append(main.allocator, vk.extensions.khr_get_physical_device_properties_2.name);
|
||||||
|
|
||||||
|
const glfw_instance_extensions = try glfw.getRequiredInstanceExtensions();
|
||||||
|
try ret.appendSlice(main.allocator, glfw_instance_extensions);
|
||||||
|
|
||||||
|
break :blk ret;
|
||||||
|
};
|
||||||
|
defer vk_instance_extensions.deinit(main.allocator);
|
||||||
|
|
||||||
|
const dum_create_info: vk.DebugUtilsMessengerCreateInfoEXT = .{
|
||||||
|
.message_severity = .{
|
||||||
|
.verbose_bit_ext = false,
|
||||||
|
.info_bit_ext = false,
|
||||||
|
.warning_bit_ext = true,
|
||||||
|
.error_bit_ext = true,
|
||||||
|
},
|
||||||
|
.message_type = .{
|
||||||
|
.general_bit_ext = true,
|
||||||
|
.validation_bit_ext = true,
|
||||||
|
.performance_bit_ext = true,
|
||||||
|
},
|
||||||
|
.pfn_user_callback = &dumCallback,
|
||||||
|
.p_user_data = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const version = vk.makeApiVersion(
|
||||||
|
0,
|
||||||
|
c.app_version.major,
|
||||||
|
c.app_version.minor,
|
||||||
|
c.app_version.patch,
|
||||||
|
);
|
||||||
|
|
||||||
|
const instance = vkb.createInstance(&.{
|
||||||
|
.p_application_info = &.{
|
||||||
|
.p_application_name = c.app_name,
|
||||||
|
.application_version = @bitCast(version),
|
||||||
|
.p_engine_name = c.app_name,
|
||||||
|
.engine_version = @bitCast(version),
|
||||||
|
.api_version = @bitCast(vk.API_VERSION_1_2),
|
||||||
|
},
|
||||||
|
.enabled_layer_count = required_instance_layers.len,
|
||||||
|
.pp_enabled_layer_names = &required_instance_layers,
|
||||||
|
.enabled_extension_count = @intCast(vk_instance_extensions.items.len),
|
||||||
|
.pp_enabled_extension_names = vk_instance_extensions.items.ptr,
|
||||||
|
.flags = .{ .enumerate_portability_bit_khr = true },
|
||||||
|
.p_next = &dum_create_info,
|
||||||
|
}, null) catch |err| {
|
||||||
|
std.log.err("Could not create Vulkan Instance", .{});
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
||||||
|
const instance_wrapper_ptr = try main.allocator.create(vk.InstanceWrapper);
|
||||||
|
errdefer main.allocator.destroy(instance_wrapper_ptr);
|
||||||
|
|
||||||
|
instance_wrapper_ptr.* = vk.InstanceWrapper.load(instance, vkb.dispatch.vkGetInstanceProcAddr.?);
|
||||||
|
vki = vk.InstanceProxy.init(instance, instance_wrapper_ptr);
|
||||||
|
errdefer vki.destroyInstance(null);
|
||||||
|
|
||||||
|
dum = try vki.createDebugUtilsMessengerEXT(&dum_create_info, null);
|
||||||
|
errdefer vki.destroyDebugUtilsMessengerEXT(dum, null);
|
||||||
|
|
||||||
|
try glfw.createWindowSurface(instance, main.window, null, &surface);
|
||||||
|
errdefer vki.destroySurfaceKHR(surface, null);
|
||||||
|
|
||||||
|
const physical_devices = try vki.enumeratePhysicalDevicesAlloc(main.allocator);
|
||||||
|
defer main.allocator.free(physical_devices);
|
||||||
|
|
||||||
|
const physical_device_data = physical_device_blk: {
|
||||||
|
loop: for (physical_devices) |physical_device_candidate| {
|
||||||
|
const device_properties = vki.getPhysicalDeviceProperties(physical_device_candidate);
|
||||||
|
const device_name = std.mem.sliceTo(&device_properties.device_name, 0);
|
||||||
|
|
||||||
|
const device_extensions = try vki.enumerateDeviceExtensionPropertiesAlloc(physical_device_candidate, null, main.allocator);
|
||||||
|
defer main.allocator.free(device_extensions);
|
||||||
|
|
||||||
|
for (required_device_extensions) |a| {
|
||||||
|
const a_name = std.mem.span(a);
|
||||||
|
for (device_extensions) |b| {
|
||||||
|
const b_name = std.mem.sliceTo(&b.extension_name, 0);
|
||||||
|
if (std.mem.eql(u8, a_name, b_name)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std.log.debug("Device \"{s}\" does not support Vulkan Device Extension \"{s}\" and is not suitable for this application", .{ device_name, a_name });
|
||||||
|
continue :loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var format_count: u32 = undefined;
|
||||||
|
_ = try vki.getPhysicalDeviceSurfaceFormatsKHR(physical_device_candidate, surface, &format_count, null);
|
||||||
|
if (format_count == 0) {
|
||||||
|
std.log.debug("Device \"{s}\" has zero Vulkan Surface formats and is not suitable for this application", .{device_name});
|
||||||
|
continue :loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
var present_mode_count: u32 = undefined;
|
||||||
|
_ = try vki.getPhysicalDeviceSurfacePresentModesKHR(physical_device_candidate, surface, &present_mode_count, null);
|
||||||
|
if (present_mode_count == 0) {
|
||||||
|
std.log.debug("Device \"{s}\" has zero Vulkan Present Modes and is not suitable for this application", .{device_name});
|
||||||
|
continue :loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
const device_queue_families = try vki.getPhysicalDeviceQueueFamilyPropertiesAlloc(physical_device_candidate, main.allocator);
|
||||||
|
defer main.allocator.free(device_queue_families);
|
||||||
|
|
||||||
|
const graphics_family_id = blk: {
|
||||||
|
var family_id: u32 = 0;
|
||||||
|
while (family_id < device_queue_families.len) : (family_id += 1) {
|
||||||
|
const family = device_queue_families[family_id];
|
||||||
|
if (family.queue_flags.graphics_bit) {
|
||||||
|
break :blk family_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std.log.debug("Device \"{s}\" has no Vulkan Queue Family with graphics flag and is not suitable for this application", .{device_name});
|
||||||
|
continue :loop;
|
||||||
|
};
|
||||||
|
|
||||||
|
const present_family_id = blk: {
|
||||||
|
var family_id: u32 = 0;
|
||||||
|
while (family_id < device_queue_families.len) : (family_id += 1) {
|
||||||
|
if (try vki.getPhysicalDeviceSurfaceSupportKHR(physical_device_candidate, family_id, surface) == .true) {
|
||||||
|
break :blk family_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std.log.debug("Device \"{s}\" has no Vulkan Queue Family with Vulkan Surface Support and is not suitable for this application", .{device_name});
|
||||||
|
continue :loop;
|
||||||
|
};
|
||||||
|
|
||||||
|
break :physical_device_blk .{
|
||||||
|
.handle = physical_device_candidate,
|
||||||
|
.name = device_name,
|
||||||
|
.properties = device_properties,
|
||||||
|
.graphics_family_id = graphics_family_id,
|
||||||
|
.present_family_id = present_family_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std.log.err("Could not find suitable Vulkan Physical Device", .{});
|
||||||
|
return error.NoSuitableDevice;
|
||||||
|
};
|
||||||
|
|
||||||
|
std.log.debug("Picked Vulkan Physical Device \"{s}\"", .{physical_device_data.name});
|
||||||
|
|
||||||
|
const device = try vki.createDevice(physical_device_data.handle, &.{
|
||||||
|
.queue_create_info_count = if (physical_device_data.graphics_family_id == physical_device_data.present_family_id) 1 else 2,
|
||||||
|
.p_queue_create_infos = &.{
|
||||||
|
.{ .queue_family_index = physical_device_data.graphics_family_id, .queue_count = 1, .p_queue_priorities = &.{1.0} },
|
||||||
|
.{ .queue_family_index = physical_device_data.present_family_id, .queue_count = 1, .p_queue_priorities = &.{1.0} },
|
||||||
|
},
|
||||||
|
.enabled_extension_count = required_device_extensions.len,
|
||||||
|
.pp_enabled_extension_names = &required_device_extensions,
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
const device_wrapper_ptr = try main.allocator.create(vk.DeviceWrapper);
|
||||||
|
errdefer main.allocator.destroy(device_wrapper_ptr);
|
||||||
|
|
||||||
|
device_wrapper_ptr.* = vk.DeviceWrapper.load(device, vki.wrapper.dispatch.vkGetDeviceProcAddr.?);
|
||||||
|
vkd = vk.DeviceProxy.init(device, device_wrapper_ptr);
|
||||||
|
errdefer vkd.destroyDevice(null);
|
||||||
|
|
||||||
|
graphics_queue = vkd.getDeviceQueue(physical_device_data.graphics_family_id, 0);
|
||||||
|
present_queue = vkd.getDeviceQueue(physical_device_data.present_family_id, 0);
|
||||||
|
|
||||||
|
memory_properties = vki.getPhysicalDeviceMemoryProperties(physical_device_data.handle);
|
||||||
|
|
||||||
|
const framebuffer_width, const framebuffer_height = blk: {
|
||||||
|
const w, const h = main.window.getFramebufferSize();
|
||||||
|
break :blk [_]u32{ @intCast(w), @intCast(h) };
|
||||||
|
};
|
||||||
|
|
||||||
|
const vk_extent: vk.Extent2D = .{
|
||||||
|
.width = framebuffer_width,
|
||||||
|
.height = framebuffer_height,
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = vk_extent;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit() void {
|
||||||
|
vkd.destroyDevice(null);
|
||||||
|
vki.destroySurfaceKHR(surface, null);
|
||||||
|
vki.destroyDebugUtilsMessengerEXT(dum, null);
|
||||||
|
vki.destroyInstance(null);
|
||||||
|
|
||||||
|
main.allocator.destroy(vki.wrapper);
|
||||||
|
main.allocator.destroy(vkd.wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dumCallback(
|
||||||
|
severity: vk.DebugUtilsMessageSeverityFlagsEXT,
|
||||||
|
message_type: vk.DebugUtilsMessageTypeFlagsEXT,
|
||||||
|
maybe_callback_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT,
|
||||||
|
_: ?*anyopaque,
|
||||||
|
) callconv(.c) vk.Bool32 {
|
||||||
|
const message = if (maybe_callback_data) |callback_data| callback_data.p_message orelse return .false else return .false;
|
||||||
|
const type_name = if (message_type.general_bit_ext) "general" else if (message_type.validation_bit_ext) "validation" else if (message_type.performance_bit_ext) "performance" else if (message_type.device_address_binding_bit_ext) "device_address_binding" else "unknown";
|
||||||
|
|
||||||
|
const format = "[{s}] {s}";
|
||||||
|
const args = .{ type_name, message };
|
||||||
|
|
||||||
|
if (severity.error_bit_ext) {
|
||||||
|
log.err(format, args);
|
||||||
|
} else if (severity.warning_bit_ext) {
|
||||||
|
log.warn(format, args);
|
||||||
|
} else if (severity.info_bit_ext) {
|
||||||
|
log.info(format, args);
|
||||||
|
} else if (severity.verbose_bit_ext) {
|
||||||
|
log.debug(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return .false;
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ const main = @import("main.zig");
|
|||||||
const math = @import("math.zig");
|
const math = @import("math.zig");
|
||||||
const tiles = @import("tiles.zig");
|
const tiles = @import("tiles.zig");
|
||||||
const samplers = @import("samplers.zig");
|
const samplers = @import("samplers.zig");
|
||||||
|
const skybox = @import("skybox.zig");
|
||||||
|
|
||||||
const Iterator3 = math.Iterator3;
|
const Iterator3 = math.Iterator3;
|
||||||
const Matrix4x4 = math.Matrix4x4;
|
const Matrix4x4 = math.Matrix4x4;
|
||||||
@@ -47,9 +48,11 @@ pub fn init() void {
|
|||||||
.stream_update = true,
|
.stream_update = true,
|
||||||
.storage_buffer = true,
|
.storage_buffer = true,
|
||||||
},
|
},
|
||||||
|
.label = "PointLight Buffer",
|
||||||
});
|
});
|
||||||
point_light_buffer_view = sg.makeView(.{
|
point_light_buffer_view = sg.makeView(.{
|
||||||
.storage_buffer = .{ .buffer = point_light_buffer },
|
.storage_buffer = .{ .buffer = point_light_buffer },
|
||||||
|
.label = "PointLight BV",
|
||||||
});
|
});
|
||||||
|
|
||||||
directional_light_buffer = sg.makeBuffer(.{
|
directional_light_buffer = sg.makeBuffer(.{
|
||||||
@@ -58,15 +61,19 @@ pub fn init() void {
|
|||||||
.stream_update = true,
|
.stream_update = true,
|
||||||
.storage_buffer = true,
|
.storage_buffer = true,
|
||||||
},
|
},
|
||||||
|
.label = "DirectionalLight Buffer",
|
||||||
});
|
});
|
||||||
directional_light_buffer_view = sg.makeView(.{
|
directional_light_buffer_view = sg.makeView(.{
|
||||||
.storage_buffer = .{ .buffer = directional_light_buffer },
|
.storage_buffer = .{ .buffer = directional_light_buffer },
|
||||||
|
.label = "DirectionalLight BV",
|
||||||
});
|
});
|
||||||
|
|
||||||
tiles.init();
|
tiles.init();
|
||||||
|
skybox.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit() void {
|
pub fn deinit() void {
|
||||||
|
skybox.deinit();
|
||||||
tiles.deinit();
|
tiles.deinit();
|
||||||
|
|
||||||
sg.destroyView(directional_light_buffer_view);
|
sg.destroyView(directional_light_buffer_view);
|
||||||
|
|||||||
0
src/global.zig
Normal file
0
src/global.zig
Normal file
226
src/main.zig
226
src/main.zig
@@ -1,215 +1,63 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const ig = @import("cimgui");
|
const glfw = @import("zglfw");
|
||||||
const sokol = @import("sokol");
|
const stbi = @import("zstbi");
|
||||||
|
const vk = @import("vulkan");
|
||||||
const sapp = sokol.app;
|
|
||||||
const sg = sokol.gfx;
|
|
||||||
const sglue = sokol.glue;
|
|
||||||
const simgui = sokol.imgui;
|
|
||||||
|
|
||||||
|
const c = @import("const.zig");
|
||||||
|
const engine = @import("engine.zig");
|
||||||
const game = @import("game.zig");
|
const game = @import("game.zig");
|
||||||
const Log = @import("Log.zig");
|
|
||||||
|
|
||||||
pub const min_framerate = 30.0;
|
|
||||||
pub const min_frametime = 1.0 / min_framerate;
|
|
||||||
pub const min_window_height = 360;
|
|
||||||
pub const min_window_width = 640;
|
|
||||||
pub const temp_allocator_capacity = 16 * 1024 * 1024;
|
|
||||||
pub const window_title = "voxel-game";
|
|
||||||
|
|
||||||
pub var allocator: std.mem.Allocator = undefined;
|
pub var allocator: std.mem.Allocator = undefined;
|
||||||
pub var temp_allocator: std.mem.Allocator = undefined;
|
pub var temp_allocator: std.mem.Allocator = undefined;
|
||||||
|
pub var window: *glfw.Window = undefined;
|
||||||
pub var logs: std.ArrayListUnmanaged(Log) = .empty;
|
|
||||||
|
|
||||||
pub const std_options: std.Options = .{
|
|
||||||
.logFn = logFn,
|
|
||||||
};
|
|
||||||
|
|
||||||
const imgui_action = blk: {
|
|
||||||
var ret: sg.PassAction = .{};
|
|
||||||
|
|
||||||
ret.colors[0] = .{
|
|
||||||
.load_action = .LOAD,
|
|
||||||
};
|
|
||||||
|
|
||||||
break :blk ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
fn init() callconv(.c) void {
|
|
||||||
sg.setup(.{
|
|
||||||
.environment = sglue.environment(),
|
|
||||||
.logger = .{ .func = sokolLogFn },
|
|
||||||
});
|
|
||||||
|
|
||||||
simgui.setup(.{
|
|
||||||
.logger = .{ .func = sokolLogFn },
|
|
||||||
});
|
|
||||||
|
|
||||||
sapp.lockMouse(true);
|
|
||||||
|
|
||||||
game.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deinit() callconv(.c) void {
|
|
||||||
game.deinit();
|
|
||||||
simgui.shutdown();
|
|
||||||
sg.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn frame() callconv(.c) void {
|
|
||||||
const dt = sapp.frameDuration();
|
|
||||||
|
|
||||||
simgui.newFrame(.{
|
|
||||||
.width = sapp.width(),
|
|
||||||
.height = sapp.height(),
|
|
||||||
.delta_time = dt,
|
|
||||||
.dpi_scale = sapp.dpiScale(),
|
|
||||||
});
|
|
||||||
|
|
||||||
game.update(@floatCast(dt));
|
|
||||||
|
|
||||||
// --- BEGIN IMGUI PASS ---
|
|
||||||
|
|
||||||
sg.beginPass(.{
|
|
||||||
.action = imgui_action,
|
|
||||||
.swapchain = sglue.swapchain(),
|
|
||||||
});
|
|
||||||
simgui.render();
|
|
||||||
sg.endPass();
|
|
||||||
|
|
||||||
// --- END IMGUI PASS ---
|
|
||||||
|
|
||||||
sg.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(_ev: [*c]const sapp.Event) callconv(.c) void {
|
|
||||||
const ev: *const sapp.Event = @ptrCast(_ev);
|
|
||||||
const ig_capture_keyboard = simgui.handleEvent(ev.*);
|
|
||||||
|
|
||||||
if (!ig_capture_keyboard) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
|
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
|
||||||
defer _ = gpa.deinit();
|
defer _ = gpa.deinit();
|
||||||
|
|
||||||
var fba: std.heap.FixedBufferAllocator = .init(&struct {
|
var fba: std.heap.FixedBufferAllocator = .init(&struct {
|
||||||
pub var buffer: [temp_allocator_capacity]u8 = undefined;
|
pub var buffer: [c.temp_allocator_capacity]u8 = undefined;
|
||||||
}.buffer);
|
}.buffer);
|
||||||
|
|
||||||
allocator = gpa.allocator();
|
allocator = gpa.allocator();
|
||||||
temp_allocator = fba.threadSafeAllocator();
|
temp_allocator = fba.threadSafeAllocator();
|
||||||
|
|
||||||
defer {
|
stbi.init(allocator);
|
||||||
for (logs.items) |log| {
|
defer stbi.deinit();
|
||||||
allocator.free(log.message);
|
|
||||||
}
|
|
||||||
logs.deinit(allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
sapp.run(.{
|
glfw.init() catch |err| {
|
||||||
.init_cb = &init,
|
std.log.err("Could not initialize GLFW", .{});
|
||||||
.cleanup_cb = &deinit,
|
return err;
|
||||||
.frame_cb = &frame,
|
|
||||||
.event_cb = &event,
|
|
||||||
.window_title = "Voxel Game",
|
|
||||||
.width = 1280,
|
|
||||||
.height = 720,
|
|
||||||
.icon = .{ .sokol_default = true },
|
|
||||||
.logger = .{ .func = sokolLogFn },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sokolLogFn(
|
|
||||||
maybe_tag: ?[*:0]const u8,
|
|
||||||
log_level: u32,
|
|
||||||
log_item: u32,
|
|
||||||
maybe_message: ?[*:0]const u8,
|
|
||||||
line_nr: u32,
|
|
||||||
maybe_filename: ?[*:0]const u8,
|
|
||||||
user_data: ?*anyopaque,
|
|
||||||
) callconv(.c) void {
|
|
||||||
defer {
|
|
||||||
if (log_level == 0) {
|
|
||||||
const message = std.mem.span(maybe_message) orelse "";
|
|
||||||
@panic(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const _SLOG_LINE_LENGTH = 512;
|
|
||||||
|
|
||||||
_ = user_data;
|
|
||||||
|
|
||||||
var line_buf: [_SLOG_LINE_LENGTH]u8 = undefined;
|
|
||||||
var writer = std.Io.Writer.fixed(&line_buf);
|
|
||||||
|
|
||||||
if (maybe_tag) |tag| {
|
|
||||||
writer.print("[{s}]", .{tag}) catch return;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.print("[{s}]", .{switch (log_level) {
|
|
||||||
0 => "panic",
|
|
||||||
1 => "error",
|
|
||||||
2 => "warning",
|
|
||||||
else => "info",
|
|
||||||
}}) catch return;
|
|
||||||
|
|
||||||
writer.print("[id:{d}]", .{log_item}) catch return;
|
|
||||||
|
|
||||||
if (maybe_filename) |filename| {
|
|
||||||
writer.print(" {s}:{d}:0: ", .{ filename, line_nr }) catch return;
|
|
||||||
} else {
|
|
||||||
writer.print("[line:{d}]", .{line_nr}) catch return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maybe_message) |message| {
|
|
||||||
writer.print("\n\t{s}", .{message}) catch return;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.print("\n\n", .{}) catch return;
|
|
||||||
|
|
||||||
if (log_level == 0) {
|
|
||||||
writer.print("ABORTING because of [panic]\n", .{}) catch return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const level: std.log.Level = switch (log_level) {
|
|
||||||
0, 1 => .err,
|
|
||||||
2 => .warn,
|
|
||||||
else => .info,
|
|
||||||
};
|
};
|
||||||
|
defer glfw.terminate();
|
||||||
|
|
||||||
const full_message = allocator.dupe(u8, writer.buffered()) catch return;
|
if (!glfw.isVulkanSupported()) {
|
||||||
|
std.log.err("Vulkan is not supported by this system", .{});
|
||||||
|
return error.NoVulkan;
|
||||||
|
}
|
||||||
|
|
||||||
std.debug.print("{s}", .{full_message});
|
glfw.windowHint(.client_api, .no_api);
|
||||||
|
window = glfw.Window.create(c.default_window_width, c.default_window_height, c.window_title, null) catch |err| {
|
||||||
logs.append(allocator, .init(level, full_message)) catch {
|
std.log.err("Could not create window", .{});
|
||||||
allocator.free(full_message);
|
return err;
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
}
|
defer window.destroy();
|
||||||
|
|
||||||
fn logFn(
|
window.setSizeLimits(c.min_window_width, c.min_window_height, -1, -1);
|
||||||
comptime level: std.log.Level,
|
|
||||||
comptime _: @Type(.enum_literal),
|
engine.init() catch |err| {
|
||||||
comptime fmt: []const u8,
|
std.log.err("Could not initialize engine", .{});
|
||||||
args: anytype,
|
return err;
|
||||||
) void {
|
|
||||||
const message = std.fmt.allocPrint(allocator, fmt, args) catch return;
|
|
||||||
logs.append(allocator, .init(level, message)) catch {
|
|
||||||
allocator.free(message);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
defer engine.deinit();
|
||||||
|
|
||||||
|
//game.init();
|
||||||
|
//defer game.deinit();
|
||||||
|
|
||||||
|
while (!window.shouldClose()) {
|
||||||
|
glfw.pollEvents();
|
||||||
|
//game.update(dt);
|
||||||
|
window.swapBuffers();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
111
src/skybox.zig
Normal file
111
src/skybox.zig
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
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 cubemap_size = 512;
|
||||||
|
|
||||||
|
var skybox_equirectangular_texture: sg.Image = undefined;
|
||||||
|
var skybox_equirectangular_texture_view: sg.View = undefined;
|
||||||
|
|
||||||
|
var skybox_cubemap_texture: sg.Image = undefined;
|
||||||
|
var skybox_cubemap_texture_view: sg.View = undefined;
|
||||||
|
|
||||||
|
pub fn init() void {
|
||||||
|
var image = ap.visitSkybox(main.allocator) catch unreachable;
|
||||||
|
defer image.deinit(main.allocator);
|
||||||
|
|
||||||
|
skybox_equirectangular_texture = sg.makeImage(.{
|
||||||
|
.type = ._2D,
|
||||||
|
.usage = .{ .immutable = true },
|
||||||
|
.width = @intCast(image.width),
|
||||||
|
.height = @intCast(image.height),
|
||||||
|
.num_slices = @intCast(image.depth),
|
||||||
|
.pixel_format = .RGBA16F,
|
||||||
|
.data = blk: {
|
||||||
|
var ret: sg.ImageData = .{};
|
||||||
|
ret.mip_levels[0] = sg.asRange(image.data);
|
||||||
|
break :blk ret;
|
||||||
|
},
|
||||||
|
.label = "Skybox Equirectangular Texture",
|
||||||
|
});
|
||||||
|
skybox_equirectangular_texture_view = sg.makeView(.{
|
||||||
|
.texture = .{ .image = skybox_equirectangular_texture },
|
||||||
|
.label = "Skybox Equirectangular TV",
|
||||||
|
});
|
||||||
|
|
||||||
|
skybox_cubemap_texture = sg.makeImage(.{
|
||||||
|
.type = .CUBE,
|
||||||
|
.usage = .{
|
||||||
|
.immutable = true,
|
||||||
|
.storage_image = true,
|
||||||
|
},
|
||||||
|
.width = cubemap_size,
|
||||||
|
.height = cubemap_size,
|
||||||
|
.pixel_format = .RGBA16F,
|
||||||
|
.label = "Skybox Cubemap Texture",
|
||||||
|
});
|
||||||
|
skybox_cubemap_texture_view = sg.makeView(.{
|
||||||
|
.texture = .{ .image = skybox_cubemap_texture },
|
||||||
|
.label = "Skybox Cubemap TV",
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
sg.beginPass(.{ .compute = true });
|
||||||
|
defer sg.endPass();
|
||||||
|
|
||||||
|
const pipeline = sg.makePipeline(.{
|
||||||
|
.shader = sg.makeShader(shaders.equirectangularToCubemapShaderDesc(sg.queryBackend())),
|
||||||
|
.compute = true,
|
||||||
|
.label = "EquirectangularToCubemap Compute Pipeline",
|
||||||
|
});
|
||||||
|
defer sg.destroyPipeline(pipeline);
|
||||||
|
|
||||||
|
sg.applyPipeline(pipeline);
|
||||||
|
|
||||||
|
const sampler = samplers.getOrCreateSampler(.{
|
||||||
|
.wrap_u = .REPEAT,
|
||||||
|
.wrap_v = .REPEAT,
|
||||||
|
.wrap_w = .REPEAT,
|
||||||
|
.min_filter = .LINEAR,
|
||||||
|
.mag_filter = .LINEAR,
|
||||||
|
.mipmap_filter = .LINEAR,
|
||||||
|
}) catch unreachable;
|
||||||
|
|
||||||
|
var layer_index: i32 = 0;
|
||||||
|
while (layer_index < 6) : (layer_index += 1) {
|
||||||
|
const skybox_cubemap_image_storage_view = sg.makeView(.{
|
||||||
|
.storage_image = .{
|
||||||
|
.image = skybox_cubemap_texture,
|
||||||
|
.slice = layer_index,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
defer sg.destroyView(skybox_cubemap_image_storage_view);
|
||||||
|
|
||||||
|
var bindings: sg.Bindings = .{};
|
||||||
|
|
||||||
|
bindings.views[shaders.VIEW__EquirectangularTexture] = skybox_equirectangular_texture_view;
|
||||||
|
bindings.views[shaders.VIEW__CubemapImage] = skybox_cubemap_image_storage_view;
|
||||||
|
|
||||||
|
bindings.samplers[shaders.SMP__EquirectangularSampler] = sampler;
|
||||||
|
sg.applyBindings(bindings);
|
||||||
|
|
||||||
|
sg.applyUniforms(0, sg.asRange(&shaders.LayerIndex{
|
||||||
|
._LayerIndex = layer_index,
|
||||||
|
}));
|
||||||
|
|
||||||
|
sg.dispatch(@divExact(cubemap_size, 8), @divExact(cubemap_size, 8), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit() void {
|
||||||
|
sg.destroyView(skybox_equirectangular_texture_view);
|
||||||
|
sg.destroyImage(skybox_equirectangular_texture);
|
||||||
|
}
|
||||||
@@ -30,8 +30,8 @@ var normal_texture_view: sg.View = undefined;
|
|||||||
var bindings: sg.Bindings = undefined;
|
var bindings: sg.Bindings = undefined;
|
||||||
|
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
var textures = ap.visitTextures(main.temp_allocator);
|
var textures = ap.visitTextures(main.allocator);
|
||||||
defer ap.deinitTextures(main.temp_allocator, &textures);
|
defer ap.deinitTextures(main.allocator, &textures);
|
||||||
|
|
||||||
const base_color_image = textures.getPtr("BaseColor").?;
|
const base_color_image = textures.getPtr("BaseColor").?;
|
||||||
const normal_image = textures.getPtr("Normal").?;
|
const normal_image = textures.getPtr("Normal").?;
|
||||||
@@ -49,6 +49,7 @@ pub fn init() void {
|
|||||||
.immutable = true,
|
.immutable = true,
|
||||||
.vertex_buffer = true,
|
.vertex_buffer = true,
|
||||||
},
|
},
|
||||||
|
.label = "Tile Quad VB",
|
||||||
});
|
});
|
||||||
|
|
||||||
index_buffer = sg.makeBuffer(.{
|
index_buffer = sg.makeBuffer(.{
|
||||||
@@ -57,6 +58,7 @@ pub fn init() void {
|
|||||||
.immutable = true,
|
.immutable = true,
|
||||||
.index_buffer = true,
|
.index_buffer = true,
|
||||||
},
|
},
|
||||||
|
.label = "Tile Quad IB",
|
||||||
});
|
});
|
||||||
|
|
||||||
pipeline = sg.makePipeline(.{
|
pipeline = sg.makePipeline(.{
|
||||||
@@ -76,6 +78,7 @@ pub fn init() void {
|
|||||||
.index_type = .UINT16,
|
.index_type = .UINT16,
|
||||||
.cull_mode = .BACK,
|
.cull_mode = .BACK,
|
||||||
.face_winding = .CCW,
|
.face_winding = .CCW,
|
||||||
|
.label = "Tile Pipeline",
|
||||||
});
|
});
|
||||||
|
|
||||||
const sampler = samplers.getOrCreateSampler(.{
|
const sampler = samplers.getOrCreateSampler(.{
|
||||||
@@ -99,9 +102,11 @@ pub fn init() void {
|
|||||||
ret.mip_levels[0] = sg.asRange(base_color_image.data);
|
ret.mip_levels[0] = sg.asRange(base_color_image.data);
|
||||||
break :blk ret;
|
break :blk ret;
|
||||||
},
|
},
|
||||||
|
.label = "Tile BaseColor Texture",
|
||||||
});
|
});
|
||||||
base_color_texture_view = sg.makeView(.{
|
base_color_texture_view = sg.makeView(.{
|
||||||
.texture = .{ .image = base_color_texture },
|
.texture = .{ .image = base_color_texture },
|
||||||
|
.label = "Tile BaseColor TV",
|
||||||
});
|
});
|
||||||
|
|
||||||
occlusion_roughness_metallic_texture = sg.makeImage(.{
|
occlusion_roughness_metallic_texture = sg.makeImage(.{
|
||||||
@@ -116,9 +121,11 @@ pub fn init() void {
|
|||||||
ret.mip_levels[0] = sg.asRange(occlusion_roughness_metallic_image.data);
|
ret.mip_levels[0] = sg.asRange(occlusion_roughness_metallic_image.data);
|
||||||
break :blk ret;
|
break :blk ret;
|
||||||
},
|
},
|
||||||
|
.label = "Tile ORM Texture",
|
||||||
});
|
});
|
||||||
occlusion_roughness_metallic_texture_view = sg.makeView(.{
|
occlusion_roughness_metallic_texture_view = sg.makeView(.{
|
||||||
.texture = .{ .image = occlusion_roughness_metallic_texture },
|
.texture = .{ .image = occlusion_roughness_metallic_texture },
|
||||||
|
.label = "Tile ORM TV",
|
||||||
});
|
});
|
||||||
|
|
||||||
normal_texture = sg.makeImage(.{
|
normal_texture = sg.makeImage(.{
|
||||||
@@ -133,9 +140,11 @@ pub fn init() void {
|
|||||||
ret.mip_levels[0] = sg.asRange(normal_image.data);
|
ret.mip_levels[0] = sg.asRange(normal_image.data);
|
||||||
break :blk ret;
|
break :blk ret;
|
||||||
},
|
},
|
||||||
|
.label = "Tile Normal Texture",
|
||||||
});
|
});
|
||||||
normal_texture_view = sg.makeView(.{
|
normal_texture_view = sg.makeView(.{
|
||||||
.texture = .{ .image = normal_texture },
|
.texture = .{ .image = normal_texture },
|
||||||
|
.label = "Tile Normal TV",
|
||||||
});
|
});
|
||||||
|
|
||||||
bindings = .{};
|
bindings = .{};
|
||||||
|
|||||||
32335
vendor/vk.xml
vendored
Normal file
32335
vendor/vk.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user