Compare commits
15 commits
dynamic_bu
...
master
Author | SHA1 | Date | |
---|---|---|---|
61a18e6f0b | |||
bd725421b6 | |||
27689b8cda | |||
56ec32fcf2 | |||
1bba633d99 | |||
2e08987c83 | |||
d81957a096 | |||
e182d73edc | |||
c0591ecb24 | |||
de68ccac0d | |||
4bd2bff03e | |||
cbf0980b67 | |||
8a7970b12e | |||
849f6b2dae | |||
32a3accb85 |
35 changed files with 21416 additions and 478 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "libs/sdl"]
|
||||
path = libs/sdl
|
||||
url = git@github.com:ikskuh/SDL.zig.git
|
1
.ignore
1
.ignore
|
@ -1 +1,2 @@
|
|||
libs/
|
||||
vk.xml
|
||||
|
|
4663
assets/models/teapot.obj
Normal file
4663
assets/models/teapot.obj
Normal file
File diff suppressed because it is too large
Load diff
13
assets/models/tescoPiwo.mtl
Normal file
13
assets/models/tescoPiwo.mtl
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Blender 4.2.0 MTL File: 'tescoPiwo.blend'
|
||||
# www.blender.org
|
||||
|
||||
newmtl Material.001
|
||||
Ns 360.000000
|
||||
Ka 0.500000 0.500000 0.500000
|
||||
Ks 0.500000 0.500000 0.500000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.500000
|
||||
d 1.000000
|
||||
illum 3
|
||||
map_Kd tescoPiwoTexture.png
|
||||
map_Bump -bm 1.000000 /home/przmk/Downloads/Downloads/tescoPiwoNormal.png
|
1751
assets/models/tescoPiwo.obj
Normal file
1751
assets/models/tescoPiwo.obj
Normal file
File diff suppressed because it is too large
Load diff
BIN
assets/textures/giraffe.png
Normal file
BIN
assets/textures/giraffe.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 674 KiB |
BIN
assets/textures/tescoPiwoNormal.png
Normal file
BIN
assets/textures/tescoPiwoNormal.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
BIN
assets/textures/tescoPiwoTexture.png
Normal file
BIN
assets/textures/tescoPiwoTexture.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 179 KiB |
BIN
assets/textures/test.png
Normal file
BIN
assets/textures/test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
33
build.zig
33
build.zig
|
@ -1,6 +1,6 @@
|
|||
const std = @import("std");
|
||||
const sdl = @import("sdl");
|
||||
const vkgen = @import("vulkan_zig");
|
||||
const vkgen = @import("vulkan");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
@ -12,12 +12,15 @@ pub fn build(b: *std.Build) void {
|
|||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
});
|
||||
|
||||
// exe.addIncludePath(b.path("include/"));
|
||||
|
||||
// --- Dependencies ---
|
||||
|
||||
// Vulkan
|
||||
const vkzig_dep = b.dependency("vulkan_zig", .{
|
||||
const vkzig_dep = b.dependency("vulkan", .{
|
||||
.registry = @as([]const u8, b.pathFromRoot("./vk.xml")),
|
||||
});
|
||||
const vkzig_bindings = vkzig_dep.module("vulkan-zig");
|
||||
|
@ -25,28 +28,46 @@ pub fn build(b: *std.Build) void {
|
|||
|
||||
const shader_comp = vkgen.ShaderCompileStep.create(
|
||||
b,
|
||||
&[_][]const u8{ "glslc", "--target-env=vulkan1.3" },
|
||||
.{ .real_path = "glslc" },
|
||||
&[_][]const u8{"--target-env=vulkan1.3"},
|
||||
"-o",
|
||||
);
|
||||
shader_comp.add("shader_frag", "src/shaders/shader.frag", .{});
|
||||
shader_comp.add("shader_vert", "src/shaders/shader.vert", .{});
|
||||
shader_comp.add("second_frag", "src/shaders/second.frag", .{});
|
||||
shader_comp.add("second_vert", "src/shaders/second.vert", .{});
|
||||
exe.root_module.addImport("shaders", shader_comp.getModule());
|
||||
|
||||
// SDL2
|
||||
const sdl_sdk = sdl.init(b, null, null);
|
||||
sdl_sdk.link(exe, .dynamic, .SDL2);
|
||||
const sdl_sdk = sdl.init(b, .{});
|
||||
sdl_sdk.link(exe, .dynamic, sdl.Library.SDL2);
|
||||
exe.root_module.addImport("sdl2", sdl_sdk.getWrapperModuleVulkan(vkzig_bindings));
|
||||
|
||||
// zmath
|
||||
const zmath = b.dependency("zmath", .{});
|
||||
exe.root_module.addImport("zmath", zmath.module("root"));
|
||||
|
||||
// zstbi
|
||||
const zstbi = b.dependency("zstbi", .{});
|
||||
exe.root_module.addImport("zstbi", zstbi.module("root"));
|
||||
exe.linkLibrary(zstbi.artifact("zstbi"));
|
||||
|
||||
// Assimp
|
||||
exe.linkSystemLibrary("assimp");
|
||||
|
||||
// ---
|
||||
|
||||
b.installArtifact(exe);
|
||||
|
||||
const exe_check = b.addExecutable(.{
|
||||
.name = "vulkan-test",
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const check = b.step("check", "Check if vulkan-test compiles");
|
||||
check.dependOn(&exe.step);
|
||||
check.dependOn(&exe_check.step);
|
||||
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
|
||||
.dependencies = .{
|
||||
.zmath = .{ .path = "libs/zmath" },
|
||||
.vulkan_zig = .{
|
||||
.url = "https://github.com/Snektron/vulkan-zig/archive/9f6e6177b1fdb3ed22231d9216a24480e84cfa5e.tar.gz",
|
||||
.hash = "1220f2961df224f7d35dee774b26194b8b937cc252fa8e4023407776c58521d53e38",
|
||||
.zstbi = .{ .path = "libs/zstbi" },
|
||||
.sdl = .{ .path = "libs/sdl" },
|
||||
.vulkan = .{
|
||||
.url = "https://github.com/Snektron/vulkan-zig/archive/f7b21d034f527765f62935de1b62855033621989.tar.gz",
|
||||
.hash = "12201e484e173e70634e664864763223427703e677f28c63ebec9332513c8ca5121c",
|
||||
},
|
||||
.sdl = .{
|
||||
.url = "https://github.com/MasterQ32/SDL.zig/archive/1432ed3f6a020973906fbc996868131ae1d631be.tar.gz",
|
||||
.hash = "1220ebeeaade31e207a56977aff537a65e6338cddc68d50217ddf30bbc58fb27d367",
|
||||
.obj = .{
|
||||
.url = "https://github.com/chip2n/zig-obj/archive/58f524ed6834790b29ac1e97b2f9e6b7de7b5346.tar.gz",
|
||||
.hash = "1220ff46dcbeb40677c0ce8560b954885beec8b699835d9e6686beab72aa9d422c79",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -19,8 +21,5 @@
|
|||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
// For example...
|
||||
//"LICENSE",
|
||||
//"README.md",
|
||||
},
|
||||
}
|
||||
|
|
1
libs/sdl
Submodule
1
libs/sdl
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 172a84e7b5ce7d4891b8b970c68f4532f96aa7e9
|
|
@ -329,7 +329,7 @@ pub inline fn boolx16(
|
|||
// zig fmt: on
|
||||
|
||||
pub inline fn veclen(comptime T: type) comptime_int {
|
||||
return @typeInfo(T).Vector.len;
|
||||
return @typeInfo(T).vector.len;
|
||||
}
|
||||
|
||||
pub inline fn splat(comptime T: type, value: f32) T {
|
||||
|
@ -413,14 +413,14 @@ pub inline fn storeArr4(arr: *[4]f32, v: F32x4) void {
|
|||
}
|
||||
|
||||
pub inline fn arr3Ptr(ptr: anytype) *const [3]f32 {
|
||||
comptime assert(@typeInfo(@TypeOf(ptr)) == .Pointer);
|
||||
comptime assert(@typeInfo(@TypeOf(ptr)) == .pointer);
|
||||
const T = std.meta.Child(@TypeOf(ptr));
|
||||
comptime assert(T == F32x4);
|
||||
return @as(*const [3]f32, @ptrCast(ptr));
|
||||
}
|
||||
|
||||
pub inline fn arrNPtr(ptr: anytype) [*]const f32 {
|
||||
comptime assert(@typeInfo(@TypeOf(ptr)) == .Pointer);
|
||||
comptime assert(@typeInfo(@TypeOf(ptr)) == .pointer);
|
||||
const T = std.meta.Child(@TypeOf(ptr));
|
||||
comptime assert(T == Mat or T == F32x4 or T == F32x8 or T == F32x16);
|
||||
return @as([*]const f32, @ptrCast(ptr));
|
||||
|
|
22
libs/zstbi/LICENSE
Normal file
22
libs/zstbi/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Michal Ziulek
|
||||
Copyright (c) 2024 zig-gamedev contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
93
libs/zstbi/README.md
Normal file
93
libs/zstbi/README.md
Normal file
|
@ -0,0 +1,93 @@
|
|||
# zstbi v0.10.0 - stb image bindings
|
||||
|
||||
## Features
|
||||
|
||||
* Supports Zig memory allocators
|
||||
* Supports decoding most popular formats
|
||||
* Supports HDR images
|
||||
* Supports 8-bits and 16-bits per channel
|
||||
* Supports image resizing
|
||||
* Supports image writing (.png, .jpg)
|
||||
|
||||
## Getting started
|
||||
|
||||
Copy `zstbi` to a subdirectory of your project and add the following to your `build.zig.zon` .dependencies:
|
||||
```zig
|
||||
.zstbi = .{ .path = "libs/zstbi" },
|
||||
```
|
||||
|
||||
Then in your `build.zig` add:
|
||||
```zig
|
||||
pub fn build(b: *std.Build) void {
|
||||
const exe = b.addExecutable(.{ ... });
|
||||
|
||||
const zstbi = b.dependency("zstbi", .{});
|
||||
exe.root_module.addImport("zstbi", zstbi.module("root"));
|
||||
exe.linkLibrary(zstbi.artifact("zstbi"));
|
||||
}
|
||||
```
|
||||
Now in your code you may import and use `zstbi`.
|
||||
|
||||
Init the lib. `zstbi.init()` is cheap and you may call it whenever you need to change memory allocator. Must be called from the main thread.
|
||||
```zig
|
||||
const zstbi = @import("zstbi");
|
||||
|
||||
zstbi.init(allocator);
|
||||
defer zstbi.deinit();
|
||||
```
|
||||
```zig
|
||||
pub const Image = struct {
|
||||
data: []u8,
|
||||
width: u32,
|
||||
height: u32,
|
||||
num_components: u32,
|
||||
bytes_per_component: u32,
|
||||
bytes_per_row: u32,
|
||||
is_hdr: bool,
|
||||
...
|
||||
```
|
||||
```zig
|
||||
pub fn loadFromFile(pathname: [:0]const u8, forced_num_components: u32) !Image
|
||||
|
||||
pub fn loadFromMemory(data: []const u8, forced_num_components: u32) !Image
|
||||
|
||||
pub fn createEmpty(width: u32, height: u32, num_components: u32, args: struct {
|
||||
bytes_per_component: u32 = 0,
|
||||
bytes_per_row: u32 = 0,
|
||||
}) !Image
|
||||
|
||||
pub fn info(pathname: [:0]const u8) struct {
|
||||
is_supported: bool,
|
||||
width: u32,
|
||||
height: u32,
|
||||
num_components: u32,
|
||||
}
|
||||
|
||||
pub fn resize(image: *const Image, new_width: u32, new_height: u32) Image
|
||||
|
||||
pub fn writeToFile(
|
||||
image: *const Image,
|
||||
filename: [:0]const u8,
|
||||
image_format: ImageWriteFormat,
|
||||
) ImageWriteError!void
|
||||
|
||||
pub fn writeToFn(
|
||||
image: *const Image,
|
||||
write_fn: *const fn (ctx: ?*anyopaque, data: ?*anyopaque, size: c_int) callconv(.C) void,
|
||||
context: ?*anyopaque,
|
||||
image_format: ImageWriteFormat,
|
||||
) ImageWriteError!void
|
||||
```
|
||||
```zig
|
||||
var image = try zstbi.Image.loadFromFile("data/image.png", forced_num_components);
|
||||
defer image.deinit();
|
||||
|
||||
const new_resized_image = image.resize(1024, 1024);
|
||||
```
|
||||
Misc functions:
|
||||
```zig
|
||||
pub fn isHdr(filename: [:0]const u8) bool
|
||||
pub fn is16bit(filename: [:0]const u8) bool
|
||||
|
||||
pub fn setFlipVerticallyOnLoad(should_flip: bool) void
|
||||
```
|
52
libs/zstbi/build.zig
Normal file
52
libs/zstbi/build.zig
Normal file
|
@ -0,0 +1,52 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
||||
_ = b.addModule("root", .{
|
||||
.root_source_file = b.path("src/zstbi.zig"),
|
||||
});
|
||||
|
||||
const zstbi_lib = b.addStaticLibrary(.{
|
||||
.name = "zstbi",
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
zstbi_lib.addIncludePath(b.path("libs/stbi"));
|
||||
if (optimize == .Debug) {
|
||||
// TODO: Workaround for Zig bug.
|
||||
zstbi_lib.addCSourceFile(.{
|
||||
.file = b.path("src/zstbi.c"),
|
||||
.flags = &.{
|
||||
"-std=c99",
|
||||
"-fno-sanitize=undefined",
|
||||
"-g",
|
||||
"-O0",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
zstbi_lib.addCSourceFile(.{
|
||||
.file = b.path("src/zstbi.c"),
|
||||
.flags = &.{
|
||||
"-std=c99",
|
||||
"-fno-sanitize=undefined",
|
||||
},
|
||||
});
|
||||
}
|
||||
zstbi_lib.linkLibC();
|
||||
b.installArtifact(zstbi_lib);
|
||||
|
||||
const test_step = b.step("test", "Run zstbi tests");
|
||||
|
||||
const tests = b.addTest(.{
|
||||
.name = "zstbi-tests",
|
||||
.root_source_file = b.path("src/zstbi.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
tests.linkLibrary(zstbi_lib);
|
||||
b.installArtifact(tests);
|
||||
|
||||
test_step.dependOn(&b.addRunArtifact(tests).step);
|
||||
}
|
11
libs/zstbi/build.zig.zon
Normal file
11
libs/zstbi/build.zig.zon
Normal file
|
@ -0,0 +1,11 @@
|
|||
.{
|
||||
.name = "zstbi",
|
||||
.version = "0.10.0",
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"libs",
|
||||
"src",
|
||||
"README.md",
|
||||
},
|
||||
}
|
7987
libs/zstbi/libs/stbi/stb_image.h
Normal file
7987
libs/zstbi/libs/stbi/stb_image.h
Normal file
File diff suppressed because it is too large
Load diff
2634
libs/zstbi/libs/stbi/stb_image_resize.h
Normal file
2634
libs/zstbi/libs/stbi/stb_image_resize.h
Normal file
File diff suppressed because it is too large
Load diff
1724
libs/zstbi/libs/stbi/stb_image_write.h
Normal file
1724
libs/zstbi/libs/stbi/stb_image_write.h
Normal file
File diff suppressed because it is too large
Load diff
32
libs/zstbi/src/zstbi.c
Normal file
32
libs/zstbi/src/zstbi.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
void* (*zstbiMallocPtr)(size_t size) = NULL;
|
||||
void* (*zstbiReallocPtr)(void* ptr, size_t size) = NULL;
|
||||
void (*zstbiFreePtr)(void* ptr) = NULL;
|
||||
|
||||
#define STBI_MALLOC(size) zstbiMallocPtr(size)
|
||||
#define STBI_REALLOC(ptr, size) zstbiReallocPtr(ptr, size)
|
||||
#define STBI_FREE(ptr) zstbiFreePtr(ptr)
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
void* (*zstbirMallocPtr)(size_t size, void* context) = NULL;
|
||||
void (*zstbirFreePtr)(void* ptr, void* context) = NULL;
|
||||
|
||||
#define STBIR_MALLOC(size, context) zstbirMallocPtr(size, context)
|
||||
#define STBIR_FREE(ptr, context) zstbirFreePtr(ptr, context)
|
||||
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "stb_image_resize.h"
|
||||
|
||||
void* (*zstbiwMallocPtr)(size_t size) = NULL;
|
||||
void* (*zstbiwReallocPtr)(void* ptr, size_t size) = NULL;
|
||||
void (*zstbiwFreePtr)(void* ptr) = NULL;
|
||||
|
||||
#define STBIW_MALLOC(size) zstbiwMallocPtr(size)
|
||||
#define STBIW_REALLOC(ptr, size) zstbiwReallocPtr(ptr, size)
|
||||
#define STBIW_FREE(ptr) zstbiwFreePtr(ptr)
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
619
libs/zstbi/src/zstbi.zig
Normal file
619
libs/zstbi/src/zstbi.zig
Normal file
|
@ -0,0 +1,619 @@
|
|||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator) void {
|
||||
assert(mem_allocator == null);
|
||||
mem_allocator = allocator;
|
||||
mem_allocations = std.AutoHashMap(usize, usize).init(allocator);
|
||||
|
||||
// stb image
|
||||
zstbiMallocPtr = zstbiMalloc;
|
||||
zstbiReallocPtr = zstbiRealloc;
|
||||
zstbiFreePtr = zstbiFree;
|
||||
// stb image resize
|
||||
zstbirMallocPtr = zstbirMalloc;
|
||||
zstbirFreePtr = zstbirFree;
|
||||
// stb image write
|
||||
zstbiwMallocPtr = zstbiMalloc;
|
||||
zstbiwReallocPtr = zstbiRealloc;
|
||||
zstbiwFreePtr = zstbiFree;
|
||||
}
|
||||
|
||||
pub fn deinit() void {
|
||||
assert(mem_allocator != null);
|
||||
assert(mem_allocations.?.count() == 0);
|
||||
|
||||
setFlipVerticallyOnLoad(false);
|
||||
setFlipVerticallyOnWrite(false);
|
||||
|
||||
mem_allocations.?.deinit();
|
||||
mem_allocations = null;
|
||||
mem_allocator = null;
|
||||
}
|
||||
|
||||
pub const JpgWriteSettings = struct {
|
||||
quality: u32,
|
||||
};
|
||||
|
||||
pub const ImageWriteFormat = union(enum) {
|
||||
png,
|
||||
jpg: JpgWriteSettings,
|
||||
};
|
||||
|
||||
pub const ImageWriteError = error{
|
||||
CouldNotWriteImage,
|
||||
};
|
||||
|
||||
pub const Image = struct {
|
||||
data: []u8,
|
||||
width: u32,
|
||||
height: u32,
|
||||
num_components: u32,
|
||||
bytes_per_component: u32,
|
||||
bytes_per_row: u32,
|
||||
is_hdr: bool,
|
||||
|
||||
pub fn info(pathname: [:0]const u8) struct {
|
||||
is_supported: bool,
|
||||
width: u32,
|
||||
height: u32,
|
||||
num_components: u32,
|
||||
} {
|
||||
assert(mem_allocator != null);
|
||||
|
||||
var w: c_int = 0;
|
||||
var h: c_int = 0;
|
||||
var c: c_int = 0;
|
||||
const is_supported = stbi_info(pathname, &w, &h, &c);
|
||||
return .{
|
||||
.is_supported = if (is_supported == 1) true else false,
|
||||
.width = @as(u32, @intCast(w)),
|
||||
.height = @as(u32, @intCast(h)),
|
||||
.num_components = @as(u32, @intCast(c)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn loadFromFile(pathname: [:0]const u8, forced_num_components: u32) !Image {
|
||||
assert(mem_allocator != null);
|
||||
|
||||
var width: u32 = 0;
|
||||
var height: u32 = 0;
|
||||
var num_components: u32 = 0;
|
||||
var bytes_per_component: u32 = 0;
|
||||
var bytes_per_row: u32 = 0;
|
||||
var is_hdr = false;
|
||||
|
||||
const data = if (isHdr(pathname)) data: {
|
||||
var x: c_int = undefined;
|
||||
var y: c_int = undefined;
|
||||
var ch: c_int = undefined;
|
||||
const ptr = stbi_loadf(
|
||||
pathname,
|
||||
&x,
|
||||
&y,
|
||||
&ch,
|
||||
@as(c_int, @intCast(forced_num_components)),
|
||||
);
|
||||
if (ptr == null) return error.ImageInitFailed;
|
||||
|
||||
num_components = if (forced_num_components == 0) @as(u32, @intCast(ch)) else forced_num_components;
|
||||
width = @as(u32, @intCast(x));
|
||||
height = @as(u32, @intCast(y));
|
||||
bytes_per_component = 2;
|
||||
bytes_per_row = width * num_components * bytes_per_component;
|
||||
is_hdr = true;
|
||||
|
||||
// Convert each component from f32 to f16.
|
||||
var ptr_f16 = @as([*]f16, @ptrCast(ptr.?));
|
||||
const num = width * height * num_components;
|
||||
var i: u32 = 0;
|
||||
while (i < num) : (i += 1) {
|
||||
ptr_f16[i] = @as(f16, @floatCast(ptr.?[i]));
|
||||
}
|
||||
break :data @as([*]u8, @ptrCast(ptr_f16))[0 .. height * bytes_per_row];
|
||||
} else data: {
|
||||
var x: c_int = undefined;
|
||||
var y: c_int = undefined;
|
||||
var ch: c_int = undefined;
|
||||
const is_16bit = is16bit(pathname);
|
||||
const ptr = if (is_16bit) @as(?[*]u8, @ptrCast(stbi_load_16(
|
||||
pathname,
|
||||
&x,
|
||||
&y,
|
||||
&ch,
|
||||
@as(c_int, @intCast(forced_num_components)),
|
||||
))) else stbi_load(
|
||||
pathname,
|
||||
&x,
|
||||
&y,
|
||||
&ch,
|
||||
@as(c_int, @intCast(forced_num_components)),
|
||||
);
|
||||
if (ptr == null) return error.ImageInitFailed;
|
||||
|
||||
num_components = if (forced_num_components == 0) @as(u32, @intCast(ch)) else forced_num_components;
|
||||
width = @as(u32, @intCast(x));
|
||||
height = @as(u32, @intCast(y));
|
||||
bytes_per_component = if (is_16bit) 2 else 1;
|
||||
bytes_per_row = width * num_components * bytes_per_component;
|
||||
is_hdr = false;
|
||||
|
||||
break :data @as([*]u8, @ptrCast(ptr))[0 .. height * bytes_per_row];
|
||||
};
|
||||
|
||||
return Image{
|
||||
.data = data,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.num_components = num_components,
|
||||
.bytes_per_component = bytes_per_component,
|
||||
.bytes_per_row = bytes_per_row,
|
||||
.is_hdr = is_hdr,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn loadFromMemory(data: []const u8, forced_num_components: u32) !Image {
|
||||
assert(mem_allocator != null);
|
||||
|
||||
var width: u32 = 0;
|
||||
var height: u32 = 0;
|
||||
var num_components: u32 = 0;
|
||||
var bytes_per_component: u32 = 0;
|
||||
var bytes_per_row: u32 = 0;
|
||||
var is_hdr = false;
|
||||
|
||||
const image_data = if (isHdrFromMem(data)) data: {
|
||||
var x: c_int = undefined;
|
||||
var y: c_int = undefined;
|
||||
var ch: c_int = undefined;
|
||||
const ptr = stbi_loadf_from_memory(
|
||||
data.ptr,
|
||||
@as(c_int, @intCast(data.len)),
|
||||
&x,
|
||||
&y,
|
||||
&ch,
|
||||
@as(c_int, @intCast(forced_num_components)),
|
||||
);
|
||||
if (ptr == null) return error.ImageInitFailed;
|
||||
|
||||
num_components = if (forced_num_components == 0) @as(u32, @intCast(ch)) else forced_num_components;
|
||||
width = @as(u32, @intCast(x));
|
||||
height = @as(u32, @intCast(y));
|
||||
bytes_per_component = 2;
|
||||
bytes_per_row = width * num_components * bytes_per_component;
|
||||
is_hdr = true;
|
||||
|
||||
// Convert each component from f32 to f16.
|
||||
var ptr_f16 = @as([*]f16, @ptrCast(ptr.?));
|
||||
const num = width * height * num_components;
|
||||
var i: u32 = 0;
|
||||
while (i < num) : (i += 1) {
|
||||
ptr_f16[i] = @as(f16, @floatCast(ptr.?[i]));
|
||||
}
|
||||
break :data @as([*]u8, @ptrCast(ptr_f16))[0 .. height * bytes_per_row];
|
||||
} else data: {
|
||||
var x: c_int = undefined;
|
||||
var y: c_int = undefined;
|
||||
var ch: c_int = undefined;
|
||||
const ptr = stbi_load_from_memory(
|
||||
data.ptr,
|
||||
@as(c_int, @intCast(data.len)),
|
||||
&x,
|
||||
&y,
|
||||
&ch,
|
||||
@as(c_int, @intCast(forced_num_components)),
|
||||
);
|
||||
if (ptr == null) return error.ImageInitFailed;
|
||||
|
||||
num_components = if (forced_num_components == 0) @as(u32, @intCast(ch)) else forced_num_components;
|
||||
width = @as(u32, @intCast(x));
|
||||
height = @as(u32, @intCast(y));
|
||||
bytes_per_component = 1;
|
||||
bytes_per_row = width * num_components * bytes_per_component;
|
||||
|
||||
break :data @as([*]u8, @ptrCast(ptr))[0 .. height * bytes_per_row];
|
||||
};
|
||||
|
||||
return Image{
|
||||
.data = image_data,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.num_components = num_components,
|
||||
.bytes_per_component = bytes_per_component,
|
||||
.bytes_per_row = bytes_per_row,
|
||||
.is_hdr = is_hdr,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn createEmpty(width: u32, height: u32, num_components: u32, args: struct {
|
||||
bytes_per_component: u32 = 0,
|
||||
bytes_per_row: u32 = 0,
|
||||
}) !Image {
|
||||
assert(mem_allocator != null);
|
||||
|
||||
const bytes_per_component = if (args.bytes_per_component == 0) 1 else args.bytes_per_component;
|
||||
const bytes_per_row = if (args.bytes_per_row == 0)
|
||||
width * num_components * bytes_per_component
|
||||
else
|
||||
args.bytes_per_row;
|
||||
|
||||
const size = height * bytes_per_row;
|
||||
|
||||
const data = @as([*]u8, @ptrCast(zstbiMalloc(size)));
|
||||
@memset(data[0..size], 0);
|
||||
|
||||
return Image{
|
||||
.data = data[0..size],
|
||||
.width = width,
|
||||
.height = height,
|
||||
.num_components = num_components,
|
||||
.bytes_per_component = bytes_per_component,
|
||||
.bytes_per_row = bytes_per_row,
|
||||
.is_hdr = false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn resize(image: *const Image, new_width: u32, new_height: u32) Image {
|
||||
assert(mem_allocator != null);
|
||||
|
||||
// TODO: Add support for HDR images
|
||||
const new_bytes_per_row = new_width * image.num_components * image.bytes_per_component;
|
||||
const new_size = new_height * new_bytes_per_row;
|
||||
const new_data = @as([*]u8, @ptrCast(zstbiMalloc(new_size)));
|
||||
stbir_resize_uint8(
|
||||
image.data.ptr,
|
||||
@as(c_int, @intCast(image.width)),
|
||||
@as(c_int, @intCast(image.height)),
|
||||
0,
|
||||
new_data,
|
||||
@as(c_int, @intCast(new_width)),
|
||||
@as(c_int, @intCast(new_height)),
|
||||
0,
|
||||
@as(c_int, @intCast(image.num_components)),
|
||||
);
|
||||
return .{
|
||||
.data = new_data[0..new_size],
|
||||
.width = new_width,
|
||||
.height = new_height,
|
||||
.num_components = image.num_components,
|
||||
.bytes_per_component = image.bytes_per_component,
|
||||
.bytes_per_row = new_bytes_per_row,
|
||||
.is_hdr = image.is_hdr,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn writeToFile(
|
||||
image: Image,
|
||||
filename: [:0]const u8,
|
||||
image_format: ImageWriteFormat,
|
||||
) ImageWriteError!void {
|
||||
assert(mem_allocator != null);
|
||||
|
||||
const w = @as(c_int, @intCast(image.width));
|
||||
const h = @as(c_int, @intCast(image.height));
|
||||
const comp = @as(c_int, @intCast(image.num_components));
|
||||
const result = switch (image_format) {
|
||||
.png => stbi_write_png(filename.ptr, w, h, comp, image.data.ptr, 0),
|
||||
.jpg => |settings| stbi_write_jpg(
|
||||
filename.ptr,
|
||||
w,
|
||||
h,
|
||||
comp,
|
||||
image.data.ptr,
|
||||
@as(c_int, @intCast(settings.quality)),
|
||||
),
|
||||
};
|
||||
// if the result is 0 then it means an error occured (per stb image write docs)
|
||||
if (result == 0) {
|
||||
return ImageWriteError.CouldNotWriteImage;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn writeToFn(
|
||||
image: Image,
|
||||
write_fn: *const fn (ctx: ?*anyopaque, data: ?*anyopaque, size: c_int) callconv(.C) void,
|
||||
context: ?*anyopaque,
|
||||
image_format: ImageWriteFormat,
|
||||
) ImageWriteError!void {
|
||||
assert(mem_allocator != null);
|
||||
|
||||
const w = @as(c_int, @intCast(image.width));
|
||||
const h = @as(c_int, @intCast(image.height));
|
||||
const comp = @as(c_int, @intCast(image.num_components));
|
||||
const result = switch (image_format) {
|
||||
.png => stbi_write_png_to_func(write_fn, context, w, h, comp, image.data.ptr, 0),
|
||||
.jpg => |settings| stbi_write_jpg_to_func(
|
||||
write_fn,
|
||||
context,
|
||||
w,
|
||||
h,
|
||||
comp,
|
||||
image.data.ptr,
|
||||
@as(c_int, @intCast(settings.quality)),
|
||||
),
|
||||
};
|
||||
// if the result is 0 then it means an error occured (per stb image write docs)
|
||||
if (result == 0) {
|
||||
return ImageWriteError.CouldNotWriteImage;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(image: *Image) void {
|
||||
stbi_image_free(image.data.ptr);
|
||||
image.* = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/// `pub fn setHdrToLdrScale(scale: f32) void`
|
||||
pub const setHdrToLdrScale = stbi_hdr_to_ldr_scale;
|
||||
|
||||
/// `pub fn setHdrToLdrGamma(gamma: f32) void`
|
||||
pub const setHdrToLdrGamma = stbi_hdr_to_ldr_gamma;
|
||||
|
||||
/// `pub fn setLdrToHdrScale(scale: f32) void`
|
||||
pub const setLdrToHdrScale = stbi_ldr_to_hdr_scale;
|
||||
|
||||
/// `pub fn setLdrToHdrGamma(gamma: f32) void`
|
||||
pub const setLdrToHdrGamma = stbi_ldr_to_hdr_gamma;
|
||||
|
||||
pub fn isHdr(filename: [:0]const u8) bool {
|
||||
return stbi_is_hdr(filename) != 0;
|
||||
}
|
||||
|
||||
pub fn isHdrFromMem(buffer: []const u8) bool {
|
||||
return stbi_is_hdr_from_memory(buffer.ptr, @as(c_int, @intCast(buffer.len))) != 0;
|
||||
}
|
||||
|
||||
pub fn is16bit(filename: [:0]const u8) bool {
|
||||
return stbi_is_16_bit(filename) != 0;
|
||||
}
|
||||
|
||||
pub fn setFlipVerticallyOnLoad(should_flip: bool) void {
|
||||
stbi_set_flip_vertically_on_load(if (should_flip) 1 else 0);
|
||||
}
|
||||
|
||||
pub fn setFlipVerticallyOnWrite(should_flip: bool) void {
|
||||
stbi_flip_vertically_on_write(if (should_flip) 1 else 0);
|
||||
}
|
||||
|
||||
var mem_allocator: ?std.mem.Allocator = null;
|
||||
var mem_allocations: ?std.AutoHashMap(usize, usize) = null;
|
||||
var mem_mutex: std.Thread.Mutex = .{};
|
||||
const mem_alignment = 16;
|
||||
|
||||
extern var zstbiMallocPtr: ?*const fn (size: usize) callconv(.C) ?*anyopaque;
|
||||
extern var zstbiwMallocPtr: ?*const fn (size: usize) callconv(.C) ?*anyopaque;
|
||||
|
||||
fn zstbiMalloc(size: usize) callconv(.C) ?*anyopaque {
|
||||
mem_mutex.lock();
|
||||
defer mem_mutex.unlock();
|
||||
|
||||
const mem = mem_allocator.?.alignedAlloc(
|
||||
u8,
|
||||
mem_alignment,
|
||||
size,
|
||||
) catch @panic("zstbi: out of memory");
|
||||
|
||||
mem_allocations.?.put(@intFromPtr(mem.ptr), size) catch @panic("zstbi: out of memory");
|
||||
|
||||
return mem.ptr;
|
||||
}
|
||||
|
||||
extern var zstbiReallocPtr: ?*const fn (ptr: ?*anyopaque, size: usize) callconv(.C) ?*anyopaque;
|
||||
extern var zstbiwReallocPtr: ?*const fn (ptr: ?*anyopaque, size: usize) callconv(.C) ?*anyopaque;
|
||||
|
||||
fn zstbiRealloc(ptr: ?*anyopaque, size: usize) callconv(.C) ?*anyopaque {
|
||||
mem_mutex.lock();
|
||||
defer mem_mutex.unlock();
|
||||
|
||||
const old_size = if (ptr != null) mem_allocations.?.get(@intFromPtr(ptr.?)).? else 0;
|
||||
const old_mem = if (old_size > 0)
|
||||
@as([*]align(mem_alignment) u8, @ptrCast(@alignCast(ptr)))[0..old_size]
|
||||
else
|
||||
@as([*]align(mem_alignment) u8, undefined)[0..0];
|
||||
|
||||
const new_mem = mem_allocator.?.realloc(old_mem, size) catch @panic("zstbi: out of memory");
|
||||
|
||||
if (ptr != null) {
|
||||
const removed = mem_allocations.?.remove(@intFromPtr(ptr.?));
|
||||
std.debug.assert(removed);
|
||||
}
|
||||
|
||||
mem_allocations.?.put(@intFromPtr(new_mem.ptr), size) catch @panic("zstbi: out of memory");
|
||||
|
||||
return new_mem.ptr;
|
||||
}
|
||||
|
||||
extern var zstbiFreePtr: ?*const fn (maybe_ptr: ?*anyopaque) callconv(.C) void;
|
||||
extern var zstbiwFreePtr: ?*const fn (maybe_ptr: ?*anyopaque) callconv(.C) void;
|
||||
|
||||
fn zstbiFree(maybe_ptr: ?*anyopaque) callconv(.C) void {
|
||||
if (maybe_ptr) |ptr| {
|
||||
mem_mutex.lock();
|
||||
defer mem_mutex.unlock();
|
||||
|
||||
const size = mem_allocations.?.fetchRemove(@intFromPtr(ptr)).?.value;
|
||||
const mem = @as([*]align(mem_alignment) u8, @ptrCast(@alignCast(ptr)))[0..size];
|
||||
mem_allocator.?.free(mem);
|
||||
}
|
||||
}
|
||||
|
||||
extern var zstbirMallocPtr: ?*const fn (size: usize, maybe_context: ?*anyopaque) callconv(.C) ?*anyopaque;
|
||||
|
||||
fn zstbirMalloc(size: usize, _: ?*anyopaque) callconv(.C) ?*anyopaque {
|
||||
return zstbiMalloc(size);
|
||||
}
|
||||
|
||||
extern var zstbirFreePtr: ?*const fn (maybe_ptr: ?*anyopaque, maybe_context: ?*anyopaque) callconv(.C) void;
|
||||
|
||||
fn zstbirFree(maybe_ptr: ?*anyopaque, _: ?*anyopaque) callconv(.C) void {
|
||||
zstbiFree(maybe_ptr);
|
||||
}
|
||||
|
||||
extern fn stbi_info(filename: [*:0]const u8, x: *c_int, y: *c_int, comp: *c_int) c_int;
|
||||
|
||||
extern fn stbi_load(
|
||||
filename: [*:0]const u8,
|
||||
x: *c_int,
|
||||
y: *c_int,
|
||||
channels_in_file: *c_int,
|
||||
desired_channels: c_int,
|
||||
) ?[*]u8;
|
||||
|
||||
extern fn stbi_load_16(
|
||||
filename: [*:0]const u8,
|
||||
x: *c_int,
|
||||
y: *c_int,
|
||||
channels_in_file: *c_int,
|
||||
desired_channels: c_int,
|
||||
) ?[*]u16;
|
||||
|
||||
extern fn stbi_loadf(
|
||||
filename: [*:0]const u8,
|
||||
x: *c_int,
|
||||
y: *c_int,
|
||||
channels_in_file: *c_int,
|
||||
desired_channels: c_int,
|
||||
) ?[*]f32;
|
||||
|
||||
pub extern fn stbi_load_from_memory(
|
||||
buffer: [*]const u8,
|
||||
len: c_int,
|
||||
x: *c_int,
|
||||
y: *c_int,
|
||||
channels_in_file: *c_int,
|
||||
desired_channels: c_int,
|
||||
) ?[*]u8;
|
||||
|
||||
pub extern fn stbi_loadf_from_memory(
|
||||
buffer: [*]const u8,
|
||||
len: c_int,
|
||||
x: *c_int,
|
||||
y: *c_int,
|
||||
channels_in_file: *c_int,
|
||||
desired_channels: c_int,
|
||||
) ?[*]f32;
|
||||
|
||||
extern fn stbi_image_free(image_data: ?[*]u8) void;
|
||||
|
||||
extern fn stbi_hdr_to_ldr_scale(scale: f32) void;
|
||||
extern fn stbi_hdr_to_ldr_gamma(gamma: f32) void;
|
||||
extern fn stbi_ldr_to_hdr_scale(scale: f32) void;
|
||||
extern fn stbi_ldr_to_hdr_gamma(gamma: f32) void;
|
||||
|
||||
extern fn stbi_is_16_bit(filename: [*:0]const u8) c_int;
|
||||
extern fn stbi_is_hdr(filename: [*:0]const u8) c_int;
|
||||
extern fn stbi_is_hdr_from_memory(buffer: [*]const u8, len: c_int) c_int;
|
||||
|
||||
extern fn stbi_set_flip_vertically_on_load(flag_true_if_should_flip: c_int) void;
|
||||
extern fn stbi_flip_vertically_on_write(flag: c_int) void; // flag is non-zero to flip data vertically
|
||||
|
||||
extern fn stbir_resize_uint8(
|
||||
input_pixels: [*]const u8,
|
||||
input_w: c_int,
|
||||
input_h: c_int,
|
||||
input_stride_in_bytes: c_int,
|
||||
output_pixels: [*]u8,
|
||||
output_w: c_int,
|
||||
output_h: c_int,
|
||||
output_stride_in_bytes: c_int,
|
||||
num_channels: c_int,
|
||||
) void;
|
||||
|
||||
extern fn stbi_write_jpg(
|
||||
filename: [*:0]const u8,
|
||||
w: c_int,
|
||||
h: c_int,
|
||||
comp: c_int,
|
||||
data: [*]const u8,
|
||||
quality: c_int,
|
||||
) c_int;
|
||||
|
||||
extern fn stbi_write_png(
|
||||
filename: [*:0]const u8,
|
||||
w: c_int,
|
||||
h: c_int,
|
||||
comp: c_int,
|
||||
data: [*]const u8,
|
||||
stride_in_bytes: c_int,
|
||||
) c_int;
|
||||
|
||||
extern fn stbi_write_png_to_func(
|
||||
func: *const fn (?*anyopaque, ?*anyopaque, c_int) callconv(.C) void,
|
||||
context: ?*anyopaque,
|
||||
w: c_int,
|
||||
h: c_int,
|
||||
comp: c_int,
|
||||
data: [*]const u8,
|
||||
stride_in_bytes: c_int,
|
||||
) c_int;
|
||||
|
||||
extern fn stbi_write_jpg_to_func(
|
||||
func: *const fn (?*anyopaque, ?*anyopaque, c_int) callconv(.C) void,
|
||||
context: ?*anyopaque,
|
||||
x: c_int,
|
||||
y: c_int,
|
||||
comp: c_int,
|
||||
data: [*]const u8,
|
||||
quality: c_int,
|
||||
) c_int;
|
||||
|
||||
test "zstbi basic" {
|
||||
init(testing.allocator);
|
||||
defer deinit();
|
||||
|
||||
var im1 = try Image.createEmpty(8, 6, 4, .{});
|
||||
defer im1.deinit();
|
||||
|
||||
try testing.expect(im1.width == 8);
|
||||
try testing.expect(im1.height == 6);
|
||||
try testing.expect(im1.num_components == 4);
|
||||
}
|
||||
|
||||
test "zstbi resize" {
|
||||
init(testing.allocator);
|
||||
defer deinit();
|
||||
|
||||
var im1 = try Image.createEmpty(32, 32, 4, .{});
|
||||
defer im1.deinit();
|
||||
|
||||
var im2 = im1.resize(8, 6);
|
||||
defer im2.deinit();
|
||||
|
||||
try testing.expect(im2.width == 8);
|
||||
try testing.expect(im2.height == 6);
|
||||
try testing.expect(im2.num_components == 4);
|
||||
}
|
||||
|
||||
test "zstbi write and load file" {
|
||||
init(testing.allocator);
|
||||
defer deinit();
|
||||
|
||||
const pth = try std.fs.selfExeDirPathAlloc(testing.allocator);
|
||||
defer testing.allocator.free(pth);
|
||||
try std.posix.chdir(pth);
|
||||
|
||||
var img = try Image.createEmpty(8, 6, 4, .{});
|
||||
defer img.deinit();
|
||||
|
||||
try img.writeToFile("test_img.png", ImageWriteFormat.png);
|
||||
try img.writeToFile("test_img.jpg", .{ .jpg = .{ .quality = 80 } });
|
||||
|
||||
var img_png = try Image.loadFromFile("test_img.png", 0);
|
||||
defer img_png.deinit();
|
||||
|
||||
try testing.expect(img_png.width == img.width);
|
||||
try testing.expect(img_png.height == img.height);
|
||||
try testing.expect(img_png.num_components == img.num_components);
|
||||
|
||||
var img_jpg = try Image.loadFromFile("test_img.jpg", 0);
|
||||
defer img_jpg.deinit();
|
||||
|
||||
try testing.expect(img_jpg.width == img.width);
|
||||
try testing.expect(img_jpg.height == img.height);
|
||||
try testing.expect(img_jpg.num_components == 3); // RGB JPEG
|
||||
|
||||
try std.fs.cwd().deleteFile("test_img.png");
|
||||
try std.fs.cwd().deleteFile("test_img.jpg");
|
||||
}
|
1
profile.json
Normal file
1
profile.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -6,11 +6,12 @@ const Utilities = @import("utilities.zig");
|
|||
const Vertex = Utilities.Vertex;
|
||||
const Device = @import("vulkan_renderer.zig").Device;
|
||||
const Instance = @import("vulkan_renderer.zig").Instance;
|
||||
const UboModel = @import("vulkan_renderer.zig").UboModel;
|
||||
const Model = @import("vulkan_renderer.zig").Model;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
ubo_model: UboModel,
|
||||
ubo_model: Model,
|
||||
tex_id: u32,
|
||||
|
||||
vertex_count: u32,
|
||||
vertex_buffer: vk.Buffer,
|
||||
|
@ -34,6 +35,7 @@ pub fn new(
|
|||
transfer_command_pool: vk.CommandPool,
|
||||
vertices: []const Vertex,
|
||||
indices: []const u32,
|
||||
tex_id: u32,
|
||||
allocator: std.mem.Allocator,
|
||||
) !Self {
|
||||
var self: Self = undefined;
|
||||
|
@ -50,6 +52,7 @@ pub fn new(
|
|||
try self.createIndexBuffer(transfer_queue, transfer_command_pool, indices);
|
||||
|
||||
self.ubo_model = .{ .model = zm.identity() };
|
||||
self.tex_id = tex_id;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -122,7 +125,6 @@ fn createVertexBuffer(
|
|||
staging_buffer,
|
||||
self.vertex_buffer,
|
||||
buffer_size,
|
||||
self.allocator,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -178,6 +180,5 @@ fn createIndexBuffer(
|
|||
staging_buffer,
|
||||
self.index_buffer,
|
||||
buffer_size,
|
||||
self.allocator,
|
||||
);
|
||||
}
|
||||
|
|
194
src/MeshModel.zig
Normal file
194
src/MeshModel.zig
Normal file
|
@ -0,0 +1,194 @@
|
|||
const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
const zm = @import("zmath");
|
||||
const ai = @import("assimp.zig").c;
|
||||
|
||||
const Mesh = @import("Mesh.zig");
|
||||
const Device = @import("vulkan_renderer.zig").Device;
|
||||
const Instance = @import("vulkan_renderer.zig").Instance;
|
||||
const Vertex = @import("utilities.zig").Vertex;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
|
||||
mesh_list: std.ArrayList(Mesh),
|
||||
model: zm.Mat,
|
||||
|
||||
pub fn new(allocator: std.mem.Allocator, mesh_list: std.ArrayList(Mesh)) Self {
|
||||
var new_mesh_model: Self = undefined;
|
||||
|
||||
new_mesh_model.allocator = allocator;
|
||||
new_mesh_model.mesh_list = mesh_list;
|
||||
new_mesh_model.model = zm.identity();
|
||||
|
||||
return new_mesh_model;
|
||||
}
|
||||
|
||||
pub fn destroy(self: *Self) void {
|
||||
for (0..self.mesh_list.items.len) |i| {
|
||||
self.mesh_list.items[i].destroyBuffers();
|
||||
}
|
||||
self.mesh_list.deinit();
|
||||
}
|
||||
|
||||
pub fn getMesh(self: Self, idx: usize) !Mesh {
|
||||
if (idx >= self.mesh_list.len - 1) {
|
||||
return error.MeshIndexOutOfBounds;
|
||||
}
|
||||
|
||||
return self.mesh_list.items[idx];
|
||||
}
|
||||
|
||||
pub fn loadMaterials(allocator: std.mem.Allocator, scene: *const ai.aiScene) !std.ArrayList(?[]const u8) {
|
||||
// Create 1:1 sized list of textures
|
||||
var texture_list = try std.ArrayList(?[]const u8).initCapacity(allocator, scene.mNumMaterials);
|
||||
|
||||
// Go through each material and copy its texture file name (if it exists)
|
||||
for (0..scene.mNumMaterials) |i| {
|
||||
// Get the material
|
||||
const material = scene.mMaterials[i];
|
||||
|
||||
// Initialise the texture to empty string (will be replaced if the texture exists)
|
||||
// try texture_list.append("");
|
||||
|
||||
// Check for diffuse texture (standard detail texture)
|
||||
if (ai.aiGetMaterialTextureCount(material, ai.aiTextureType_DIFFUSE) != 0) {
|
||||
// Get the path of the texture file
|
||||
var path: ai.aiString = undefined;
|
||||
if (ai.aiGetMaterialTexture(
|
||||
material,
|
||||
ai.aiTextureType_DIFFUSE,
|
||||
0,
|
||||
&path,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
) == ai.AI_SUCCESS) {
|
||||
// Cut of any directory information already present
|
||||
var it = std.mem.splitBackwardsAny(u8, &path.data, "\\/");
|
||||
if (it.next()) |filename| {
|
||||
texture_list.appendAssumeCapacity(try allocator.dupe(u8, filename));
|
||||
}
|
||||
} else {
|
||||
texture_list.appendAssumeCapacity(null);
|
||||
}
|
||||
} else {
|
||||
texture_list.appendAssumeCapacity(null);
|
||||
}
|
||||
}
|
||||
|
||||
return texture_list;
|
||||
}
|
||||
|
||||
pub fn loadNode(
|
||||
allocator: std.mem.Allocator,
|
||||
instance: Instance,
|
||||
pdev: vk.PhysicalDevice,
|
||||
device: Device,
|
||||
transfer_queue: vk.Queue,
|
||||
transfer_command_pool: vk.CommandPool,
|
||||
node: *const ai.aiNode,
|
||||
scene: *const ai.aiScene,
|
||||
mat_to_tex: []u32,
|
||||
) !std.ArrayList(Mesh) {
|
||||
var mesh_list = std.ArrayList(Mesh).init(allocator);
|
||||
|
||||
// Go through each mesh at this node and create it, then add it to our mesh list
|
||||
for (0..node.mNumMeshes) |i| {
|
||||
// Load mesh here
|
||||
try mesh_list.append(try loadMesh(
|
||||
allocator,
|
||||
instance,
|
||||
pdev,
|
||||
device,
|
||||
transfer_queue,
|
||||
transfer_command_pool,
|
||||
scene.mMeshes[node.mMeshes[i]],
|
||||
mat_to_tex,
|
||||
));
|
||||
}
|
||||
|
||||
// Go through each node attached to this node and load it, then append their meshes to this node's mesh list
|
||||
for (0..node.mNumChildren) |i| {
|
||||
var new_list = try loadNode(
|
||||
allocator,
|
||||
instance,
|
||||
pdev,
|
||||
device,
|
||||
transfer_queue,
|
||||
transfer_command_pool,
|
||||
node.mChildren[i],
|
||||
scene,
|
||||
mat_to_tex,
|
||||
);
|
||||
defer new_list.deinit();
|
||||
|
||||
try mesh_list.appendSlice(new_list.items[0..]);
|
||||
}
|
||||
|
||||
return mesh_list;
|
||||
}
|
||||
|
||||
pub fn loadMesh(
|
||||
allocator: std.mem.Allocator,
|
||||
instance: Instance,
|
||||
pdev: vk.PhysicalDevice,
|
||||
device: Device,
|
||||
transfer_queue: vk.Queue,
|
||||
transfer_command_pool: vk.CommandPool,
|
||||
mesh: *const ai.aiMesh,
|
||||
mat_to_tex: []u32,
|
||||
) !Mesh {
|
||||
var vertices = try std.ArrayList(Vertex).initCapacity(allocator, mesh.mNumVertices);
|
||||
var indices = std.ArrayList(u32).init(allocator);
|
||||
defer vertices.deinit();
|
||||
defer indices.deinit();
|
||||
|
||||
// Go through each vertex and copy it across to our vertices
|
||||
for (0..mesh.mNumVertices) |i| {
|
||||
var vertex: Vertex = undefined;
|
||||
|
||||
// Set position
|
||||
vertex.pos = .{ mesh.mVertices[i].x, mesh.mVertices[i].y, mesh.mVertices[i].z };
|
||||
|
||||
// Set texture coords (if they exist)
|
||||
if (mesh.mTextureCoords[0] != null) {
|
||||
vertex.tex = .{ mesh.mTextureCoords[0][i].x, mesh.mTextureCoords[0][i].y };
|
||||
} else {
|
||||
vertex.tex = .{ 0.0, 0.0 };
|
||||
}
|
||||
|
||||
// Set colour (just use white for now)
|
||||
vertex.col = .{ 1.0, 1.0, 1.0 };
|
||||
|
||||
// vertices.items[i] = vertex;
|
||||
vertices.appendAssumeCapacity(vertex);
|
||||
}
|
||||
|
||||
// Iterate over indices through faces and copy across
|
||||
for (0..mesh.mNumFaces) |i| {
|
||||
// Get a face
|
||||
const face = mesh.mFaces[i];
|
||||
|
||||
// Go through face's indices and add to list
|
||||
for (0..face.mNumIndices) |j| {
|
||||
try indices.append(face.mIndices[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return try Mesh.new(
|
||||
instance,
|
||||
pdev,
|
||||
device,
|
||||
transfer_queue,
|
||||
transfer_command_pool,
|
||||
vertices.items,
|
||||
indices.items,
|
||||
mat_to_tex[mesh.mMaterialIndex],
|
||||
allocator,
|
||||
);
|
||||
}
|
9
src/assimp.zig
Normal file
9
src/assimp.zig
Normal file
|
@ -0,0 +1,9 @@
|
|||
pub const c = @cImport({
|
||||
@cInclude("assimp/cimport.h");
|
||||
@cInclude("assimp/scene.h");
|
||||
@cInclude("assimp/postprocess.h");
|
||||
});
|
||||
|
||||
// pub fn importFile(path: [:0]const u8, flags: c_uint) *const c.aiScene {
|
||||
// return c.aiImportFile(path.ptr, flags);
|
||||
// }
|
97
src/main.zig
97
src/main.zig
|
@ -6,6 +6,52 @@ const zm = @import("zmath");
|
|||
const VulkanRenderer = @import("vulkan_renderer.zig").VulkanRenderer;
|
||||
const Vector3 = @import("utilities.zig").Vector3;
|
||||
|
||||
// 100 fps
|
||||
const TARGET_MS_F32: f32 = 16.0;
|
||||
|
||||
const Delta = struct {
|
||||
current_time: u64 = 0,
|
||||
last_time: u64 = 0,
|
||||
|
||||
delta_ms: u64 = 0,
|
||||
delta_f32: f32 = 0.0,
|
||||
|
||||
delay_amount: u32 = 0,
|
||||
|
||||
perf_frequency: f64,
|
||||
|
||||
_counter: u32 = 0,
|
||||
|
||||
pub fn new() Delta {
|
||||
return .{
|
||||
.perf_frequency = @as(f64, @floatFromInt(sdl.getPerformanceFrequency())),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn start(self: *Delta) void {
|
||||
self.last_time = sdl.getPerformanceCounter();
|
||||
}
|
||||
|
||||
pub fn tick(self: *Delta) void {
|
||||
self.current_time = sdl.getPerformanceCounter();
|
||||
self.delta_ms = self.current_time - self.last_time;
|
||||
|
||||
const delta_f64 = @as(f64, @floatFromInt(self.delta_ms)) / (self.perf_frequency * 1000.0);
|
||||
self.delta_f32 = @as(f32, @floatCast(delta_f64));
|
||||
|
||||
self.delay_amount = @as(u32, @intFromFloat(@floor(TARGET_MS_F32 - self.delta_f32)));
|
||||
|
||||
// Limit the output to the terminal
|
||||
if (self._counter % 100 == 0) {
|
||||
const fps = self.perf_frequency / @as(f64, @floatFromInt(self.delta_ms));
|
||||
std.debug.print("ms/f: {d}\tFPS: {d}\n", .{ delta_f64 * 1000.0, fps });
|
||||
}
|
||||
|
||||
self.last_time = self.current_time;
|
||||
self._counter += 1;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
const window = try initWindow();
|
||||
defer sdl.quit();
|
||||
|
@ -19,10 +65,13 @@ pub fn main() !void {
|
|||
var vulkan_renderer = try VulkanRenderer.init(window, allocator);
|
||||
defer vulkan_renderer.deinit();
|
||||
|
||||
var delta = Delta.new();
|
||||
delta.start();
|
||||
|
||||
var angle: f32 = 0.0;
|
||||
var now: u64 = sdl.getPerformanceCounter();
|
||||
var last: u64 = 0;
|
||||
var delta_time: f32 = 0.0;
|
||||
const move_speed: f32 = 1000;
|
||||
|
||||
const model_handle = try vulkan_renderer.createMeshModel("tescoPiwo.obj");
|
||||
|
||||
mainLoop: while (true) {
|
||||
while (sdl.pollEvent()) |ev| {
|
||||
|
@ -37,29 +86,41 @@ pub fn main() !void {
|
|||
}
|
||||
}
|
||||
|
||||
last = now;
|
||||
now = sdl.getPerformanceCounter();
|
||||
delta_time = @as(f32, @floatFromInt(now - last)) * 1000.0 / @as(f32, @floatFromInt(now));
|
||||
const keystate = sdl.getKeyboardState();
|
||||
if (keystate.isPressed(sdl.Scancode.left_shift)) {
|
||||
const move = zm.translation(0.0, -move_speed * delta.delta_f32, 0.0);
|
||||
vulkan_renderer.updateCamera(move);
|
||||
} else if (keystate.isPressed(sdl.Scancode.left_control)) {
|
||||
const move = zm.translation(0.0, move_speed * delta.delta_f32, 0.0);
|
||||
vulkan_renderer.updateCamera(move);
|
||||
} else if (keystate.isPressed(sdl.Scancode.w)) {
|
||||
const move = zm.translation(0.0, 0.0, move_speed * delta.delta_f32);
|
||||
vulkan_renderer.updateCamera(move);
|
||||
} else if (keystate.isPressed(sdl.Scancode.s)) {
|
||||
const move = zm.translation(0.0, 0.0, -move_speed * delta.delta_f32);
|
||||
vulkan_renderer.updateCamera(move);
|
||||
} else if (keystate.isPressed(sdl.Scancode.a)) {
|
||||
const move = zm.translation(move_speed * delta.delta_f32, 0.0, 0.0);
|
||||
vulkan_renderer.updateCamera(move);
|
||||
} else if (keystate.isPressed(sdl.Scancode.d)) {
|
||||
const move = zm.translation(-move_speed * delta.delta_f32, 0.0, 0.0);
|
||||
vulkan_renderer.updateCamera(move);
|
||||
}
|
||||
|
||||
angle += 10.0 * delta_time;
|
||||
delta.tick();
|
||||
|
||||
angle += 200.0 * delta.delta_f32;
|
||||
|
||||
if (angle > 360.0) {
|
||||
angle -= 360.0;
|
||||
}
|
||||
|
||||
var first_model = zm.identity();
|
||||
var second_model = zm.identity();
|
||||
|
||||
first_model = zm.mul(first_model, zm.rotationZ(angle));
|
||||
first_model = zm.mul(first_model, zm.translation(-2.0, 0.0, -5.0));
|
||||
|
||||
second_model = zm.mul(second_model, zm.rotationZ(-angle * 2));
|
||||
second_model = zm.mul(second_model, zm.translation(2.0, 0.0, -5.0));
|
||||
|
||||
try vulkan_renderer.updateModel(0, first_model);
|
||||
try vulkan_renderer.updateModel(1, second_model);
|
||||
const rotate = zm.mul(zm.identity(), zm.rotationY(angle));
|
||||
try vulkan_renderer.updateModel(model_handle, rotate);
|
||||
|
||||
try vulkan_renderer.draw();
|
||||
|
||||
sdl.delay(delta.delay_amount);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
22
src/shaders/second.frag
Normal file
22
src/shaders/second.frag
Normal file
|
@ -0,0 +1,22 @@
|
|||
#version 450
|
||||
|
||||
// Colour output from subpass 1
|
||||
layout(input_attachment_index = 0, binding = 0) uniform subpassInput inputColour;
|
||||
// Depth output from subpass 1
|
||||
layout(input_attachment_index = 1, binding = 1) uniform subpassInput inputDepth;
|
||||
|
||||
layout(location = 0) out vec4 colour;
|
||||
|
||||
void main() {
|
||||
int xHalf = 800 / 2;
|
||||
if (gl_FragCoord.x > xHalf) {
|
||||
float lowerBound = 0.98;
|
||||
float upperBound = 1;
|
||||
|
||||
float depth = subpassLoad(inputDepth).r;
|
||||
float depthColourScaled = 1.0f - ((depth - lowerBound) / (upperBound - lowerBound));
|
||||
colour = vec4(subpassLoad(inputColour).rgb * depthColourScaled, 1.0f);
|
||||
} else {
|
||||
colour = subpassLoad(inputColour).rgba;
|
||||
}
|
||||
}
|
12
src/shaders/second.vert
Normal file
12
src/shaders/second.vert
Normal file
|
@ -0,0 +1,12 @@
|
|||
#version 450
|
||||
|
||||
// Array for triangle that fills screen
|
||||
vec2 positions[3] = vec2[](
|
||||
vec2(3.0, -1.0),
|
||||
vec2(-1.0, -1.0),
|
||||
vec2(-1.0, 3.0)
|
||||
);
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 fragCol;
|
||||
layout(location = 1) in vec2 fragTex;
|
||||
|
||||
// Final output output (must also have location)
|
||||
layout(location = 0) out vec4 outColour;
|
||||
|
||||
layout(set = 1, binding = 0) uniform sampler2D textureSampler;
|
||||
|
||||
void main() {
|
||||
outColour = vec4(fragCol, 1.0);
|
||||
outColour = texture(textureSampler, fragTex);
|
||||
}
|
||||
|
|
|
@ -2,19 +2,22 @@
|
|||
|
||||
layout(location = 0) in vec3 pos;
|
||||
layout(location = 1) in vec3 col;
|
||||
layout(location = 2) in vec2 tex;
|
||||
|
||||
layout(binding = 0) uniform UboViewProjection {
|
||||
layout(location = 0) out vec3 fragCol;
|
||||
layout(location = 1) out vec2 fragTex;
|
||||
|
||||
layout(set = 0, binding = 0) uniform UboViewProjection {
|
||||
mat4 projection;
|
||||
mat4 view;
|
||||
} uboViewProjection;
|
||||
|
||||
layout(binding = 1) uniform UboModel {
|
||||
layout(push_constant) uniform PushModel {
|
||||
mat4 model;
|
||||
} uboModel;
|
||||
|
||||
layout(location = 0) out vec3 fragCol;
|
||||
} pushModel;
|
||||
|
||||
void main() {
|
||||
gl_Position = uboViewProjection.projection * uboViewProjection.view * uboModel.model * vec4(pos, 1.0);
|
||||
gl_Position = uboViewProjection.projection * uboViewProjection.view * pushModel.model * vec4(pos, 1.0);
|
||||
fragCol = col;
|
||||
fragTex = tex;
|
||||
}
|
||||
|
|
13
src/string_utils.zig
Normal file
13
src/string_utils.zig
Normal file
|
@ -0,0 +1,13 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub const StringError = error{ConcatError};
|
||||
|
||||
/// Concatenates two strings together using `std.mem.concat()`
|
||||
pub fn concat(str_1: []const u8, str_2: []const u8, allocator: std.mem.Allocator) StringError![:0]const u8 {
|
||||
const path_concat = [2][]const u8{ str_1, str_2 };
|
||||
|
||||
return std.mem.concatWithSentinel(allocator, u8, &path_concat, 0) catch |e| {
|
||||
std.log.err("[{s}] Failed to concatenate the following strings: '{s}' and '{s}'\n", .{ @errorName(e), str_1, str_2 });
|
||||
return StringError.ConcatError;
|
||||
};
|
||||
}
|
|
@ -8,12 +8,13 @@ const CommandBuffer = @import("vulkan_renderer.zig").CommandBuffer;
|
|||
pub const device_extensions = [_][*:0]const u8{vk.extensions.khr_swapchain.name};
|
||||
|
||||
pub const Vector3 = @Vector(3, f32);
|
||||
pub const Vector2 = @Vector(2, f32);
|
||||
|
||||
// Vertex data representation
|
||||
pub const Vertex = struct {
|
||||
// Vertex position (x, y, z)
|
||||
pos: Vector3,
|
||||
col: Vector3,
|
||||
pos: Vector3, // Vertex position (x, y, z)
|
||||
col: Vector3, // Vertex colour (r, g, b)
|
||||
tex: Vector2, // Texture coords (u, v)
|
||||
};
|
||||
|
||||
pub const QueueFamilyIndices = struct {
|
||||
|
@ -36,7 +37,7 @@ pub const SwapchainImage = struct {
|
|||
image_view: vk.ImageView,
|
||||
};
|
||||
|
||||
fn findMemoryTypeIndex(pdev: vk.PhysicalDevice, instance: Instance, allowed_types: u32, properties: vk.MemoryPropertyFlags) u32 {
|
||||
pub fn findMemoryTypeIndex(pdev: vk.PhysicalDevice, instance: Instance, allowed_types: u32, properties: vk.MemoryPropertyFlags) u32 {
|
||||
// Get properties of physical device memory
|
||||
const memory_properties = instance.getPhysicalDeviceMemoryProperties(pdev);
|
||||
const mem_type_count = memory_properties.memory_type_count;
|
||||
|
@ -96,31 +97,20 @@ pub fn createBuffer(
|
|||
try device.bindBufferMemory(buffer.*, buffer_memory.*, 0);
|
||||
}
|
||||
|
||||
pub fn copyBuffer(
|
||||
device: Device,
|
||||
transfer_queue: vk.Queue,
|
||||
transfer_command_pool: vk.CommandPool,
|
||||
src_buffer: vk.Buffer,
|
||||
dst_buffer: vk.Buffer,
|
||||
buffer_size: vk.DeviceSize,
|
||||
allocator: std.mem.Allocator,
|
||||
) !void {
|
||||
fn beginCommandBuffer(device: Device, command_pool: vk.CommandPool) !CommandBuffer {
|
||||
// Command buffer to hold transfer commands
|
||||
const transfer_command_buffer_handle = try allocator.create(vk.CommandBuffer);
|
||||
defer allocator.destroy(transfer_command_buffer_handle);
|
||||
// Free temporary buffer back to pool
|
||||
defer device.freeCommandBuffers(transfer_command_pool, 1, @ptrCast(transfer_command_buffer_handle));
|
||||
var command_buffer_handle: vk.CommandBuffer = undefined;
|
||||
|
||||
// Command buffer details
|
||||
const alloc_info: vk.CommandBufferAllocateInfo = .{
|
||||
.command_pool = transfer_command_pool,
|
||||
.command_pool = command_pool,
|
||||
.level = .primary,
|
||||
.command_buffer_count = 1,
|
||||
};
|
||||
|
||||
// Allocate command buffer from pool
|
||||
try device.allocateCommandBuffers(&alloc_info, @ptrCast(transfer_command_buffer_handle));
|
||||
const transfer_command_buffer = CommandBuffer.init(transfer_command_buffer_handle.*, device.wrapper);
|
||||
try device.allocateCommandBuffers(&alloc_info, @ptrCast(&command_buffer_handle));
|
||||
const command_buffer = CommandBuffer.init(command_buffer_handle, device.wrapper);
|
||||
|
||||
// Information to begin the command buffer record
|
||||
const begin_info: vk.CommandBufferBeginInfo = .{
|
||||
|
@ -128,7 +118,39 @@ pub fn copyBuffer(
|
|||
};
|
||||
|
||||
// Begin recording transfer commands
|
||||
try transfer_command_buffer.beginCommandBuffer(&begin_info);
|
||||
try command_buffer.beginCommandBuffer(&begin_info);
|
||||
|
||||
return command_buffer;
|
||||
}
|
||||
|
||||
fn endAndSubmitCommandBuffer(device: Device, command_buffer: CommandBuffer, command_pool: vk.CommandPool, queue: vk.Queue) !void {
|
||||
// End commands
|
||||
try command_buffer.endCommandBuffer();
|
||||
|
||||
// Queue submission information
|
||||
const submit_info: vk.SubmitInfo = .{
|
||||
.command_buffer_count = 1,
|
||||
.p_command_buffers = @ptrCast(&command_buffer.handle),
|
||||
};
|
||||
|
||||
// Submit transfer command to transfer queue and wait until it finishes
|
||||
try device.queueSubmit(queue, 1, @ptrCast(&submit_info), .null_handle);
|
||||
try device.queueWaitIdle(queue);
|
||||
|
||||
// Free temporary buffer back to pool
|
||||
device.freeCommandBuffers(command_pool, 1, @ptrCast(&command_buffer.handle));
|
||||
}
|
||||
|
||||
pub fn copyBuffer(
|
||||
device: Device,
|
||||
transfer_queue: vk.Queue,
|
||||
transfer_command_pool: vk.CommandPool,
|
||||
src_buffer: vk.Buffer,
|
||||
dst_buffer: vk.Buffer,
|
||||
buffer_size: vk.DeviceSize,
|
||||
) !void {
|
||||
// Create buffer
|
||||
const transfer_command_buffer = try beginCommandBuffer(device, transfer_command_pool);
|
||||
|
||||
// Region of data to copy from and to
|
||||
const buffer_copy_region: vk.BufferCopy = .{
|
||||
|
@ -140,16 +162,96 @@ pub fn copyBuffer(
|
|||
// Command to copy src buffer to dst buffer
|
||||
transfer_command_buffer.copyBuffer(src_buffer, dst_buffer, 1, @ptrCast(&buffer_copy_region));
|
||||
|
||||
// End commands
|
||||
try transfer_command_buffer.endCommandBuffer();
|
||||
// Command to copy src buffer to dst buffer
|
||||
try endAndSubmitCommandBuffer(device, transfer_command_buffer, transfer_command_pool, transfer_queue);
|
||||
}
|
||||
|
||||
// Queue submission information
|
||||
const submit_info: vk.SubmitInfo = .{
|
||||
.command_buffer_count = 1,
|
||||
.p_command_buffers = @ptrCast(&transfer_command_buffer.handle),
|
||||
pub fn copyImageBuffer(
|
||||
device: Device,
|
||||
transfer_queue: vk.Queue,
|
||||
transfer_command_pool: vk.CommandPool,
|
||||
src_buffer: vk.Buffer,
|
||||
image: vk.Image,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) !void {
|
||||
const transfer_command_buffer = try beginCommandBuffer(device, transfer_command_pool);
|
||||
|
||||
const image_region: vk.BufferImageCopy = .{
|
||||
.buffer_offset = 0, // Offset into data
|
||||
.buffer_row_length = 0, // Row length of data to calculate data spacing
|
||||
.buffer_image_height = 0, // Image height to calculate data spacing
|
||||
.image_subresource = .{
|
||||
.aspect_mask = .{ .color_bit = true }, // Which aspect of image to copy
|
||||
.mip_level = 0, // Mipmap level to copy
|
||||
.base_array_layer = 0, // Starting array layer (if array)
|
||||
.layer_count = 1, // Number of layers of copy starting at base_array_layer
|
||||
},
|
||||
.image_offset = .{ .x = 0, .y = 0, .z = 0 }, // Offset to image (as opposed to raw data buffer offset)
|
||||
.image_extent = .{ .width = width, .height = height, .depth = 1 }, // Size of the region to copy as x, y, z values
|
||||
};
|
||||
|
||||
// Submit transfer command to transfer queue and wait until it finishes
|
||||
try device.queueSubmit(transfer_queue, 1, @ptrCast(&submit_info), .null_handle);
|
||||
try device.queueWaitIdle(transfer_queue);
|
||||
transfer_command_buffer.copyBufferToImage(src_buffer, image, .transfer_dst_optimal, 1, @ptrCast(&image_region));
|
||||
|
||||
try endAndSubmitCommandBuffer(device, transfer_command_buffer, transfer_command_pool, transfer_queue);
|
||||
}
|
||||
|
||||
pub fn transitionImageLayout(
|
||||
device: Device,
|
||||
queue: vk.Queue,
|
||||
command_pool: vk.CommandPool,
|
||||
image: vk.Image,
|
||||
old_layout: vk.ImageLayout,
|
||||
new_layout: vk.ImageLayout,
|
||||
) !void {
|
||||
const command_buffer = try beginCommandBuffer(device, command_pool);
|
||||
|
||||
var image_memory_barrier: vk.ImageMemoryBarrier = .{
|
||||
.old_layout = old_layout, // Layout to transition from
|
||||
.new_layout = new_layout, // Layout to transition to
|
||||
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED, // Queue family to transition from
|
||||
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED, // Queue family to transition to
|
||||
.image = image, // Image being accessed and modified as part of barrier
|
||||
.subresource_range = .{
|
||||
.aspect_mask = .{ .color_bit = true }, // Aspect of image being altered
|
||||
.base_mip_level = 0, // First mip level to start alterations on
|
||||
.level_count = 1, // Number of mipmap levels to alter starting from base mipmap level
|
||||
.base_array_layer = 0, // First layer to start alterations on
|
||||
.layer_count = 1, // Number of layers to alter starting from base array layer
|
||||
},
|
||||
.src_access_mask = .{}, // Memory access stage transition must happen after
|
||||
.dst_access_mask = .{}, // Memory access stage transition must happen before
|
||||
};
|
||||
|
||||
var src_stage: vk.PipelineStageFlags = .{};
|
||||
var dst_stage: vk.PipelineStageFlags = .{};
|
||||
|
||||
// If transitioning from new image to image ready to receive data
|
||||
if (old_layout == vk.ImageLayout.undefined and new_layout == vk.ImageLayout.transfer_dst_optimal) {
|
||||
image_memory_barrier.dst_access_mask.transfer_write_bit = true;
|
||||
|
||||
src_stage.top_of_pipe_bit = true;
|
||||
dst_stage.transfer_bit = true;
|
||||
} else if (old_layout == vk.ImageLayout.transfer_dst_optimal and new_layout == vk.ImageLayout.shader_read_only_optimal) {
|
||||
// If transitioning from transfer destination to shader readable
|
||||
image_memory_barrier.src_access_mask.transfer_write_bit = true;
|
||||
image_memory_barrier.dst_access_mask.shader_read_bit = true;
|
||||
|
||||
src_stage.transfer_bit = true;
|
||||
dst_stage.fragment_shader_bit = true;
|
||||
}
|
||||
|
||||
command_buffer.pipelineBarrier(
|
||||
src_stage, // Pipeline stages (match to src and dst access mask)
|
||||
dst_stage,
|
||||
.{}, // Dependency flags
|
||||
0, // Memory barrier count
|
||||
null, // Memory barrier data
|
||||
0, // Buffer memory barrier count
|
||||
null, // Buffer memory barrier data
|
||||
1, // Image memory barrier count
|
||||
@ptrCast(&image_memory_barrier), // Image memory barrier data
|
||||
);
|
||||
|
||||
try endAndSubmitCommandBuffer(device, command_buffer, command_pool, queue);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue