This commit is contained in:
Peter Li 2025-04-12 17:21:53 -07:00
parent fc6b0a154a
commit 653f61e8d9
211 changed files with 35980 additions and 36276 deletions

View File

@ -13,12 +13,12 @@ const engineDepList = [_][]const u8{
"assets", "assets",
"audio", "audio",
"core", "core",
"graphics",
"papyrus", "papyrus",
"platform", "platform",
"physics", "physics",
"ui", // "graphics",
"vkImgui", // "ui",
// "vkImgui",
}; };
const BuildSystem = @This(); const BuildSystem = @This();
@ -110,20 +110,64 @@ pub fn addProgram(self: *BuildSystem, opts: AddProgramOptions) *std.Build.Step.C
mod.addImport("Backlog", self.nw_mod); mod.addImport("Backlog", self.nw_mod);
exe.root_module.addOptions("BacklogOptions", self.options); exe.root_module.addOptions("BacklogOptions", self.options);
self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/triangle_mesh.vert"), "triangle_mesh_vert"); // I want to generate definitions from the spirv-reflect-tool during pre-build.
self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/default_lit.frag"), "default_lit"); //
// shaders will now be part of content, not code. However. .zig code definitions will be generated
// from content via the build.zig script.
//
// heres some thoughts:
//
// -Dupdate_shaders=true
//
// -Dupdate_shaders basically adds a run step to the build process 'python', 'tools/scripts/cook-shaders.py'
//
// 1. ensure spirv-reflect is compiled.
// 2. shadercross cooker generates all shader outputs - specifically spv files. they are output to content/_shaders/
// - search paths for shaders:
// - content/shaders/**
// - engine/<module names>/shaders/**
// - shaders must have a unique name across the entire project, naming scheme should be <module>.shadername.<stage>.hlsl
// 3. spirv-cross --reflect is called on each shader, updating the content/_shaders/defs/shader-name.json folder with up to date .json files
//
// final tree
//
// engine/
// - ui/
// - shaders/
// - papyrus.rect.vert.hlsl
// content/
// - _shaders/
// - def/
// papyrus.rect.vert.json
// - msl/
// papyrus.rect.vert.msl
// - spv/
// papyrus.rect.vert.spv
// - dxil/
// papyrus.rect.vert.dxil
//
//
// During build:
// 1. spirv-reflect is called on each json in each folder and .zig shader interfaces added to the executable as a global import.
// 2. if -Dupdate_shaders is not
//
// At any time:
// asset-cooker will cook shaders and place them under content/_shaders/<msl|dxil|dxil>/<shader-name>.<msl|spv|dxil>
self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/debug.vert"), "debug_vert"); // self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/triangle_mesh.vert"), "triangle_mesh_vert");
self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/debug.frag"), "debug_frag"); // self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/default_lit.frag"), "default_lit");
self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/skybox/skybox.vert"), "skybox_vert"); // self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/debug.vert"), "debug_vert");
self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/skybox/skybox.frag"), "skybox_frag"); // self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/debug.frag"), "debug_frag");
self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/ui/shaders/PapyrusRect.vert"), "papyrus_vk_vert"); // self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/skybox/skybox.vert"), "skybox_vert");
self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/ui/shaders/PapyrusRect.frag"), "papyrus_vk_frag"); // self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/graphics/shaders/skybox/skybox.frag"), "skybox_frag");
self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/ui/shaders/FontSDF.vert"), "FontSDF_vert"); // self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/ui/shaders/PapyrusRect.vert"), "papyrus_vk_vert");
self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/ui/shaders/FontSDF.frag"), "FontSDF_frag"); // self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/ui/shaders/PapyrusRect.frag"), "papyrus_vk_frag");
// self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/ui/shaders/FontSDF.vert"), "FontSDF_vert");
// self.spirvReflect.addShaderInstallRef(exe, self.nw_builder.path("engine/ui/shaders/FontSDF.frag"), "FontSDF_frag");
b.getInstallStep().dependOn(self.nw_builder.getInstallStep()); b.getInstallStep().dependOn(self.nw_builder.getInstallStep());

View File

@ -1,16 +1,17 @@
.{ .{
.name = "Backlog", .name = .Backlog,
.version = "0.0.0", .version = "0.0.0",
.dependencies = .{ .dependencies = .{
.assets = .{ .path = "engine/assets" }, .assets = .{ .path = "engine/assets" },
.audio = .{ .path = "engine/audio" }, .audio = .{ .path = "engine/audio" },
.core = .{ .path = "engine/core" }, .core = .{ .path = "engine/core" },
.graphics = .{ .path = "engine/graphics" },
.papyrus = .{ .path = "engine/papyrus" }, .papyrus = .{ .path = "engine/papyrus" },
.physics = .{ .path = "engine/physics" }, .physics = .{ .path = "engine/physics" },
.platform = .{ .path = "engine/platform" }, .platform = .{ .path = "engine/platform" },
.ui = .{ .path = "engine/ui" },
.vkImgui = .{ .path = "engine/vkImgui" }, // .graphics = .{ .path = "engine/graphics" },
// .ui = .{ .path = "engine/ui" },
// .vkImgui = .{ .path = "engine/vkImgui" },
.SpirvReflect = .{ .path = "lib/spirv-reflect-zig" }, .SpirvReflect = .{ .path = "lib/spirv-reflect-zig" },
.ozz = .{ .path = "lib/ozz" }, .ozz = .{ .path = "lib/ozz" },
@ -18,4 +19,5 @@
.paths = .{ .paths = .{
"", "",
}, },
.fingerprint = 0xcf9bab998abe37e3
} }

View File

@ -1,21 +1,21 @@
.{ .{
.name = "graphics", .name = "graphics",
.version = "0.0.0", .version = "0.0.0",
.dependencies = .{ .dependencies = .{
// //
.vulkan = .{ .path = "../../lib/vulkan" }, .vulkan = .{ .path = "../../lib/vulkan" },
.vma = .{ .path = "../../lib/vma" }, .vma = .{ .path = "../../lib/vma" },
.glfw3 = .{ .path = "../../lib/glfw3" }, .glfw3 = .{ .path = "../../lib/glfw3" },
.cgltf = .{ .path = "../../lib/cgltf" }, .cgltf = .{ .path = "../../lib/cgltf" },
.objLoader = .{ .path = "../../lib/objLoader" }, .objLoader = .{ .path = "../../lib/objLoader" },
.SpirvReflect = .{ .path = "../../lib/spirv-reflect-zig" }, .SpirvReflect = .{ .path = "../../lib/spirv-reflect-zig" },
.ozz = .{ .path = "../../lib/ozz" }, .ozz = .{ .path = "../../lib/ozz" },
// core // core
.core = .{ .path = "../core" }, .core = .{ .path = "../core" },
.assets = .{ .path = "../assets" }, .assets = .{ .path = "../assets" },
.platform = .{ .path = "../platform" }, .platform = .{ .path = "../platform" },
}, },
.paths = .{ .paths = .{
"", "",
}, },
} }

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,32 +1,32 @@
//glsl version 4.5 //glsl version 4.5
#version 450 #version 450
layout (location = 0) in vec3 in_color; layout (location = 0) in vec3 in_color;
layout (location = 1) in vec2 texCoord; layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 worldPosition; layout (location = 2) in vec3 worldPosition;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
layout (set = 0, binding = 0) uniform CameraBuffer{ layout (set = 0, binding = 0) uniform CameraBuffer{
mat4 view; mat4 view;
mat4 proj; mat4 proj;
mat4 viewproj; mat4 viewproj;
vec4 position; vec4 position;
} cameraData; } cameraData;
layout(set = 0, binding = 1) uniform SceneData{ layout(set = 0, binding = 1) uniform SceneData{
vec4 fogColor; // w is for exponent vec4 fogColor; // w is for exponent
vec4 fogDistances; //x for min, y for max, zw unused. vec4 fogDistances; //x for min, y for max, zw unused.
vec4 ambientColor; vec4 ambientColor;
vec4 sunlightDirection; //w for sun power vec4 sunlightDirection; //w for sun power
vec4 sunlightColor; vec4 sunlightColor;
} sceneData; } sceneData;
void main() void main()
{ {
vec3 color = in_color.rgb; vec3 color = in_color.rgb;
float cameraDist = length(cameraData.position.xyz - worldPosition); float cameraDist = length(cameraData.position.xyz - worldPosition);
float opacity = (1.0) - (cameraDist / 300); float opacity = (1.0) - (cameraDist / 300);
outFragColor = vec4(color, opacity * 1.0); outFragColor = vec4(color, opacity * 1.0);
} }

View File

@ -1,40 +1,40 @@
#version 460 #version 460
layout (location = 0) in vec3 vPosition; layout (location = 0) in vec3 vPosition;
layout (location = 1) in vec3 vNormal; layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec4 vColor; layout (location = 2) in vec4 vColor;
layout (location = 3) in vec2 vTexCoord; layout (location = 3) in vec2 vTexCoord;
layout (location = 0) out vec3 outColor; layout (location = 0) out vec3 outColor;
layout (location = 1) out vec2 texCoord; layout (location = 1) out vec2 texCoord;
layout (location = 2) out vec3 worldPosition; layout (location = 2) out vec3 worldPosition;
layout (set = 0, binding = 0) uniform CameraBuffer{ layout (set = 0, binding = 0) uniform CameraBuffer{
mat4 view; mat4 view;
mat4 proj; mat4 proj;
mat4 viewproj; mat4 viewproj;
vec4 position; vec4 position;
} cameraData; } cameraData;
// size: 16 x 4 + 3 x 4 = 76 => 128 bytes per object per alignment // size: 16 x 4 + 3 x 4 = 76 => 128 bytes per object per alignment
struct ObjectData { struct ObjectData {
mat4 model; mat4 model;
vec4 color; vec4 color;
}; };
layout(std140, set = 1, binding = 0) readonly buffer ObjectBuffer{ layout(std140, set = 1, binding = 0) readonly buffer ObjectBuffer{
ObjectData objects[]; ObjectData objects[];
} objectBuffer; } objectBuffer;
void main() void main()
{ {
ObjectData object = objectBuffer.objects[gl_BaseInstance]; ObjectData object = objectBuffer.objects[gl_BaseInstance];
mat4 modelMatrix = object.model; mat4 modelMatrix = object.model;
mat4 final = (cameraData.viewproj * modelMatrix); mat4 final = (cameraData.viewproj * modelMatrix);
vec4 position = final * vec4(vPosition, 1.0f); vec4 position = final * vec4(vPosition, 1.0f);
gl_Position = position; gl_Position = position;
outColor = object.color.xyz; outColor = object.color.xyz;
texCoord = vTexCoord; texCoord = vTexCoord;
vec4 modelPos = modelMatrix * vec4(vPosition, 1.0f); vec4 modelPos = modelMatrix * vec4(vPosition, 1.0f);
worldPosition = modelPos.xyz; worldPosition = modelPos.xyz;
} }

View File

@ -1,47 +1,47 @@
//glsl version 4.5 //glsl version 4.5
#version 450 #version 450
#extension GL_EXT_nonuniform_qualifier : require #extension GL_EXT_nonuniform_qualifier : require
layout (location = 0) in vec3 in_color; layout (location = 0) in vec3 in_color;
layout (location = 1) in vec2 texCoord; layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 worldPosition; layout (location = 2) in vec3 worldPosition;
layout (location = 3) flat in uint textureId; layout (location = 3) flat in uint textureId;
layout (location = 4) flat in uint baseInstance; layout (location = 4) flat in uint baseInstance;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
#include "globalSet.glsl" #include "globalSet.glsl"
#include "sharedSsbo.glsl" #include "sharedSsbo.glsl"
void main() void main()
{ {
// outFragColor = vec4(in_color + 0.25 * sceneData.ambientColor.xyz,1.0f); // outFragColor = vec4(in_color + 0.25 * sceneData.ambientColor.xyz,1.0f);
// outFragColor = vec4(texCoord.x, texCoord.y, 0.5f, 1.0f); // outFragColor = vec4(texCoord.x, texCoord.y, 0.5f, 1.0f);
// vec4 color = texture(tex1, texCoord).xyzw; // vec4 color = texture(tex1, texCoord).xyzw;
vec4 color = texture(gTex[textureId], texCoord).xyzw; vec4 color = texture(gTex[textureId], texCoord).xyzw;
if(color.w < 0.05f) if(color.w < 0.05f)
{ {
discard; discard;
} }
float cameraDist = length(cameraData.position.xyz - worldPosition); float cameraDist = length(cameraData.position.xyz - worldPosition);
float opacity = clamp((1.f) - (clamp(cameraDist - 300, 0, 300) / 300.f), 0.f, 1.f); float opacity = clamp((1.f) - (clamp(cameraDist - 300, 0, 300) / 300.f), 0.f, 1.f);
//float opacity = 1.0; //float opacity = 1.0;
if(opacity < 0.05f) if(opacity < 0.05f)
{ {
discard; discard;
} }
// outFragColor = vec4(mix(sceneData.fogColor.xyz, color.xyz, opacity), color.w); // outFragColor = vec4(mix(sceneData.fogColor.xyz, color.xyz, opacity), color.w);
outFragColor = vec4(color.xyz, opacity); outFragColor = vec4(color.xyz, opacity);
//vec3 mixed = mix(normalize(vec3(0.5, 0.3, 0.2)) * 3, vec3(0.2, 0.2, 1) * 3, texCoord.y * 2); //vec3 mixed = mix(normalize(vec3(0.5, 0.3, 0.2)) * 3, vec3(0.2, 0.2, 1) * 3, texCoord.y * 2);
//outFragColor = vec4(color.xyz, 1.0f); //outFragColor = vec4(color.xyz, 1.0f);
//outFragColor = vec4(0.0, 1.0, 0.0, 1.0f); //outFragColor = vec4(0.0, 1.0, 0.0, 1.0f);
} }

View File

@ -1,18 +1,18 @@
layout (set = 0, binding = 0) uniform CameraBuffer{ layout (set = 0, binding = 0) uniform CameraBuffer{
mat4 view; mat4 view;
mat4 proj; mat4 proj;
mat4 viewproj; mat4 viewproj;
mat4 viewprojAlt; mat4 viewprojAlt;
vec4 position; vec4 position;
} cameraData; } cameraData;
layout(set = 0, binding = 1) uniform SceneData{ layout(set = 0, binding = 1) uniform SceneData{
vec4 fogColor; // w is for exponent vec4 fogColor; // w is for exponent
vec4 fogDistances; //x for min, y for max, zw unused. vec4 fogDistances; //x for min, y for max, zw unused.
vec4 ambientColor; vec4 ambientColor;
vec4 sunlightDirection; //w for sun power vec4 sunlightDirection; //w for sun power
vec4 sunlightColor; vec4 sunlightColor;
} sceneData; } sceneData;
layout(set = 0, binding = 2) uniform sampler2D[] gTex; layout(set = 0, binding = 2) uniform sampler2D[] gTex;

View File

@ -1,25 +1,25 @@
struct ObjectData { struct ObjectData {
mat4 model; mat4 model;
uint textureId; uint textureId;
int animation; // this is the index offset of the first matrix in the animation finals buffer. int animation; // this is the index offset of the first matrix in the animation finals buffer.
uint flags0; uint flags0;
// packed flags0 flags; // packed flags0 flags;
// [0,0]: alwaysInFront // [0,0]: alwaysInFront
// [1,1]: useAltCamera // [1,1]: useAltCamera
uint pad1; uint pad1;
}; };
layout(std140, set = 1, binding = 0) readonly buffer ObjectBuffer{ layout(std140, set = 1, binding = 0) readonly buffer ObjectBuffer{
ObjectData objects[]; ObjectData objects[];
} objectBuffer; } objectBuffer;
uint flag0_AlwaysInFront(uint flags) uint flag0_AlwaysInFront(uint flags)
{ {
return flags & 0x1; return flags & 0x1;
} }
uint flag0_useAltFov(uint flags) uint flag0_useAltFov(uint flags)
{ {
return (flags >> 1) & 0x1; return (flags >> 1) & 0x1;
} }

View File

@ -1,3 +1,3 @@
layout(std140, set = 1, binding = 1) readonly buffer BoneBuffer{ layout(std140, set = 1, binding = 1) readonly buffer BoneBuffer{
mat4 finals[]; mat4 finals[];
} animationBuffer; } animationBuffer;

View File

@ -1,15 +1,15 @@
#version 450 #version 450
#include "../globalSet.glsl" #include "../globalSet.glsl"
layout(set = 1, binding = 0) uniform samplerCube cubemap; layout(set = 1, binding = 0) uniform samplerCube cubemap;
layout (location = 0) in vec3 inUVW; layout (location = 0) in vec3 inUVW;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
void main() void main()
{ {
outFragColor = texture(cubemap, inUVW); outFragColor = texture(cubemap, inUVW);
} }

View File

@ -1,17 +1,17 @@
#version 450 #version 450
#include "../vertexInput.glsl" #include "../vertexInput.glsl"
#include "../globalSet.glsl" #include "../globalSet.glsl"
layout (location = 0) out vec3 outUVW; layout (location = 0) out vec3 outUVW;
void main() void main()
{ {
outUVW = vPosition; outUVW = vPosition;
// Convert cubemap coordinates into Vulkan coordinate space // Convert cubemap coordinates into Vulkan coordinate space
// Remove translation from view matrix // Remove translation from view matrix
mat4 viewMat = mat4(mat3(cameraData.view)); mat4 viewMat = mat4(mat3(cameraData.view));
gl_Position = cameraData.proj * viewMat * vec4(vPosition.xyz, 1.0); gl_Position = cameraData.proj * viewMat * vec4(vPosition.xyz, 1.0);
} }

View File

@ -1,66 +1,66 @@
#version 460 #version 460
#include "vertexInput.glsl" #include "vertexInput.glsl"
layout (location = 0) out vec3 outColor; layout (location = 0) out vec3 outColor;
layout (location = 1) out vec2 texCoord; layout (location = 1) out vec2 texCoord;
layout (location = 2) out vec3 worldPosition; layout (location = 2) out vec3 worldPosition;
layout (location = 3) flat out uint textureId; layout (location = 3) flat out uint textureId;
layout (location = 4) flat out uint baseInstance; layout (location = 4) flat out uint baseInstance;
#include "globalSet.glsl" #include "globalSet.glsl"
#include "sharedSsbo.glsl" #include "sharedSsbo.glsl"
#include "skeletalBuffers.glsl" #include "skeletalBuffers.glsl"
void main() void main()
{ {
vec3 vertexPos = vec3(0.0); vec3 vertexPos = vec3(0.0);
int animation = objectBuffer.objects[gl_BaseInstance].animation; int animation = objectBuffer.objects[gl_BaseInstance].animation;
if(animation == -1) if(animation == -1)
{ {
vertexPos = vPosition; vertexPos = vPosition;
} }
else else
{ {
uint animation = objectBuffer.objects[gl_BaseInstance].animation; uint animation = objectBuffer.objects[gl_BaseInstance].animation;
for(int i = 0; i < 4; i += 1) for(int i = 0; i < 4; i += 1)
{ {
uint boneIndex = bones[i]; uint boneIndex = bones[i];
float weight = float(weights[i]) / 255; float weight = float(weights[i]) / 255;
// this will depend on ozz's finals format // this will depend on ozz's finals format
mat4 boneTransform = animationBuffer.finals[animation + boneIndex]; mat4 boneTransform = animationBuffer.finals[animation + boneIndex];
vertexPos += weight * ( boneTransform * vec4(vPosition, 1.0) ).xyz; vertexPos += weight * ( boneTransform * vec4(vPosition, 1.0) ).xyz;
} }
} }
mat4 modelMatrix = objectBuffer.objects[gl_BaseInstance].model; mat4 modelMatrix = objectBuffer.objects[gl_BaseInstance].model;
mat4 final; mat4 final;
if(flag0_useAltFov(objectBuffer.objects[gl_BaseInstance].flags0) == 1) if(flag0_useAltFov(objectBuffer.objects[gl_BaseInstance].flags0) == 1)
{ {
final = (cameraData.viewprojAlt * modelMatrix); final = (cameraData.viewprojAlt * modelMatrix);
} }
else else
{ {
final = (cameraData.viewproj * modelMatrix); final = (cameraData.viewproj * modelMatrix);
} }
vec4 position = final * vec4(vertexPos, 1.0f); vec4 position = final * vec4(vertexPos, 1.0f);
if( flag0_AlwaysInFront(objectBuffer.objects[gl_BaseInstance].flags0) == 1) if( flag0_AlwaysInFront(objectBuffer.objects[gl_BaseInstance].flags0) == 1)
{ {
position.z *= 0.0001; position.z *= 0.0001;
} }
baseInstance = gl_BaseInstance; baseInstance = gl_BaseInstance;
gl_Position = position; gl_Position = position;
textureId = objectBuffer.objects[gl_BaseInstance].textureId; textureId = objectBuffer.objects[gl_BaseInstance].textureId;
outColor = vec3(vColor.x, vColor.y, vColor.z); outColor = vec3(vColor.x, vColor.y, vColor.z);
texCoord = vTexCoord; texCoord = vTexCoord;
worldPosition = (modelMatrix * vec4(0,0,0,1)).xyz; worldPosition = (modelMatrix * vec4(0,0,0,1)).xyz;
} }

View File

@ -1,7 +1,7 @@
#extension GL_EXT_shader_explicit_arithmetic_types_int8 : enable #extension GL_EXT_shader_explicit_arithmetic_types_int8 : enable
layout (location = 0) in vec3 vPosition; layout (location = 0) in vec3 vPosition;
layout (location = 1) in vec3 vNormal; layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec4 vColor; layout (location = 2) in vec4 vColor;
layout (location = 3) in vec2 vTexCoord; layout (location = 3) in vec2 vTexCoord;
layout (location = 4) in u8vec4 bones; layout (location = 4) in u8vec4 bones;
layout (location = 5) in u8vec4 weights; layout (location = 5) in u8vec4 weights;

View File

@ -1,32 +1,32 @@
pixels: []u8, pixels: []u8,
extent: core.Vector2i, extent: core.Vector2i,
const std = @import("std"); const std = @import("std");
const core = @import("core"); const core = @import("core");
const colors = core.colors; const colors = core.colors;
pub fn init(allocator: std.mem.Allocator, extent: core.Vector2i) !@This() { pub fn init(allocator: std.mem.Allocator, extent: core.Vector2i) !@This() {
return .{ return .{
.pixels = try allocator.alignedAlloc(u8, 8, @intCast(extent.x * extent.y * 4)), .pixels = try allocator.alignedAlloc(u8, 8, @intCast(extent.x * extent.y * 4)),
.extent = extent, .extent = extent,
}; };
} }
pub fn clear(self: *@This(), clearColor: colors.ColorRGBA8) void { pub fn clear(self: *@This(), clearColor: colors.ColorRGBA8) void {
var as32: []u32 = undefined; var as32: []u32 = undefined;
as32.len = self.pixels.len / 4; as32.len = self.pixels.len / 4;
as32.ptr = @alignCast(@ptrCast(self.pixels.ptr)); as32.ptr = @alignCast(@ptrCast(self.pixels.ptr));
@memset(as32, @as(u32, @bitCast(clearColor))); @memset(as32, @as(u32, @bitCast(clearColor)));
} }
pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void { pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
allocator.free(self.pixels); allocator.free(self.pixels);
} }
pub inline fn getPixel(self: *@This(), position: core.Vector2i) *colors.ColorRGBA8 { pub inline fn getPixel(self: *@This(), position: core.Vector2i) *colors.ColorRGBA8 {
const offset = position.x * position.y * 4; const offset = position.x * position.y * 4;
const r: *u8 = &self.pixels[@intCast(offset)]; const r: *u8 = &self.pixels[@intCast(offset)];
return @as(*colors.ColorRGBA8, @alignCast(@ptrCast(r))); return @as(*colors.ColorRGBA8, @alignCast(@ptrCast(r)));
} }

View File

@ -1,232 +1,232 @@
pub const AnimResolverRef = core.Reference(AnimResolverInterface); pub const AnimResolverRef = core.Reference(AnimResolverInterface);
pub const AnimResolverInterface = core.MakeInterface("AnimResolverVTable", struct { pub const AnimResolverInterface = core.MakeInterface("AnimResolverVTable", struct {
// this tick function should evaluate the current state of the resolver // this tick function should evaluate the current state of the resolver
// and then update the animator's finals[] matrix list. // and then update the animator's finals[] matrix list.
resolve: *const fn (*anyopaque, f64, *Animator) void, resolve: *const fn (*anyopaque, f64, *Animator) void,
onSkeletonSet: ?*const fn (*anyopaque, *Animator) void = null, onSkeletonSet: ?*const fn (*anyopaque, *Animator) void = null,
create: *const fn (std.mem.Allocator) core.EngineDataEventError!*anyopaque, create: *const fn (std.mem.Allocator) core.EngineDataEventError!*anyopaque,
destroy: *const fn (*anyopaque) void, destroy: *const fn (*anyopaque) void,
pub fn Implement(comptime TargetType: type) @This() { pub fn Implement(comptime TargetType: type) @This() {
const Wrap = struct { const Wrap = struct {
pub fn create(allocator: std.mem.Allocator) core.EngineDataEventError!*anyopaque { pub fn create(allocator: std.mem.Allocator) core.EngineDataEventError!*anyopaque {
const new = TargetType.create(allocator) catch return core.EngineDataEventError.BadInit; const new = TargetType.create(allocator) catch return core.EngineDataEventError.BadInit;
return @ptrCast(new); return @ptrCast(new);
} }
pub fn destroy(p: *anyopaque) void { pub fn destroy(p: *anyopaque) void {
const ptr: *TargetType = @ptrCast(@alignCast(p)); const ptr: *TargetType = @ptrCast(@alignCast(p));
ptr.destroy(); ptr.destroy();
} }
pub fn onSkeletonSet(p: *anyopaque, a: *Animator) void { pub fn onSkeletonSet(p: *anyopaque, a: *Animator) void {
const ptr: *TargetType = @ptrCast(@alignCast(p)); const ptr: *TargetType = @ptrCast(@alignCast(p));
ptr.onSkeletonSet(a) catch unreachable; ptr.onSkeletonSet(a) catch unreachable;
} }
pub fn resolve(p: *anyopaque, dt: f64, a: *Animator) void { pub fn resolve(p: *anyopaque, dt: f64, a: *Animator) void {
const ptr: *TargetType = @ptrCast(@alignCast(p)); const ptr: *TargetType = @ptrCast(@alignCast(p));
ptr.resolve(dt, a) catch unreachable; ptr.resolve(dt, a) catch unreachable;
} }
}; };
return .{ return .{
.destroy = Wrap.destroy, .destroy = Wrap.destroy,
.create = Wrap.create, .create = Wrap.create,
.resolve = Wrap.resolve, .resolve = Wrap.resolve,
}; };
} }
}); });
pub const AnimSampler = struct { pub const AnimSampler = struct {
name: ?core.Name = null, name: ?core.Name = null,
track: ?*AnimationTrack = null, track: ?*AnimationTrack = null,
playbackRate: f32 = 1.0, playbackRate: f32 = 1.0,
time: f32 = 0.0, time: f32 = 0.0,
outputLocals: std.ArrayListUnmanaged(ozz.SoaTransform) = .{}, outputLocals: std.ArrayListUnmanaged(ozz.SoaTransform) = .{},
// other features // other features
// paused: bool = false, // paused: bool = false,
pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void { pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
self.outputLocals.deinit(allocator); self.outputLocals.deinit(allocator);
} }
pub fn getOutput(self: *@This()) []ozz.SoaTransform { pub fn getOutput(self: *@This()) []ozz.SoaTransform {
return self.outputLocals.items; return self.outputLocals.items;
} }
pub fn sampleAndAdvance(self: *@This(), allocator: std.mem.Allocator, dt: f64, animator: *Animator) void { pub fn sampleAndAdvance(self: *@This(), allocator: std.mem.Allocator, dt: f64, animator: *Animator) void {
self.sample(allocator, animator); self.sample(allocator, animator);
self.advance(dt); self.advance(dt);
} }
pub fn advance(self: *@This(), dt: f64) void { pub fn advance(self: *@This(), dt: f64) void {
if (self.track == null) { if (self.track == null) {
return; return;
} }
FloatHelpers.updateTrackTime(&self.time, dt, self.playbackRate, self.track.?.endTime); FloatHelpers.updateTrackTime(&self.time, dt, self.playbackRate, self.track.?.endTime);
} }
pub fn setName(self: *@This(), name: core.Name) void { pub fn setName(self: *@This(), name: core.Name) void {
self.name = name; self.name = name;
self.track = null; self.track = null;
} }
pub fn sample(self: *@This(), allocator: std.mem.Allocator, animator: *Animator) void { pub fn sample(self: *@This(), allocator: std.mem.Allocator, animator: *Animator) void {
if (self.name == null) { if (self.name == null) {
return; return;
} }
if (self.track == null) { if (self.track == null) {
self.track = animation_system.gAnimationSys.animTracks.get(self.name.?.handle()); self.track = animation_system.gAnimationSys.animTracks.get(self.name.?.handle());
} }
self.outputLocals.resize(allocator, animator.jointLength) catch return; self.outputLocals.resize(allocator, animator.jointLength) catch return;
if (self.track) |track| { if (self.track) |track| {
if (track.endTime < 0.01) { if (track.endTime < 0.01) {
return; return;
} }
animator.sampleAnimation(self.time, track, self.outputLocals.items); animator.sampleAnimation(self.time, track, self.outputLocals.items);
} }
} }
}; };
pub const BlenderList = struct { pub const BlenderList = struct {
backing: std.mem.Allocator, backing: std.mem.Allocator,
arena: std.heap.ArenaAllocator, arena: std.heap.ArenaAllocator,
jobLayers: std.ArrayListUnmanaged(ozz.Layer) = .{}, jobLayers: std.ArrayListUnmanaged(ozz.Layer) = .{},
jobLayersAdditive: std.ArrayListUnmanaged(ozz.Layer) = .{}, jobLayersAdditive: std.ArrayListUnmanaged(ozz.Layer) = .{},
useAdditive: bool = false, useAdditive: bool = false,
threshold: f32 = 0.01, threshold: f32 = 0.01,
jointLength: usize = 0, jointLength: usize = 0,
blendingJob: ozz.BlendingJob = .{}, blendingJob: ozz.BlendingJob = .{},
pub fn create(backingAllocator: std.mem.Allocator) !*@This() { pub fn create(backingAllocator: std.mem.Allocator) !*@This() {
const self = try backingAllocator.create(@This()); const self = try backingAllocator.create(@This());
self.* = .{ self.* = .{
.backing = backingAllocator, .backing = backingAllocator,
.arena = std.heap.ArenaAllocator.init(backingAllocator), .arena = std.heap.ArenaAllocator.init(backingAllocator),
}; };
return self; return self;
} }
pub fn destroy(self: *@This()) void { pub fn destroy(self: *@This()) void {
self.arena.deinit(); self.arena.deinit();
self.backing.destroy(self); self.backing.destroy(self);
} }
pub fn updateRestPose(self: *@This(), animator: *Animator) !void { pub fn updateRestPose(self: *@This(), animator: *Animator) !void {
if (animator.skeleton) |skeleton| { if (animator.skeleton) |skeleton| {
self.jointLength = skeleton.sk.numJoints(); self.jointLength = skeleton.sk.numJoints();
self.blendingJob.rest_pose = skeleton.sk.getRestPoseModel(); self.blendingJob.rest_pose = skeleton.sk.getRestPoseModel();
} }
} }
pub fn clearLayers(self: *@This()) void { pub fn clearLayers(self: *@This()) void {
self.jobLayersAdditive.clearRetainingCapacity(); self.jobLayersAdditive.clearRetainingCapacity();
self.jobLayers.clearRetainingCapacity(); self.jobLayers.clearRetainingCapacity();
} }
pub fn addLayer(self: *@This(), transform: []ozz.SoaTransform, weight: f32, settings: anytype) void { pub fn addLayer(self: *@This(), transform: []ozz.SoaTransform, weight: f32, settings: anytype) void {
const layer = self.jobLayers.addOne(self.arena.allocator()) catch unreachable; const layer = self.jobLayers.addOne(self.arena.allocator()) catch unreachable;
layer.* = .{ layer.* = .{
.weight = weight, .weight = weight,
.transform = ozz.makeSpan(transform), .transform = ozz.makeSpan(transform),
}; };
_ = settings; _ = settings;
} }
pub fn updateAndRun(self: *@This(), output: []ozz.SoaTransform) void { pub fn updateAndRun(self: *@This(), output: []ozz.SoaTransform) void {
self.updateBlendingJob(); self.updateBlendingJob();
self.runBlendingJob(output) catch return; self.runBlendingJob(output) catch return;
} }
pub fn updateBlendingJob(self: *@This()) void { pub fn updateBlendingJob(self: *@This()) void {
self.blendingJob.threshold = self.threshold; self.blendingJob.threshold = self.threshold;
self.blendingJob.layers = ozz.makeSpan(self.jobLayers.items); self.blendingJob.layers = ozz.makeSpan(self.jobLayers.items);
//self.blendingJob.additive_layers = if (self.useAdditive) ozz.makeSpan(self.jobLayersAdditive.items) else .{}; //self.blendingJob.additive_layers = if (self.useAdditive) ozz.makeSpan(self.jobLayersAdditive.items) else .{};
self.blendingJob.additive_layers = .{}; self.blendingJob.additive_layers = .{};
} }
pub fn runBlendingJob(self: *@This(), output: []ozz.SoaTransform) !void { pub fn runBlendingJob(self: *@This(), output: []ozz.SoaTransform) !void {
self.blendingJob.output = ozz.makeSpan(output); self.blendingJob.output = ozz.makeSpan(output);
if (!self.blendingJob.run()) { if (!self.blendingJob.run()) {
core.engine_logs("blending job failed"); core.engine_logs("blending job failed");
return; return;
} }
} }
}; };
// resolver helpers // resolver helpers
pub const FloatHelpers = struct { pub const FloatHelpers = struct {
pub inline fn updateTrackTime(target: *f32, dt: f64, rate: f32, endTime: f32) void { pub inline fn updateTrackTime(target: *f32, dt: f64, rate: f32, endTime: f32) void {
target.* += @as(f32, @floatCast(dt)) * rate; target.* += @as(f32, @floatCast(dt)) * rate;
while (target.* > endTime) { while (target.* > endTime) {
target.* -= endTime; target.* -= endTime;
} }
} }
}; };
// samples a single animation, same as the default behaviour. // samples a single animation, same as the default behaviour.
// used as a test for the resolver system // used as a test for the resolver system
pub const SingleAnimationResolver = struct { pub const SingleAnimationResolver = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
locals: std.ArrayListUnmanaged(ozz.SoaTransform) = .{}, locals: std.ArrayListUnmanaged(ozz.SoaTransform) = .{},
track: ?*AnimationTrack = null, track: ?*AnimationTrack = null,
playback: f32 = 0.0, playback: f32 = 0.0,
playbackRate: f32 = 1.0, playbackRate: f32 = 1.0,
pub const AnimResolverVTable = AnimResolverInterface.Implement(@This()); pub const AnimResolverVTable = AnimResolverInterface.Implement(@This());
pub fn create(allocator: std.mem.Allocator) !*@This() { pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This()); const self = try allocator.create(@This());
self.* = .{ self.* = .{
.allocator = allocator, .allocator = allocator,
}; };
return self; return self;
} }
pub fn onSkeletonSet(self: *@This(), animator: *Animator) !void { pub fn onSkeletonSet(self: *@This(), animator: *Animator) !void {
if (animator.skeleton) |skeleton| { if (animator.skeleton) |skeleton| {
try self.locals.resize(self.allocator, skeleton.sk.numSoaJoints()); try self.locals.resize(self.allocator, skeleton.sk.numSoaJoints());
} }
} }
pub fn resolve(self: *@This(), dt: f64, animator: *Animator) !void { pub fn resolve(self: *@This(), dt: f64, animator: *Animator) !void {
self.track = animator.track; self.track = animator.track;
if (self.track == null) { if (self.track == null) {
return; return;
} }
const track = self.track.?; const track = self.track.?;
if (track.endTime < 0.01) { if (track.endTime < 0.01) {
return; return;
} }
FloatHelpers.updateTrackTime(&self.playback, dt, self.playbackRate, track.endTime); FloatHelpers.updateTrackTime(&self.playback, dt, self.playbackRate, track.endTime);
animator.sampleAnimation(self.playback, track, self.locals.items); animator.sampleAnimation(self.playback, track, self.locals.items);
animator.commitLocalToModel(self.locals.items); animator.commitLocalToModel(self.locals.items);
animator.modelToFinal(); animator.modelToFinal();
} }
pub fn destroy(self: *@This()) void { pub fn destroy(self: *@This()) void {
self.locals.deinit(self.allocator); self.locals.deinit(self.allocator);
self.allocator.destroy(self); self.allocator.destroy(self);
} }
}; };
const animation_system = @import("animationSystem.zig"); const animation_system = @import("animationSystem.zig");
const Animator = animation_system.Animator; const Animator = animation_system.Animator;
const AnimationTrack = animation_system.AnimationTrack; const AnimationTrack = animation_system.AnimationTrack;
const core = @import("core"); const core = @import("core");
const std = @import("std"); const std = @import("std");
const ozz = @import("ozz"); const ozz = @import("ozz");

View File

@ -1,480 +1,480 @@
// big main sy.itemsstem for animation // big main sy.itemsstem for animation
const ozz = @import("ozz"); const ozz = @import("ozz");
const core = @import("core"); const core = @import("core");
const std = @import("std"); const std = @import("std");
pub const BoneHandle = enum(u8) { _ }; pub const BoneHandle = enum(u8) { _ };
pub const Skeleton = struct { pub const Skeleton = struct {
sk: *ozz.Skeleton, sk: *ozz.Skeleton,
inverseBinds: std.ArrayListUnmanaged(core.Mat) = .{}, inverseBinds: std.ArrayListUnmanaged(core.Mat) = .{},
jointMapping: std.StringHashMapUnmanaged(u8) = .{}, jointMapping: std.StringHashMapUnmanaged(u8) = .{},
pub fn buildJointMap(self: *@This(), allocator: std.mem.Allocator) !void { pub fn buildJointMap(self: *@This(), allocator: std.mem.Allocator) !void {
for (self.sk.getJointsList(), 0..) |jointName, i| { for (self.sk.getJointsList(), 0..) |jointName, i| {
// std.debug.print("jointName {d} {s}\n", .{ i, jointName }); // std.debug.print("jointName {d} {s}\n", .{ i, jointName });
const str = std.mem.span(jointName); const str = std.mem.span(jointName);
try self.jointMapping.put(allocator, str, @intCast(i)); try self.jointMapping.put(allocator, str, @intCast(i));
} }
} }
pub fn getBoneHandleByName(self: @This(), string: []const u8) ?BoneHandle { pub fn getBoneHandleByName(self: @This(), string: []const u8) ?BoneHandle {
if (self.jointMapping.get(string)) |x| { if (self.jointMapping.get(string)) |x| {
return @enumFromInt(x); return @enumFromInt(x);
} else { } else {
return null; return null;
} }
} }
pub fn deinit(self: *@This()) void { pub fn deinit(self: *@This()) void {
self.sk.destroy(); self.sk.destroy();
} }
}; };
pub const AnimationTrack = struct { pub const AnimationTrack = struct {
animation: *ozz.Animation, animation: *ozz.Animation,
endTime: f32 = 1.0, endTime: f32 = 1.0,
pub fn deinit(self: *@This()) void { pub fn deinit(self: *@This()) void {
self.animation.destroy(); self.animation.destroy();
} }
}; };
pub const PlaybackTrack = struct { pub const PlaybackTrack = struct {
track: ?*AnimationTrack = null, track: ?*AnimationTrack = null,
playback: f32 = 0.0, playback: f32 = 0.0,
playbackRate: f32 = 1.0, playbackRate: f32 = 1.0,
}; };
pub const Animator = struct { pub const Animator = struct {
jointRemap: ?[]u8 = null, jointRemap: ?[]u8 = null,
animationName: ?core.Name = null, animationName: ?core.Name = null,
skeleton: ?*Skeleton = null, skeleton: ?*Skeleton = null,
skeletonName: ?core.Name = null, skeletonName: ?core.Name = null,
sjc: *ozz.SamplingJobContext = undefined, sjc: *ozz.SamplingJobContext = undefined,
track: ?*AnimationTrack = null, track: ?*AnimationTrack = null,
playback: f32 = 0.0, playback: f32 = 0.0,
playbackRate: f32 = 1.0, playbackRate: f32 = 1.0,
// todo.. implement blending // todo.. implement blending
// animations: [4]*ozz.Animation = undefined, // animations: [4]*ozz.Animation = undefined,
// timelines: [4]f32 = .{ 0, 0, 0, 0 }, // timelines: [4]f32 = .{ 0, 0, 0, 0 },
animationCount: u32 = 0, animationCount: u32 = 0,
locals: std.ArrayListUnmanaged(ozz.SoaTransform) = .{}, locals: std.ArrayListUnmanaged(ozz.SoaTransform) = .{},
models: std.ArrayListUnmanaged(ozz.Float4x4) = .{}, models: std.ArrayListUnmanaged(ozz.Float4x4) = .{},
finals: std.ArrayListUnmanaged(core.Mat) = .{}, finals: std.ArrayListUnmanaged(core.Mat) = .{},
finalsSpan: core.Span = undefined, finalsSpan: core.Span = undefined,
entity: core.Entity = undefined, entity: core.Entity = undefined,
jointLength: usize = 0, jointLength: usize = 0,
resolverRef: ?AnimResolverRef = null, resolverRef: ?AnimResolverRef = null,
pub var allocator: std.mem.Allocator = undefined; pub var allocator: std.mem.Allocator = undefined;
// oh god if I want to support multiple animation blending... // oh god if I want to support multiple animation blending...
// maybe the kernel should contain a fixed amount of animations? // maybe the kernel should contain a fixed amount of animations?
pub fn initECS(self: *@This(), handle: core.SetHandle) void { pub fn initECS(self: *@This(), handle: core.SetHandle) void {
// get the mesh component // get the mesh component
self.entity = core.Entity{ .handle = handle }; self.entity = core.Entity{ .handle = handle };
if (self.entity.get(graphics.StaticMesh)) |mesh| { if (self.entity.get(graphics.StaticMesh)) |mesh| {
mesh.animated = true; //todo mesh.animated = true; //todo
mesh.animator = self; mesh.animator = self;
self.sjc = ozz.SamplingJobContext.createMaxTracks(256); self.sjc = ozz.SamplingJobContext.createMaxTracks(256);
} else { } else {
@panic("animator added to an entity that does not have a mesh component"); @panic("animator added to an entity that does not have a mesh component");
} }
} }
pub fn getBoneTransform(self: *@This(), handle: BoneHandle) core.Mat { pub fn getBoneTransform(self: *@This(), handle: BoneHandle) core.Mat {
return @bitCast(self.models.items[@intFromEnum(handle)]); return @bitCast(self.models.items[@intFromEnum(handle)]);
} }
pub fn setSkeletonByName(self: *@This(), skName: core.Name) !void { pub fn setSkeletonByName(self: *@This(), skName: core.Name) !void {
if (self.skeleton != null) { if (self.skeleton != null) {
// return the previous span and allocate a new one. // return the previous span and allocate a new one.
gAnimationSys.slots.removeSpan(self.finalsSpan); gAnimationSys.slots.removeSpan(self.finalsSpan);
} }
self.skeletonName = skName; self.skeletonName = skName;
self.skeleton = gAnimationSys.skeletons.get(self.skeletonName.?.handle()).?; self.skeleton = gAnimationSys.skeletons.get(self.skeletonName.?.handle()).?;
const numJoints = self.skeleton.?.sk.numJoints(); const numJoints = self.skeleton.?.sk.numJoints();
self.jointLength = numJoints; self.jointLength = numJoints;
self.sjc.resize(@intCast(numJoints)); self.sjc.resize(@intCast(numJoints));
try self.locals.resize(allocator, self.skeleton.?.sk.numSoaJoints()); try self.locals.resize(allocator, self.skeleton.?.sk.numSoaJoints());
try self.models.resize(allocator, numJoints); try self.models.resize(allocator, numJoints);
try self.finals.resize(allocator, numJoints); try self.finals.resize(allocator, numJoints);
self.finalsSpan = try gAnimationSys.slots.allocate(@intCast(numJoints)); self.finalsSpan = try gAnimationSys.slots.allocate(@intCast(numJoints));
if (self.resolverRef) |ref| { if (self.resolverRef) |ref| {
if (ref.vtable.onSkeletonSet) |f| { if (ref.vtable.onSkeletonSet) |f| {
f(ref.ptr, self); f(ref.ptr, self);
} }
} }
self.jointRemap = null; self.jointRemap = null;
} }
pub fn setSkeleton(self: *@This(), skeleton: []const u8) void { pub fn setSkeleton(self: *@This(), skeleton: []const u8) void {
self.setSkeletonByName(core.MakeName(skeleton)) catch unreachable; self.setSkeletonByName(core.MakeName(skeleton)) catch unreachable;
} }
pub fn addResolver(self: *@This(), comptime Resolver: type) !*Resolver { pub fn addResolver(self: *@This(), comptime Resolver: type) !*Resolver {
const resolver = try Resolver.create(allocator); const resolver = try Resolver.create(allocator);
try resolver.onSkeletonSet(self); try resolver.onSkeletonSet(self);
self.resolverRef = core.refFromPtr(AnimResolverInterface, resolver); self.resolverRef = core.refFromPtr(AnimResolverInterface, resolver);
return resolver; return resolver;
} }
pub fn removeResolver(self: *@This()) void { pub fn removeResolver(self: *@This()) void {
if (self.resolverRef) |ref| { if (self.resolverRef) |ref| {
ref.vtable.destroy(ref.ptr); ref.vtable.destroy(ref.ptr);
self.resolverRef = null; self.resolverRef = null;
} }
} }
pub fn update(self: *@This(), dt: f64) void { pub fn update(self: *@This(), dt: f64) void {
if (self.skeleton == null) { if (self.skeleton == null) {
return; return;
} }
// if a resolver is present, use that to update my the finals instead of the default function below // if a resolver is present, use that to update my the finals instead of the default function below
if (self.resolverRef) |ref| { if (self.resolverRef) |ref| {
ref.vtable.resolve(ref.ptr, dt, self); ref.vtable.resolve(ref.ptr, dt, self);
return; return;
} }
if (!self.defaultSample(dt)) { if (!self.defaultSample(dt)) {
return; return;
} }
self.modelToFinal(); self.modelToFinal();
} }
fn defaultSample(self: *@This(), dt: f64) bool { fn defaultSample(self: *@This(), dt: f64) bool {
if (self.track == null) if (self.track == null)
return false; return false;
const track = self.track.?; const track = self.track.?;
if (track.endTime < 0.01) if (track.endTime < 0.01)
return false; return false;
const skeleton = self.skeleton.?; const skeleton = self.skeleton.?;
self.playback += @as(f32, @floatCast(dt)) * self.playbackRate; self.playback += @as(f32, @floatCast(dt)) * self.playbackRate;
while (self.playback > track.endTime) { while (self.playback > track.endTime) {
self.playback -= track.endTime; self.playback -= track.endTime;
} }
var samplingJob: ozz.SamplingJob = .{ var samplingJob: ozz.SamplingJob = .{
.ratio = self.playback / track.endTime, .ratio = self.playback / track.endTime,
.animation = track.animation, .animation = track.animation,
.context = self.sjc, .context = self.sjc,
.output = ozz.makeSpan(self.locals.items), .output = ozz.makeSpan(self.locals.items),
}; };
if (!samplingJob.run()) { if (!samplingJob.run()) {
core.engine_errs("sampling job failed"); core.engine_errs("sampling job failed");
return false; return false;
} }
var ltmJob: ozz.LocalToModelJob = .{ var ltmJob: ozz.LocalToModelJob = .{
.skeleton = skeleton.sk, .skeleton = skeleton.sk,
.input = ozz.makeSpan(self.locals.items), .input = ozz.makeSpan(self.locals.items),
.output = ozz.makeSpan(self.models.items), .output = ozz.makeSpan(self.models.items),
}; };
if (!ltmJob.run()) { if (!ltmJob.run()) {
core.engine_errs("local to model job failed"); core.engine_errs("local to model job failed");
return false; return false;
} }
return true; return true;
} }
pub fn commitLocalToModel(self: *@This(), input: []ozz.SoaTransform) void { pub fn commitLocalToModel(self: *@This(), input: []ozz.SoaTransform) void {
self.localToModel(input, self.models.items); self.localToModel(input, self.models.items);
} }
pub fn localToModel(self: *@This(), input: []ozz.SoaTransform, output: []ozz.Float4x4) void { pub fn localToModel(self: *@This(), input: []ozz.SoaTransform, output: []ozz.Float4x4) void {
var ltmJob: ozz.LocalToModelJob = .{ var ltmJob: ozz.LocalToModelJob = .{
.skeleton = self.skeleton.?.sk, .skeleton = self.skeleton.?.sk,
.input = ozz.makeSpan(input), .input = ozz.makeSpan(input),
.output = ozz.makeSpan(output), .output = ozz.makeSpan(output),
}; };
if (!ltmJob.run()) { if (!ltmJob.run()) {
core.engine_errs("local to model job failed"); core.engine_errs("local to model job failed");
return; return;
} }
} }
pub fn sampleAnimation(self: *@This(), time: f32, track: *AnimationTrack, output: []ozz.SoaTransform) void { pub fn sampleAnimation(self: *@This(), time: f32, track: *AnimationTrack, output: []ozz.SoaTransform) void {
var samplingJob: ozz.SamplingJob = .{ var samplingJob: ozz.SamplingJob = .{
.ratio = time / track.endTime, .ratio = time / track.endTime,
.animation = track.animation, .animation = track.animation,
.context = self.sjc, .context = self.sjc,
.output = ozz.makeSpan(output), .output = ozz.makeSpan(output),
}; };
if (!samplingJob.run()) { if (!samplingJob.run()) {
core.engine_errs("sampling job failed"); core.engine_errs("sampling job failed");
return; return;
} }
} }
pub fn modelToFinal(self: *@This()) void { pub fn modelToFinal(self: *@This()) void {
if (self.jointRemap == null) { if (self.jointRemap == null) {
if (self.entity.get(graphics.StaticMesh)) |meshComponent| { if (self.entity.get(graphics.StaticMesh)) |meshComponent| {
if (meshComponent.mesh) |mesh| { if (meshComponent.mesh) |mesh| {
self.jointRemap = mesh.jointRemap; self.jointRemap = mesh.jointRemap;
} }
} }
} }
const skeleton = self.skeleton.?; const skeleton = self.skeleton.?;
for (self.models.items, 0..) |model, i| { for (self.models.items, 0..) |model, i| {
const transform: core.Mat = @bitCast(model); const transform: core.Mat = @bitCast(model);
// const p: core.zm.Vec = .{ 0, 0, 0, 1 }; // const p: core.zm.Vec = .{ 0, 0, 0, 1 };
// graphics.debugSphere(core.Vectorf.fromZm(core.zm.mul(p, transform)), 0.03, .{ // graphics.debugSphere(core.Vectorf.fromZm(core.zm.mul(p, transform)), 0.03, .{
// .color = if (i == 15) .{ .x = 1 } else .{ .y = 1 }, // .color = if (i == 15) .{ .x = 1 } else .{ .y = 1 },
// }); // });
const final = core.zm.mul(skeleton.inverseBinds.items[i], transform); const final = core.zm.mul(skeleton.inverseBinds.items[i], transform);
// joint remap ozz -> gltf // joint remap ozz -> gltf
if (self.jointRemap) |jr| { if (self.jointRemap) |jr| {
// core.engine_log("{d} xx {d}", .{ i, jr[i] }); // core.engine_log("{d} xx {d}", .{ i, jr[i] });
self.finals.items[@intCast(jr[i])] = final; self.finals.items[@intCast(jr[i])] = final;
} else { } else {
self.finals.items[i] = final; self.finals.items[i] = final;
} }
// core.engine_log( // core.engine_log(
// "[{d}] {d} {d} {d} {d}, {d} {d} {d} {d}", // "[{d}] {d} {d} {d} {d}, {d} {d} {d} {d}",
// .{ i, transform[0][0], transform[0][1], transform[0][2], transform[0][3], transform[1][0], transform[1][1], transform[1][2], transform[1][3] }, // .{ i, transform[0][0], transform[0][1], transform[0][2], transform[0][3], transform[1][0], transform[1][1], transform[1][2], transform[1][3] },
// ); // );
} }
} }
pub fn setAnimationByName(self: *@This(), _name: core.Name) !void { pub fn setAnimationByName(self: *@This(), _name: core.Name) !void {
var name = _name; var name = _name;
self.track = gAnimationSys.animTracks.get(name.handle()); self.track = gAnimationSys.animTracks.get(name.handle());
} }
pub fn setAnimation(self: *@This(), path: []const u8) void { pub fn setAnimation(self: *@This(), path: []const u8) void {
const name = core.MakeName(path); const name = core.MakeName(path);
self.setAnimationByName(name) catch unreachable; self.setAnimationByName(name) catch unreachable;
} }
pub fn deinit(self: *@This()) void { pub fn deinit(self: *@This()) void {
self.sjc.destroy(); self.sjc.destroy();
self.removeResolver(); self.removeResolver();
self.finals.deinit(allocator); self.finals.deinit(allocator);
self.locals.deinit(allocator); self.locals.deinit(allocator);
self.models.deinit(allocator); self.models.deinit(allocator);
} }
pub var BaseContainer: *core.SparseMap(@This()) = undefined; pub var BaseContainer: *core.SparseMap(@This()) = undefined;
pub const ComponentName = "Animator"; pub const ComponentName = "Animator";
pub const ScriptExports: []const []const u8 = &.{}; pub const ScriptExports: []const []const u8 = &.{};
}; };
pub const AnimationSystem = struct { pub const AnimationSystem = struct {
backingAllocator: std.mem.Allocator, backingAllocator: std.mem.Allocator,
arena: std.heap.ArenaAllocator, arena: std.heap.ArenaAllocator,
slots: MergedSpans, slots: MergedSpans,
// Only AnimationTrack and Skeletons are made using the ArenaAllocator // Only AnimationTrack and Skeletons are made using the ArenaAllocator
animTracks: std.AutoHashMapUnmanaged(u32, *AnimationTrack) = .{}, animTracks: std.AutoHashMapUnmanaged(u32, *AnimationTrack) = .{},
skeletons: std.AutoHashMapUnmanaged(u32, *Skeleton) = .{}, skeletons: std.AutoHashMapUnmanaged(u32, *Skeleton) = .{},
sharedArena: [2]std.heap.ArenaAllocator, // could be a good usecase for a fat bump arena sharedArena: [2]std.heap.ArenaAllocator, // could be a good usecase for a fat bump arena
shared: [2]std.ArrayListUnmanaged(MatrixUploads) = .{ .{}, .{} }, shared: [2]std.ArrayListUnmanaged(MatrixUploads) = .{ .{}, .{} },
sharedLocks: [2]std.Thread.Mutex = .{ .{}, .{} }, // could be a good usecase for a fat bump arena sharedLocks: [2]std.Thread.Mutex = .{ .{}, .{} }, // could be a good usecase for a fat bump arena
pub const MatrixUploads = struct { pub const MatrixUploads = struct {
offset: u32, offset: u32,
matrices: std.ArrayListUnmanaged(core.Mat) = .{}, matrices: std.ArrayListUnmanaged(core.Mat) = .{},
}; };
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
pub const RendererInterfaceVTable = graphics.RendererInterface.from(@This()); pub const RendererInterfaceVTable = graphics.RendererInterface.from(@This());
pub fn preTick(self: *@This(), dt: f64) !void { pub fn preTick(self: *@This(), dt: f64) !void {
_ = self; _ = self;
var z1 = core.tracy.ZoneN(@src(), "animation system tick"); var z1 = core.tracy.ZoneN(@src(), "animation system tick");
defer z1.End(); defer z1.End();
for (Animator.BaseContainer.list.items) |animator| { for (Animator.BaseContainer.list.items) |animator| {
animator.update(dt); animator.update(dt);
} }
} }
pub fn newAnimTrack(self: *@This(), _name: core.Name, anim: *ozz.Animation) !void { pub fn newAnimTrack(self: *@This(), _name: core.Name, anim: *ozz.Animation) !void {
var name = _name; var name = _name;
const new = try self.arenaAllocator().create(AnimationTrack); const new = try self.arenaAllocator().create(AnimationTrack);
new.* = .{ new.* = .{
.animation = anim, .animation = anim,
.endTime = anim.getDuration(), .endTime = anim.getDuration(),
}; };
try self.animTracks.put(self.backingAllocator, name.handle(), new); try self.animTracks.put(self.backingAllocator, name.handle(), new);
} }
pub fn newSkeleton(self: *@This(), _name: core.Name, sk: *ozz.Skeleton) !void { pub fn newSkeleton(self: *@This(), _name: core.Name, sk: *ozz.Skeleton) !void {
const new = try self.arenaAllocator().create(Skeleton); const new = try self.arenaAllocator().create(Skeleton);
new.* = .{ new.* = .{
.sk = sk, .sk = sk,
}; };
var name = _name; var name = _name;
try new.buildJointMap(self.arenaAllocator()); try new.buildJointMap(self.arenaAllocator());
try new.inverseBinds.resize(self.arenaAllocator(), new.sk.numJoints()); try new.inverseBinds.resize(self.arenaAllocator(), new.sk.numJoints());
if (new.inverseBinds.items.len > 256) { if (new.inverseBinds.items.len > 256) {
@panic("too many bones in skeleton, not supported"); @panic("too many bones in skeleton, not supported");
} }
var bindModels = std.ArrayList(ozz.Float4x4).init(self.backingAllocator); var bindModels = std.ArrayList(ozz.Float4x4).init(self.backingAllocator);
defer bindModels.deinit(); defer bindModels.deinit();
try bindModels.resize(new.sk.numJoints()); try bindModels.resize(new.sk.numJoints());
var ltmJob: ozz.LocalToModelJob = .{ var ltmJob: ozz.LocalToModelJob = .{
.skeleton = new.sk, .skeleton = new.sk,
.input = new.sk.getRestPoseModel(), .input = new.sk.getRestPoseModel(),
.output = ozz.makeSpan(bindModels.items), .output = ozz.makeSpan(bindModels.items),
}; };
core.engine_log("creating bind pose {d} joints", .{new.inverseBinds.items.len}); core.engine_log("creating bind pose {d} joints", .{new.inverseBinds.items.len});
if (!ltmJob.run()) { if (!ltmJob.run()) {
core.engine_logs("unable to get bind pose"); core.engine_logs("unable to get bind pose");
return error.UnableToLoad; return error.UnableToLoad;
} }
for (bindModels.items, 0..) |bind, i| { for (bindModels.items, 0..) |bind, i| {
// const p: core.zm.Vec = .{ 0, 0, 0, 1 }; // const p: core.zm.Vec = .{ 0, 0, 0, 1 };
// graphics.debugSphere(core.Vectorf.fromZm(core.zm.mul(p, @as(core.Mat, @bitCast(bind)))), 0.1, .{ .duration = 100 }); // graphics.debugSphere(core.Vectorf.fromZm(core.zm.mul(p, @as(core.Mat, @bitCast(bind)))), 0.1, .{ .duration = 100 });
new.inverseBinds.items[i] = core.zm.inverse(@as(core.Mat, @bitCast(bind))); new.inverseBinds.items[i] = core.zm.inverse(@as(core.Mat, @bitCast(bind)));
} }
try self.skeletons.put(self.backingAllocator, name.handle(), new); try self.skeletons.put(self.backingAllocator, name.handle(), new);
} }
pub fn arenaAllocator(self: *@This()) std.mem.Allocator { pub fn arenaAllocator(self: *@This()) std.mem.Allocator {
return self.arena.allocator(); return self.arena.allocator();
} }
pub fn getShared(self: @This(), fi: u32) []const MatrixUploads { pub fn getShared(self: @This(), fi: u32) []const MatrixUploads {
return self.shared[fi].items; return self.shared[fi].items;
} }
pub fn sendShared(self: *@This(), frameIndex: u32) void { pub fn sendShared(self: *@This(), frameIndex: u32) void {
const fi: usize = @intCast(frameIndex); const fi: usize = @intCast(frameIndex);
self.sharedLocks[fi].lock(); self.sharedLocks[fi].lock();
defer self.sharedLocks[fi].unlock(); defer self.sharedLocks[fi].unlock();
_ = self.sharedArena[fi].reset(.retain_capacity); _ = self.sharedArena[fi].reset(.retain_capacity);
const allocator = self.sharedArena[fi].allocator(); const allocator = self.sharedArena[fi].allocator();
const shared = &self.shared[fi]; const shared = &self.shared[fi];
shared.* = .{}; shared.* = .{};
for (Animator.BaseContainer.list.items) |animator| { for (Animator.BaseContainer.list.items) |animator| {
var upload: MatrixUploads = .{ .offset = animator.finalsSpan.start }; var upload: MatrixUploads = .{ .offset = animator.finalsSpan.start };
// core.engine_log( // core.engine_log(
// "finalsSpan size offset{d} {d} animator finals {d}\n", // "finalsSpan size offset{d} {d} animator finals {d}\n",
// .{ // .{
// animator.finalsSpan.start, // animator.finalsSpan.start,
// animator.finalsSpan.size, // animator.finalsSpan.size,
// animator.finals.items.len // animator.finals.items.len
// }); // });
upload.matrices.resize(allocator, animator.finalsSpan.size) catch unreachable; upload.matrices.resize(allocator, animator.finalsSpan.size) catch unreachable;
for (animator.finals.items, 0..) |final, i| { for (animator.finals.items, 0..) |final, i| {
upload.matrices.items[i] = final; upload.matrices.items[i] = final;
} }
shared.append(allocator, upload) catch unreachable; shared.append(allocator, upload) catch unreachable;
} }
} }
pub fn init(alloc: std.mem.Allocator) !*@This() { pub fn init(alloc: std.mem.Allocator) !*@This() {
const self = try alloc.create(@This()); const self = try alloc.create(@This());
self.* = .{ self.* = .{
.backingAllocator = alloc, .backingAllocator = alloc,
.arena = std.heap.ArenaAllocator.init(alloc), .arena = std.heap.ArenaAllocator.init(alloc),
.sharedArena = .{ .sharedArena = .{
std.heap.ArenaAllocator.init(alloc), std.heap.ArenaAllocator.init(alloc),
std.heap.ArenaAllocator.init(alloc), std.heap.ArenaAllocator.init(alloc),
}, },
.slots = try MergedSpans.init(alloc, vk_constants.MAX_SKIN_SLOTS), .slots = try MergedSpans.init(alloc, vk_constants.MAX_SKIN_SLOTS),
}; };
gAnimationSys = self; gAnimationSys = self;
Animator.allocator = alloc; Animator.allocator = alloc;
try core.defineComponent(Animator, alloc); try core.defineComponent(Animator, alloc);
return self; return self;
} }
pub fn deinit(self: *@This()) void { pub fn deinit(self: *@This()) void {
core.engine_logs("deinitializing animation system"); core.engine_logs("deinitializing animation system");
{ {
core.engine_log("skeleton count {d}", .{self.skeletons.count()}); core.engine_log("skeleton count {d}", .{self.skeletons.count()});
var iter = self.skeletons.iterator(); var iter = self.skeletons.iterator();
while (iter.next()) |i| { while (iter.next()) |i| {
i.value_ptr.*.deinit(); i.value_ptr.*.deinit();
} }
} }
{ {
core.engine_log("animTracks count {d}", .{self.animTracks.count()}); core.engine_log("animTracks count {d}", .{self.animTracks.count()});
var iter = self.animTracks.iterator(); var iter = self.animTracks.iterator();
while (iter.next()) |i| { while (iter.next()) |i| {
i.value_ptr.*.deinit(); i.value_ptr.*.deinit();
} }
} }
for (self.sharedArena) |arena| { for (self.sharedArena) |arena| {
arena.deinit(); arena.deinit();
} }
for (Animator.BaseContainer.list.items) |animator| { for (Animator.BaseContainer.list.items) |animator| {
animator.deinit(); animator.deinit();
} }
self.slots.deinit(); self.slots.deinit();
core.undefineComponent(Animator); core.undefineComponent(Animator);
self.arena.deinit(); self.arena.deinit();
self.skeletons.deinit(self.backingAllocator); self.skeletons.deinit(self.backingAllocator);
self.animTracks.deinit(self.backingAllocator); self.animTracks.deinit(self.backingAllocator);
self.backingAllocator.destroy(self); self.backingAllocator.destroy(self);
} }
}; };
pub var gAnimationSys: *AnimationSystem = undefined; pub var gAnimationSys: *AnimationSystem = undefined;
pub fn getSkeletonByName(_name: core.Name) ?*Skeleton { pub fn getSkeletonByName(_name: core.Name) ?*Skeleton {
var name = _name; var name = _name;
return gAnimationSys.skeletons.get(name.handle()); return gAnimationSys.skeletons.get(name.handle());
} }
const graphics = @import("../graphics.zig"); const graphics = @import("../graphics.zig");
const MergedSpans = core.MergedSpans; const MergedSpans = core.MergedSpans;
const vk_constants = @import("../vk_constants.zig"); const vk_constants = @import("../vk_constants.zig");
const anim_resolver = @import("animResolver.zig"); const anim_resolver = @import("animResolver.zig");
const AnimResolverRef = anim_resolver.AnimResolverRef; const AnimResolverRef = anim_resolver.AnimResolverRef;
const AnimResolverInterface = anim_resolver.AnimResolverInterface; const AnimResolverInterface = anim_resolver.AnimResolverInterface;

View File

@ -1,86 +1,86 @@
pub const AnimationLoader = struct { pub const AnimationLoader = struct {
pub var LoaderInterfaceVTable: assets.AssetLoaderInterface = assets.AssetLoaderInterface.from("Animation", @This()); pub var LoaderInterfaceVTable: assets.AssetLoaderInterface = assets.AssetLoaderInterface.from("Animation", @This());
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
sys: *animation_system.AnimationSystem, sys: *animation_system.AnimationSystem,
pub fn discardAll(self: *@This()) void { pub fn discardAll(self: *@This()) void {
_ = self; _ = self;
} }
pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, propertiesBag: ?assets.AssetPropertiesBag) assets.AssetLoaderError!void { pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, propertiesBag: ?assets.AssetPropertiesBag) assets.AssetLoaderError!void {
const animation = ozz.Animation.create(); const animation = ozz.Animation.create();
const mapping = core.fs().loadFile(propertiesBag.?.path) catch return error.UnableToLoad; const mapping = core.fs().loadFile(propertiesBag.?.path) catch return error.UnableToLoad;
defer core.fs().unmap(mapping); defer core.fs().unmap(mapping);
animation.loadFromBytes(mapping.bytes); animation.loadFromBytes(mapping.bytes);
self.sys.newAnimTrack(assetRef.name, animation) catch return error.UnableToLoad; self.sys.newAnimTrack(assetRef.name, animation) catch return error.UnableToLoad;
} }
pub fn init(allocator: std.mem.Allocator) !*@This() { pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This()); const self = try allocator.create(@This());
self.* = .{ self.* = .{
.sys = animation_system.gAnimationSys, .sys = animation_system.gAnimationSys,
}; };
return self; return self;
} }
pub fn destroy(self: *@This(), allocator: std.mem.Allocator) void { pub fn destroy(self: *@This(), allocator: std.mem.Allocator) void {
allocator.destroy(self); allocator.destroy(self);
} }
}; };
pub const SkeletonLoader = struct { pub const SkeletonLoader = struct {
pub var LoaderInterfaceVTable: assets.AssetLoaderInterface = assets.AssetLoaderInterface.from("Skeleton", @This()); pub var LoaderInterfaceVTable: assets.AssetLoaderInterface = assets.AssetLoaderInterface.from("Skeleton", @This());
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
sys: *animation_system.AnimationSystem, sys: *animation_system.AnimationSystem,
pub fn discardAll(self: *@This()) void { pub fn discardAll(self: *@This()) void {
_ = self; _ = self;
} }
pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, propertiesBag: ?assets.AssetPropertiesBag) assets.AssetLoaderError!void { pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, propertiesBag: ?assets.AssetPropertiesBag) assets.AssetLoaderError!void {
const sk = ozz.Skeleton.create(); const sk = ozz.Skeleton.create();
const mapping = core.fs().loadFile(propertiesBag.?.path) catch return error.UnableToLoad; const mapping = core.fs().loadFile(propertiesBag.?.path) catch return error.UnableToLoad;
defer core.fs().unmap(mapping); defer core.fs().unmap(mapping);
sk.loadFromBytes(mapping.bytes); sk.loadFromBytes(mapping.bytes);
self.sys.newSkeleton(assetRef.name, sk) catch return error.UnableToLoad; self.sys.newSkeleton(assetRef.name, sk) catch return error.UnableToLoad;
} }
pub fn init(allocator: std.mem.Allocator) !*@This() { pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This()); const self = try allocator.create(@This());
self.* = .{ self.* = .{
.sys = animation_system.gAnimationSys, .sys = animation_system.gAnimationSys,
}; };
return self; return self;
} }
pub fn destroy(self: *@This(), allocator: std.mem.Allocator) void { pub fn destroy(self: *@This(), allocator: std.mem.Allocator) void {
allocator.destroy(self); allocator.destroy(self);
} }
}; };
pub var gSkeletonLoader: *SkeletonLoader = undefined; pub var gSkeletonLoader: *SkeletonLoader = undefined;
pub var gAnimationLoader: *AnimationLoader = undefined; pub var gAnimationLoader: *AnimationLoader = undefined;
pub fn initLoaders() !void { pub fn initLoaders() !void {
gSkeletonLoader = try core.createObject(SkeletonLoader, .{}); gSkeletonLoader = try core.createObject(SkeletonLoader, .{});
gAnimationLoader = try core.createObject(AnimationLoader, .{}); gAnimationLoader = try core.createObject(AnimationLoader, .{});
try assets.gAssetSys.registerLoader(gSkeletonLoader); try assets.gAssetSys.registerLoader(gSkeletonLoader);
try assets.gAssetSys.registerLoader(gAnimationLoader); try assets.gAssetSys.registerLoader(gAnimationLoader);
} }
const animation_system = @import("animationSystem.zig"); const animation_system = @import("animationSystem.zig");
const assets = @import("assets"); const assets = @import("assets");
const core = @import("core"); const core = @import("core");
const std = @import("std"); const std = @import("std");
const ozz = @import("ozz"); const ozz = @import("ozz");

View File

@ -1,239 +1,239 @@
const MeshConfig = struct { const MeshConfig = struct {
info: CookInfo = .{ .assetType = "Mesh" }, // there must always be a CookInfo field info: CookInfo = .{ .assetType = "Mesh" }, // there must always be a CookInfo field
sourceType: []const u8 = "obj", sourceType: []const u8 = "obj",
animated: bool = false, animated: bool = false,
}; };
const extList = [_][]const u8{ "gltf", "obj", "glb" }; const extList = [_][]const u8{ "gltf", "obj", "glb" };
pub fn generateFunction(allocator: std.mem.Allocator, path: []const u8, out: *std.ArrayList(u8)) GenerateError!void { pub fn generateFunction(allocator: std.mem.Allocator, path: []const u8, out: *std.ArrayList(u8)) GenerateError!void {
_ = allocator; _ = allocator;
out.clearRetainingCapacity(); out.clearRetainingCapacity();
const ext = core.getFileExtension(path)[1..]; const ext = core.getFileExtension(path)[1..];
var config: MeshConfig = .{}; var config: MeshConfig = .{};
for (extList) |e| { for (extList) |e| {
if (std.mem.eql(u8, e, ext)) { if (std.mem.eql(u8, e, ext)) {
config.sourceType = e; config.sourceType = e;
if (std.mem.eql(u8, e, "glb")) { if (std.mem.eql(u8, e, "glb")) {
config.sourceType = "gltf"; config.sourceType = "gltf";
} }
} }
} }
std.json.stringify( std.json.stringify(
config, config,
.{ .whitespace = .indent_4 }, .{ .whitespace = .indent_4 },
out.writer(), out.writer(),
) catch return GenerateError.UnableToGenerate; ) catch return GenerateError.UnableToGenerate;
} }
fn cookObj(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8) cook.CookResult { fn cookObj(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8) cook.CookResult {
const rawFileBytes = cook.loadFileAlloc(allocator, dir, path) catch unreachable; const rawFileBytes = cook.loadFileAlloc(allocator, dir, path) catch unreachable;
defer allocator.free(rawFileBytes); defer allocator.free(rawFileBytes);
var out = std.ArrayList(u8).init(allocator); var out = std.ArrayList(u8).init(allocator);
var vertices = std.ArrayList(Vertex).init(allocator); var vertices = std.ArrayList(Vertex).init(allocator);
defer vertices.deinit(); defer vertices.deinit();
var objs = obj.loadObjBytes(rawFileBytes, allocator) catch unreachable; var objs = obj.loadObjBytes(rawFileBytes, allocator) catch unreachable;
defer objs.deinit(); defer objs.deinit();
if (objs.meshes.items.len > 0) { if (objs.meshes.items.len > 0) {
mesh.loadObjMeshVertices(&vertices, objs.meshes.items[0]) catch unreachable; mesh.loadObjMeshVertices(&vertices, objs.meshes.items[0]) catch unreachable;
for (vertices.items) |vert| { for (vertices.items) |vert| {
out.appendSlice(&@as([@sizeOf(Vertex)]u8, @bitCast(vert))) catch unreachable; out.appendSlice(&@as([@sizeOf(Vertex)]u8, @bitCast(vert))) catch unreachable;
} }
return .{ return .{
.bytes = out, .bytes = out,
.result = .Success, .result = .Success,
}; };
} else { } else {
return .{ return .{
.bytes = out, .bytes = out,
.result = .Failure, .result = .Failure,
}; };
} }
} }
fn ensureGltf2ozz(allocator: std.mem.Allocator) !void { fn ensureGltf2ozz(allocator: std.mem.Allocator) !void {
const suffix = if (builtin.os.tag == .windows) ".exe" else ""; const suffix = if (builtin.os.tag == .windows) ".exe" else "";
std.fs.cwd().access("zig-out/tools/gltf2ozz" ++ suffix, .{}) catch { std.fs.cwd().access("zig-out/tools/gltf2ozz" ++ suffix, .{}) catch {
const argv: []const []const u8 = &.{ "zig", "build", "tools" }; const argv: []const []const u8 = &.{ "zig", "build", "tools" };
core.engine_log("gltf2ozz missing, building it...", .{}); core.engine_log("gltf2ozz missing, building it...", .{});
var child = std.process.Child.init(argv, allocator); var child = std.process.Child.init(argv, allocator);
child.stdin_behavior = .Ignore; child.stdin_behavior = .Ignore;
child.stdout_behavior = .Pipe; child.stdout_behavior = .Pipe;
child.stderr_behavior = .Pipe; child.stderr_behavior = .Pipe;
child.cwd = "."; child.cwd = ".";
switch (try child.spawnAndWait()) { switch (try child.spawnAndWait()) {
.Exited => |value| { .Exited => |value| {
if (value == 0) { if (value == 0) {
core.engine_log("gltf2ozz built", .{}); core.engine_log("gltf2ozz built", .{});
} else { } else {
core.engine_logs("unable to build gltf2ozz"); core.engine_logs("unable to build gltf2ozz");
} }
}, },
.Signal => { .Signal => {
core.engine_logs("unable to build gltf2ozz"); core.engine_logs("unable to build gltf2ozz");
}, },
.Stopped => {}, .Stopped => {},
.Unknown => { .Unknown => {
unreachable; unreachable;
}, },
} }
return; return;
}; };
core.engine_log("gltf2ozz found", .{}); core.engine_log("gltf2ozz found", .{});
} }
fn cookAnimations(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8, config: MeshConfig) !void { fn cookAnimations(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8, config: MeshConfig) !void {
_ = config; _ = config;
// 1. check if it has an associated .ozzconfig file. // 1. check if it has an associated .ozzconfig file.
const gltf2OzzAbs = try std.fs.cwd().realpathAlloc(allocator, "zig-out/tools/gltf2ozz.exe"); const gltf2OzzAbs = try std.fs.cwd().realpathAlloc(allocator, "zig-out/tools/gltf2ozz.exe");
defer allocator.free(gltf2OzzAbs); defer allocator.free(gltf2OzzAbs);
const ozzconfig = try std.fmt.allocPrint(allocator, "{s}.ozzconfig", .{path}); const ozzconfig = try std.fmt.allocPrint(allocator, "{s}.ozzconfig", .{path});
defer allocator.free(ozzconfig); defer allocator.free(ozzconfig);
const fileArg = try std.fmt.allocPrint(allocator, "--file={s}", .{core.getBasePath(path)}); const fileArg = try std.fmt.allocPrint(allocator, "--file={s}", .{core.getBasePath(path)});
defer allocator.free(fileArg); defer allocator.free(fileArg);
const configArg = try std.fmt.allocPrint(allocator, "--config_file={s}", .{core.getBasePath(ozzconfig)}); const configArg = try std.fmt.allocPrint(allocator, "--config_file={s}", .{core.getBasePath(ozzconfig)});
defer allocator.free(configArg); defer allocator.free(configArg);
// todo, fix this later, idrc right now. // todo, fix this later, idrc right now.
const newConfigArg = try std.fmt.allocPrint(allocator, "--config_dump_reference={s}", .{core.getBasePath(ozzconfig)}); const newConfigArg = try std.fmt.allocPrint(allocator, "--config_dump_reference={s}", .{core.getBasePath(ozzconfig)});
defer allocator.free(newConfigArg); defer allocator.free(newConfigArg);
const absFile = try dir.realpathAlloc(allocator, path); const absFile = try dir.realpathAlloc(allocator, path);
defer allocator.free(absFile); defer allocator.free(absFile);
var argv: []const []const u8 = &.{ var argv: []const []const u8 = &.{
gltf2OzzAbs, gltf2OzzAbs,
fileArg, fileArg,
configArg, configArg,
}; };
dir.access(ozzconfig, .{}) catch { dir.access(ozzconfig, .{}) catch {
argv = &.{ argv = &.{
gltf2OzzAbs, gltf2OzzAbs,
fileArg, fileArg,
newConfigArg, newConfigArg,
}; };
core.engine_log("creating ozz config for file, marked as animated but no animation data", .{}); core.engine_log("creating ozz config for file, marked as animated but no animation data", .{});
}; };
// std.debug.print("{s} {s} {s} cwd = {s}\n", .{ argv[0], argv[1], argv[2], core.getFolder(absFile) }); // std.debug.print("{s} {s} {s} cwd = {s}\n", .{ argv[0], argv[1], argv[2], core.getFolder(absFile) });
const result = try std.process.Child.run(.{ const result = try std.process.Child.run(.{
.argv = argv, .argv = argv,
.allocator = allocator, .allocator = allocator,
.cwd = core.getFolder(absFile), .cwd = core.getFolder(absFile),
.max_output_bytes = 150 * 1024 * 1024, .max_output_bytes = 150 * 1024 * 1024,
}); });
defer allocator.free(result.stdout); defer allocator.free(result.stdout);
defer allocator.free(result.stderr); defer allocator.free(result.stderr);
var success: bool = true; var success: bool = true;
switch (result.term) { switch (result.term) {
.Exited => |value| { .Exited => |value| {
if (value != 0) { if (value != 0) {
success = false; success = false;
} }
}, },
.Signal => { .Signal => {
success = false; success = false;
}, },
.Stopped => { .Stopped => {
success = false; success = false;
// no-op should be ok? // no-op should be ok?
}, },
.Unknown => { .Unknown => {
unreachable; unreachable;
}, },
} }
if (success) { if (success) {
core.engine_log("generated animations for {s}", .{path}); core.engine_log("generated animations for {s}", .{path});
} else { } else {
core.engine_log("error generating animations {s} stdout:\n{s}\n stderr:{s}\n", .{ path, result.stdout, result.stderr }); core.engine_log("error generating animations {s} stdout:\n{s}\n stderr:{s}\n", .{ path, result.stdout, result.stderr });
} }
// 2. if so, run it through gltf2ozz with that file. // 2. if so, run it through gltf2ozz with that file.
} }
fn cookGltf(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8, config: MeshConfig) cook.CookResult { fn cookGltf(allocator: std.mem.Allocator, dir: std.fs.Dir, path: []const u8, config: MeshConfig) cook.CookResult {
core.engine_logs("gltf cooking not implemeted"); core.engine_logs("gltf cooking not implemeted");
const out = std.ArrayList(u8).init(allocator); const out = std.ArrayList(u8).init(allocator);
// check if it's animated. if it's animated, then invoke gltf2ozz and create a .ozzconfig file and // check if it's animated. if it's animated, then invoke gltf2ozz and create a .ozzconfig file and
// make a subfolder called // make a subfolder called
if (config.animated) { if (config.animated) {
// if gltf2ozz isn't there then we have to call zig build tools // if gltf2ozz isn't there then we have to call zig build tools
ensureGltf2ozz(allocator) catch unreachable; ensureGltf2ozz(allocator) catch unreachable;
cookAnimations(allocator, dir, path, config) catch unreachable; cookAnimations(allocator, dir, path, config) catch unreachable;
} }
return .{ .bytes = out, .result = .Failure }; return .{ .bytes = out, .result = .Failure };
} }
pub fn cookFunction( pub fn cookFunction(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
dir: std.fs.Dir, dir: std.fs.Dir,
path: []const u8, path: []const u8,
params: cook.CookParams, params: cook.CookParams,
) cook.CookResult { ) cook.CookResult {
core.engine_log("{s}", .{params.cookFileName}); core.engine_log("{s}", .{params.cookFileName});
const fc = cook.loadFileAlloc(allocator, dir, params.cookFileName) catch unreachable; const fc = cook.loadFileAlloc(allocator, dir, params.cookFileName) catch unreachable;
defer allocator.free(fc); defer allocator.free(fc);
const config = std.json.parseFromSlice(MeshConfig, allocator, fc[0 .. fc.len - 1], .{}) catch unreachable; const config = std.json.parseFromSlice(MeshConfig, allocator, fc[0 .. fc.len - 1], .{}) catch unreachable;
defer config.deinit(); defer config.deinit();
if (std.mem.eql(u8, config.value.sourceType, "obj")) { if (std.mem.eql(u8, config.value.sourceType, "obj")) {
return cookObj(allocator, dir, path); return cookObj(allocator, dir, path);
} else { } else {
return cookGltf(allocator, dir, path, config.value); return cookGltf(allocator, dir, path, config.value);
} }
} }
pub fn initCooker(allocator: std.mem.Allocator) !void { pub fn initCooker(allocator: std.mem.Allocator) !void {
_ = allocator; _ = allocator;
const registry = assets.cook.getRegistry(); const registry = assets.cook.getRegistry();
try registry.install("Mesh", generateFunction, cookFunction, &.{ try registry.install("Mesh", generateFunction, cookFunction, &.{
".obj", ".obj",
".gltf", ".gltf",
".glb", ".glb",
}); });
} }
pub fn deinitCooker() void { pub fn deinitCooker() void {
// //
} }
const std = @import("std"); const std = @import("std");
const assets = @import("assets"); const assets = @import("assets");
const cook = assets.cook; const cook = assets.cook;
const CookInfo = assets.cook.CookInfo; const CookInfo = assets.cook.CookInfo;
const GenerateError = assets.cook.GenerateError; const GenerateError = assets.cook.GenerateError;
const core = @import("core"); const core = @import("core");
const obj = @import("objLoader"); const obj = @import("objLoader");
const builtin = @import("builtin"); const builtin = @import("builtin");
const mesh = @import("../mesh.zig"); const mesh = @import("../mesh.zig");
const Mesh = mesh.Mesh; const Mesh = mesh.Mesh;
const Vertex = mesh.MeshVertex; const Vertex = mesh.MeshVertex;

View File

@ -1,60 +1,60 @@
const TextureConfig = struct { const TextureConfig = struct {
info: CookInfo = .{ .assetType = "Texture" }, // there must always be a CookInfo field info: CookInfo = .{ .assetType = "Texture" }, // there must always be a CookInfo field
sourceType: []const u8 = "png", sourceType: []const u8 = "png",
}; };
pub fn generateFunction(allocator: std.mem.Allocator, path: []const u8, out: *std.ArrayList(u8)) GenerateError!void { pub fn generateFunction(allocator: std.mem.Allocator, path: []const u8, out: *std.ArrayList(u8)) GenerateError!void {
_ = allocator; _ = allocator;
_ = path; _ = path;
out.clearRetainingCapacity(); out.clearRetainingCapacity();
std.json.stringify( std.json.stringify(
TextureConfig{}, TextureConfig{},
.{ .whitespace = .indent_4 }, .{ .whitespace = .indent_4 },
out.writer(), out.writer(),
) catch return GenerateError.UnableToGenerate; ) catch return GenerateError.UnableToGenerate;
} }
pub fn cookFunction( pub fn cookFunction(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
dir: std.fs.Dir, dir: std.fs.Dir,
path: []const u8, path: []const u8,
params: cook.CookParams, params: cook.CookParams,
) cook.CookResult { ) cook.CookResult {
_ = params; _ = params;
const rawFileBytes = cook.loadFileAlloc(allocator, dir, path) catch unreachable; const rawFileBytes = cook.loadFileAlloc(allocator, dir, path) catch unreachable;
defer allocator.free(rawFileBytes); defer allocator.free(rawFileBytes);
// 1. load the file, and create a bytes buffer // 1. load the file, and create a bytes buffer
var contents = png.PngContents.initFromBytes(allocator, path, rawFileBytes) catch unreachable; var contents = png.PngContents.initFromBytes(allocator, path, rawFileBytes) catch unreachable;
defer contents.deinit(); defer contents.deinit();
// png.PngContents.initFromBytes(allocator: std.mem.Allocator, pathName: []const u8, pngFileContents: []const u8) // png.PngContents.initFromBytes(allocator: std.mem.Allocator, pathName: []const u8, pngFileContents: []const u8)
// 2. use the PngContents function to cook it. // 2. use the PngContents function to cook it.
return .{ return .{
.bytes = contents.toBuffer() catch unreachable, .bytes = contents.toBuffer() catch unreachable,
.result = .Success, .result = .Success,
}; };
} }
pub fn initCooker(allocator: std.mem.Allocator) !void { pub fn initCooker(allocator: std.mem.Allocator) !void {
_ = allocator; _ = allocator;
const registry = assets.cook.getRegistry(); const registry = assets.cook.getRegistry();
try registry.install("Texture", generateFunction, cookFunction, &.{ try registry.install("Texture", generateFunction, cookFunction, &.{
".png", ".png",
}); });
} }
pub fn deinitCooker() void { pub fn deinitCooker() void {
// //
} }
const std = @import("std"); const std = @import("std");
const assets = @import("assets"); const assets = @import("assets");
const cook = assets.cook; const cook = assets.cook;
const CookInfo = assets.cook.CookInfo; const CookInfo = assets.cook.CookInfo;
const GenerateError = assets.cook.GenerateError; const GenerateError = assets.cook.GenerateError;
const core = @import("core"); const core = @import("core");
const png = core.png; const png = core.png;

View File

@ -1,52 +1,52 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const core = @import("core"); const core = @import("core");
const VkConstants = @import("vk_constants.zig"); const VkConstants = @import("vk_constants.zig");
const meshes = @import("mesh.zig"); const meshes = @import("mesh.zig");
const NeonVkContext = @import("vk_renderer.zig").NeonVkContext; const NeonVkContext = @import("vk_renderer.zig").NeonVkContext;
const vk_pipeline = @import("vk_pipeline.zig"); const vk_pipeline = @import("vk_pipeline.zig");
const NeonVkPipelineBuilder = vk_pipeline.NeonVkPipelineBuilder; const NeonVkPipelineBuilder = vk_pipeline.NeonVkPipelineBuilder;
const EulerAngles = core.EulerAngles; const EulerAngles = core.EulerAngles;
const Mat = core.Mat; const Mat = core.Mat;
const Vectorf = core.Vectorf; const Vectorf = core.Vectorf;
const Quat = core.Quat; const Quat = core.Quat;
const zm = core.zm; const zm = core.zm;
const mul = zm.mul; const mul = zm.mul;
pub const Material = struct { pub const Material = struct {
materialName: core.Name, materialName: core.Name,
textureSet: vk.DescriptorSet = .null_handle, textureSet: vk.DescriptorSet = .null_handle,
pipeline: vk.Pipeline, pipeline: vk.Pipeline,
layout: vk.PipelineLayout, layout: vk.PipelineLayout,
pub fn deinit(self: *Material, ctx: *NeonVkContext) void { pub fn deinit(self: *Material, ctx: *NeonVkContext) void {
ctx.vkd.destroyPipeline(ctx.dev, self.pipeline, null); ctx.vkd.destroyPipeline(ctx.dev, self.pipeline, null);
ctx.vkAllocator.destroyPipelineLayout(ctx.dev, self.layout); ctx.vkAllocator.destroyPipelineLayout(ctx.dev, self.layout);
} }
}; };
pub const MaterialBuilder = struct { pub const MaterialBuilder = struct {
const Self = @This(); const Self = @This();
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
ctx: *NeonVkContext, ctx: *NeonVkContext,
pipelineBuilder: NeonVkPipelineBuilder, pipelineBuilder: NeonVkPipelineBuilder,
pub fn init(ctx: *NeonVkContext) MaterialBuilder { pub fn init(ctx: *NeonVkContext) MaterialBuilder {
const self = MaterialBuilder{ const self = MaterialBuilder{
.allocator = ctx.allocator, .allocator = ctx.allocator,
.ctx = ctx, .ctx = ctx,
}; };
return self; return self;
} }
pub fn build(self: *Self) !void { pub fn build(self: *Self) !void {
_ = self; _ = self;
// try self.ctx.add_material(); // try self.ctx.add_material();
} }
pub fn deinit(self: *Self) void { pub fn deinit(self: *Self) void {
_ = self; _ = self;
} }
}; };

View File

@ -1,96 +1,96 @@
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
cubeMapShared: [graphics.NumFrames]?vk.DescriptorSet = .{ null, null }, cubeMapShared: [graphics.NumFrames]?vk.DescriptorSet = .{ null, null },
cubeMapTextureSet: ?vk.DescriptorSet = null, cubeMapTextureSet: ?vk.DescriptorSet = null,
cubeMapName: ?core.Name = null, cubeMapName: ?core.Name = null,
material: *graphics.Material = undefined, material: *graphics.Material = undefined,
mesh: ?graphics.IndexedMesh = null, mesh: ?graphics.IndexedMesh = null,
pub const RendererInterfaceVTable = graphics.RendererInterface.from(@This()); pub const RendererInterfaceVTable = graphics.RendererInterface.from(@This());
pub var gSkybox: *@This() = undefined; pub var gSkybox: *@This() = undefined;
pub fn create(allocator: std.mem.Allocator) !*@This() { pub fn create(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This()); const self = try allocator.create(@This());
self.* = .{ self.* = .{
.allocator = allocator, .allocator = allocator,
}; };
gSkybox = self; gSkybox = self;
try self.initPipeline(); try self.initPipeline();
try graphics.registerRendererPlugin(self); try graphics.registerRendererPlugin(self);
return self; return self;
} }
pub fn sendShared(self: *@This(), fi: u32) void { pub fn sendShared(self: *@This(), fi: u32) void {
if (self.cubeMapName == null) { if (self.cubeMapName == null) {
self.cubeMapShared[fi] = self.cubeMapTextureSet; self.cubeMapShared[fi] = self.cubeMapTextureSet;
return; return;
} else { } else {
if (self.mesh == null) if (self.mesh == null)
self.mesh = graphics.getIndexedMeshByName(core.MakeName("m_skybox")); self.mesh = graphics.getIndexedMeshByName(core.MakeName("m_skybox"));
if (self.cubeMapTextureSet == null) { if (self.cubeMapTextureSet == null) {
const handle = self.cubeMapName.?.handle(); const handle = self.cubeMapName.?.handle();
self.cubeMapTextureSet = graphics.getContext().textureSets.get(handle); self.cubeMapTextureSet = graphics.getContext().textureSets.get(handle);
} }
} }
self.cubeMapShared[fi] = self.cubeMapTextureSet; self.cubeMapShared[fi] = self.cubeMapTextureSet;
} }
pub fn initPipeline(self: *@This()) !void { pub fn initPipeline(self: *@This()) !void {
const gc = graphics.getContext(); const gc = graphics.getContext();
var pipelineBuilder = try graphics.NeonVkPipelineBuilder.init( var pipelineBuilder = try graphics.NeonVkPipelineBuilder.init(
gc.dev, gc.dev,
gc.vkd, gc.vkd,
self.allocator, self.allocator,
gc.vkAllocator, gc.vkAllocator,
skybox_vert.spv(), skybox_vert.spv(),
skybox_frag.spv(), skybox_frag.spv(),
); );
defer pipelineBuilder.deinit(); defer pipelineBuilder.deinit();
try pipelineBuilder.add_mesh_description(); try pipelineBuilder.add_mesh_description();
try pipelineBuilder.add_layout(gc.globalDescriptorLayout); try pipelineBuilder.add_layout(gc.globalDescriptorLayout);
try pipelineBuilder.add_layout(gc.singleTextureSetLayout); try pipelineBuilder.add_layout(gc.singleTextureSetLayout);
try pipelineBuilder.add_depth_stencil(); // todo.. we might not want this for a skybox. try pipelineBuilder.add_depth_stencil(); // todo.. we might not want this for a skybox.
try pipelineBuilder.init_triangle_pipeline(gc.actual_extent); try pipelineBuilder.init_triangle_pipeline(gc.actual_extent);
pipelineBuilder.pdsci.?.depth_write_enable = vk.FALSE; pipelineBuilder.pdsci.?.depth_write_enable = vk.FALSE;
pipelineBuilder.pdsci.?.depth_test_enable = vk.FALSE; pipelineBuilder.pdsci.?.depth_test_enable = vk.FALSE;
pipelineBuilder.pdsci.?.depth_compare_op = .never; pipelineBuilder.pdsci.?.depth_compare_op = .never;
const materialName = core.MakeName("Mat_skybox"); const materialName = core.MakeName("Mat_skybox");
self.material = try self.allocator.create(graphics.Material); self.material = try self.allocator.create(graphics.Material);
self.material.* = graphics.Material{ self.material.* = graphics.Material{
.materialName = materialName, .materialName = materialName,
.pipeline = (try pipelineBuilder.build(gc.renderPass)).?, .pipeline = (try pipelineBuilder.build(gc.renderPass)).?,
.layout = pipelineBuilder.pipelineLayout, .layout = pipelineBuilder.pipelineLayout,
}; };
try gc.add_material(self.material); try gc.add_material(self.material);
} }
pub fn setSkybox(textureName: []const u8) !void { pub fn setSkybox(textureName: []const u8) !void {
const name = core.MakeName(textureName); const name = core.MakeName(textureName);
gSkybox.cubeMapName = name; gSkybox.cubeMapName = name;
} }
pub fn destroy(self: *@This()) void { pub fn destroy(self: *@This()) void {
self.allocator.destroy(self); self.allocator.destroy(self);
} }
const vk_renderer_interface = @import("vk_renderer/vk_renderer_interface.zig"); const vk_renderer_interface = @import("vk_renderer/vk_renderer_interface.zig");
const RendererInterface = vk_renderer_interface.RendererInterface; const RendererInterface = vk_renderer_interface.RendererInterface;
const std = @import("std"); const std = @import("std");
const graphics = @import("graphics.zig"); const graphics = @import("graphics.zig");
const core = @import("core"); const core = @import("core");
const vk = @import("vulkan"); const vk = @import("vulkan");
const skybox_vert = @import("skybox_vert"); const skybox_vert = @import("skybox_vert");
const skybox_frag = @import("skybox_frag"); const skybox_frag = @import("skybox_frag");
const vkinit = @import("vk_init.zig"); const vkinit = @import("vk_init.zig");

View File

@ -1,39 +1,39 @@
const std = @import("std"); const std = @import("std");
const core = @import("core"); const core = @import("core");
const vk_renderer = @import("vk_renderer.zig"); const vk_renderer = @import("vk_renderer.zig");
const vma = @import("vma"); const vma = @import("vma");
const vk = @import("vulkan"); const vk = @import("vulkan");
const vkinit = @import("vk_init.zig"); const vkinit = @import("vk_init.zig");
const NeonVkContext = vk_renderer.NeonVkContext; const NeonVkContext = vk_renderer.NeonVkContext;
const NeonVkBuffer = vk_renderer.NeonVkBuffer; const NeonVkBuffer = vk_renderer.NeonVkBuffer;
const NeonVkImage = vk_renderer.NeonVkImage; const NeonVkImage = vk_renderer.NeonVkImage;
pub const PixelPos = struct { pub const PixelPos = struct {
x: u32, x: u32,
y: u32, y: u32,
/// returns y/x of the pixel position /// returns y/x of the pixel position
pub fn ratio(self: @This()) f32 { pub fn ratio(self: @This()) f32 {
return @as(f32, @floatFromInt(self.y)) / @as(f32, @floatFromInt(self.x)); return @as(f32, @floatFromInt(self.y)) / @as(f32, @floatFromInt(self.x));
} }
}; };
// This is a simple display texture // This is a simple display texture
pub const Texture = struct { pub const Texture = struct {
image: NeonVkImage, image: NeonVkImage,
imageView: vk.ImageView, imageView: vk.ImageView,
isCube: bool = false, isCube: bool = false,
pub fn deinit(self: *@This(), ctx: *NeonVkContext) void { pub fn deinit(self: *@This(), ctx: *NeonVkContext) void {
ctx.vkd.destroyImageView(ctx.dev, self.imageView, null); ctx.vkd.destroyImageView(ctx.dev, self.imageView, null);
self.image.deinit(ctx.vkAllocator); self.image.deinit(ctx.vkAllocator);
} }
pub fn getDimensions(self: @This()) PixelPos { pub fn getDimensions(self: @This()) PixelPos {
return .{ return .{
.x = self.image.pixelWidth, .x = self.image.pixelWidth,
.y = self.image.pixelHeight, .y = self.image.pixelHeight,
}; };
} }
}; };

View File

@ -1,16 +1,16 @@
// global api // global api
// //
// i hate lugging these variables around. // i hate lugging these variables around.
// device and cmd buffers are fine, // device and cmd buffers are fine,
// but the dispatch variables are going to be kept here and easily accessible. // but the dispatch variables are going to be kept here and easily accessible.
pub var _vkb: constants.BaseDispatch = undefined; pub var _vkb: constants.BaseDispatch = undefined;
pub var _vki: constants.InstanceDispatch = undefined; pub var _vki: constants.InstanceDispatch = undefined;
pub var _vkd: constants.DeviceDispatch = undefined; pub var _vkd: constants.DeviceDispatch = undefined;
pub const vkb = &_vkb; pub const vkb = &_vkb;
pub const vki = &_vki; pub const vki = &_vki;
pub const vkd = &_vkd; pub const vkd = &_vkd;
const vk = @import("vulkan"); const vk = @import("vulkan");
const constants = @import("vk_constants.zig"); const constants = @import("vk_constants.zig");

View File

@ -1,373 +1,373 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const graphics = @import("graphics.zig"); const graphics = @import("graphics.zig");
const core = @import("core"); const core = @import("core");
const assets = @import("assets"); const assets = @import("assets");
const vk_utils = @import("vk_utils.zig"); const vk_utils = @import("vk_utils.zig");
const vkinit = @import("vk_init.zig"); const vkinit = @import("vk_init.zig");
const vk_cubemap = @import("vk_renderer/vk_cubemap.zig"); const vk_cubemap = @import("vk_renderer/vk_cubemap.zig");
const tracy = core.tracy; const tracy = core.tracy;
const materials = @import("materials.zig"); const materials = @import("materials.zig");
const vk_renderer = @import("vk_renderer.zig"); const vk_renderer = @import("vk_renderer.zig");
const mesh = @import("mesh.zig"); const mesh = @import("mesh.zig");
const texture = @import("texture.zig"); const texture = @import("texture.zig");
const NeonVkContext = vk_renderer.NeonVkContext; const NeonVkContext = vk_renderer.NeonVkContext;
const Material = materials.Material; const Material = materials.Material;
const Mesh = mesh.Mesh; const Mesh = mesh.Mesh;
const Texture = texture.Texture; const Texture = texture.Texture;
pub const TextureLoader = struct { pub const TextureLoader = struct {
pub var LoaderInterfaceVTable: assets.AssetLoaderInterface = assets.AssetLoaderInterface.from("Texture", @This()); pub var LoaderInterfaceVTable: assets.AssetLoaderInterface = assets.AssetLoaderInterface.from("Texture", @This());
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
const StagedTextureDescription = struct { const StagedTextureDescription = struct {
name: core.Name, name: core.Name,
stagingResults: vk_utils.LoadAndStageImage, stagingResults: vk_utils.LoadAndStageImage,
textureListResults: ?[]vk_utils.LoadAndStageImage = null, textureListResults: ?[]vk_utils.LoadAndStageImage = null,
assetRef: assets.AssetRef, assetRef: assets.AssetRef,
properties: assets.AssetPropertiesBag, properties: assets.AssetPropertiesBag,
pub fn deinit(self: *@This(), gc: *NeonVkContext) void { pub fn deinit(self: *@This(), gc: *NeonVkContext) void {
self.stagingResults.deinit(gc.vkAllocator); self.stagingResults.deinit(gc.vkAllocator);
if (self.textureListResults) |results| { if (self.textureListResults) |results| {
for (results) |*result| { for (results) |*result| {
result.deinit(gc.vkAllocator); result.deinit(gc.vkAllocator);
} }
} }
} }
}; };
const RTAssetsReady = struct { const RTAssetsReady = struct {
name: core.Name, name: core.Name,
texture: *Texture, texture: *Texture,
textureSet: vk.DescriptorSet, textureSet: vk.DescriptorSet,
textureId: u32, textureId: u32,
}; };
gc: *NeonVkContext, gc: *NeonVkContext,
assetsReady: core.RingQueue(StagedTextureDescription), assetsReady: core.RingQueue(StagedTextureDescription),
rtAssetsReady: core.RingQueue(RTAssetsReady), rtAssetsReady: core.RingQueue(RTAssetsReady),
discarding: std.atomic.Value(bool) = std.atomic.Value(bool).init(false), discarding: std.atomic.Value(bool) = std.atomic.Value(bool).init(false),
pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, props: ?assets.AssetPropertiesBag) assets.AssetLoaderError!void { pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, props: ?assets.AssetPropertiesBag) assets.AssetLoaderError!void {
if (self.discarding.load(.seq_cst)) { if (self.discarding.load(.seq_cst)) {
return; return;
} }
var z = tracy.ZoneN(@src(), "TextureLoader loadAsset"); var z = tracy.ZoneN(@src(), "TextureLoader loadAsset");
const Lambda = struct { const Lambda = struct {
loader: *TextureLoader, loader: *TextureLoader,
assetRef: assets.AssetRef, assetRef: assets.AssetRef,
gc: *NeonVkContext, gc: *NeonVkContext,
properties: assets.AssetPropertiesBag, properties: assets.AssetPropertiesBag,
pub fn eFunc(ctx: @This()) !void { pub fn eFunc(ctx: @This()) !void {
var z1 = tracy.ZoneN(@src(), "Loading file from TextureLoader"); var z1 = tracy.ZoneN(@src(), "Loading file from TextureLoader");
const gc = ctx.gc; const gc = ctx.gc;
defer { defer {
_ = ctx.gc.outstandingJobsCount.fetchSub(1, .seq_cst); _ = ctx.gc.outstandingJobsCount.fetchSub(1, .seq_cst);
} }
var loadAndStageResults: vk_utils.LoadAndStageImage = undefined; var loadAndStageResults: vk_utils.LoadAndStageImage = undefined;
if (!ctx.properties.textureCube) { if (!ctx.properties.textureCube) {
loadAndStageResults = try vk_utils.load_and_stage_image_from_file(gc, ctx.properties.path); loadAndStageResults = try vk_utils.load_and_stage_image_from_file(gc, ctx.properties.path);
errdefer loadAndStageResults.deinit(gc.vkAllocator); errdefer loadAndStageResults.deinit(gc.vkAllocator);
} else { } else {
loadAndStageResults = try vk_cubemap.stageCubeTexture(ctx.properties.textureList.?); loadAndStageResults = try vk_cubemap.stageCubeTexture(ctx.properties.textureList.?);
errdefer loadAndStageResults.deinit(gc.vkAllocator); errdefer loadAndStageResults.deinit(gc.vkAllocator);
} }
var assetRefName = ctx.assetRef.name; var assetRefName = ctx.assetRef.name;
tracy.Message(assetRefName.utf8()); tracy.Message(assetRefName.utf8());
tracy.Message(ctx.properties.path); tracy.Message(ctx.properties.path);
core.engine_log("loaded: {s} from: {s}", .{ assetRefName.utf8(), ctx.properties.path }); core.engine_log("loaded: {s} from: {s}", .{ assetRefName.utf8(), ctx.properties.path });
var loadedDescription = StagedTextureDescription{ var loadedDescription = StagedTextureDescription{
.name = ctx.assetRef.name, .name = ctx.assetRef.name,
.stagingResults = loadAndStageResults, .stagingResults = loadAndStageResults,
.assetRef = ctx.assetRef, .assetRef = ctx.assetRef,
.properties = ctx.properties, .properties = ctx.properties,
}; };
if (ctx.properties.textureList) |textureList| { if (ctx.properties.textureList) |textureList| {
const tlResults = try ctx.gc.allocator.alloc(vk_utils.LoadAndStageImage, textureList.len); const tlResults = try ctx.gc.allocator.alloc(vk_utils.LoadAndStageImage, textureList.len);
errdefer ctx.gc.allocator.free(tlResults); errdefer ctx.gc.allocator.free(tlResults);
for (textureList, 0..) |tPath, i| { for (textureList, 0..) |tPath, i| {
const rv = vk_utils.load_and_stage_image_from_file(gc, tPath) catch { const rv = vk_utils.load_and_stage_image_from_file(gc, tPath) catch {
core.engine_log("unable to load file {s}", .{tPath}); core.engine_log("unable to load file {s}", .{tPath});
return error.FailedToLoad; return error.FailedToLoad;
}; };
errdefer rv.deinit(); errdefer rv.deinit();
tlResults[i] = rv; tlResults[i] = rv;
} }
loadedDescription.textureListResults = tlResults; loadedDescription.textureListResults = tlResults;
} }
z1.End(); z1.End();
ctx.loader.assetsReady.pushLocked(loadedDescription) catch unreachable; ctx.loader.assetsReady.pushLocked(loadedDescription) catch unreachable;
} }
pub fn func(ctx: @This(), _: *core.JobContext) void { pub fn func(ctx: @This(), _: *core.JobContext) void {
ctx.eFunc() catch unreachable; ctx.eFunc() catch unreachable;
} }
}; };
_ = self.gc.outstandingJobsCount.fetchAdd(1, .seq_cst); _ = self.gc.outstandingJobsCount.fetchAdd(1, .seq_cst);
core.dispatchJob(Lambda{ core.dispatchJob(Lambda{
.loader = self, .loader = self,
.gc = self.gc, .gc = self.gc,
.assetRef = assetRef, .assetRef = assetRef,
.properties = props.?, .properties = props.?,
}) catch return error.UnableToLoad; }) catch return error.UnableToLoad;
z.End(); z.End();
} }
pub fn processRenderThreadEvents(ptr: *anyopaque) void { pub fn processRenderThreadEvents(ptr: *anyopaque) void {
const self: *@This() = @ptrCast(@alignCast(ptr)); const self: *@This() = @ptrCast(@alignCast(ptr));
self.processEventInner() catch {}; self.processEventInner() catch {};
} }
pub fn createImageFromStagingResult(self: *@This(), name: core.Name, stagingResults: *vk_utils.LoadAndStageImage, properties: assets.AssetPropertiesBag) core.EngineDataEventError!void { pub fn createImageFromStagingResult(self: *@This(), name: core.Name, stagingResults: *vk_utils.LoadAndStageImage, properties: assets.AssetPropertiesBag) core.EngineDataEventError!void {
const gc = self.gc; const gc = self.gc;
var stagingBuffer = stagingResults.stagingBuffer; var stagingBuffer = stagingResults.stagingBuffer;
const image = stagingResults.image; const image = stagingResults.image;
if (stagingResults.cubeOffsets != null) { if (stagingResults.cubeOffsets != null) {
vk_cubemap.submitTextureCube(&gc.uploader, stagingResults) catch return error.UnknownStatePanic; vk_cubemap.submitTextureCube(&gc.uploader, stagingResults) catch return error.UnknownStatePanic;
stagingBuffer.deinit(gc.vkAllocator); stagingBuffer.deinit(gc.vkAllocator);
var ivc = vkinit.imageViewCreateInfo( var ivc = vkinit.imageViewCreateInfo(
.r8g8b8a8_srgb, .r8g8b8a8_srgb,
image.image, image.image,
.{ .color_bit = true }, .{ .color_bit = true },
stagingResults.mipLevel, stagingResults.mipLevel,
); );
ivc.view_type = .cube; ivc.view_type = .cube;
ivc.subresource_range.layer_count = 6; ivc.subresource_range.layer_count = 6;
const imageView = gc.vkd.createImageView(gc.dev, &ivc, null) catch return error.UnknownStatePanic; const imageView = gc.vkd.createImageView(gc.dev, &ivc, null) catch return error.UnknownStatePanic;
const newTexture = gc.allocator.create(Texture) catch return error.UnknownStatePanic; const newTexture = gc.allocator.create(Texture) catch return error.UnknownStatePanic;
newTexture.* = Texture{ newTexture.* = Texture{
.image = image, .image = image,
.imageView = imageView, .imageView = imageView,
}; };
const rv = vk_utils.createDescriptorSetForImage( const rv = vk_utils.createDescriptorSetForImage(
gc.dev, gc.dev,
gc.descriptorPool, gc.descriptorPool,
gc.singleTextureSetLayout, gc.singleTextureSetLayout,
imageView, imageView,
gc.cubeSampler, gc.cubeSampler,
false, false,
) catch return error.UnknownStatePanic; ) catch return error.UnknownStatePanic;
self.rtAssetsReady.pushLocked(.{ self.rtAssetsReady.pushLocked(.{
.name = name, .name = name,
.texture = newTexture, .texture = newTexture,
.textureSet = rv.textureSet, .textureSet = rv.textureSet,
.textureId = rv.textureId, .textureId = rv.textureId,
}) catch return error.UnknownStatePanic; }) catch return error.UnknownStatePanic;
} else { } else {
vk_utils.submit_copy_from_staging(gc, stagingBuffer, image, stagingResults.mipLevel) catch return error.UnknownStatePanic; vk_utils.submit_copy_from_staging(gc, stagingBuffer, image, stagingResults.mipLevel) catch return error.UnknownStatePanic;
stagingBuffer.deinit(gc.vkAllocator); stagingBuffer.deinit(gc.vkAllocator);
var imageViewCreate = vkinit.imageViewCreateInfo( var imageViewCreate = vkinit.imageViewCreateInfo(
.r8g8b8a8_srgb, .r8g8b8a8_srgb,
image.image, image.image,
.{ .color_bit = true }, .{ .color_bit = true },
stagingResults.mipLevel, stagingResults.mipLevel,
); );
const imageView = gc.vkd.createImageView(gc.dev, &imageViewCreate, null) catch return error.UnknownStatePanic; const imageView = gc.vkd.createImageView(gc.dev, &imageViewCreate, null) catch return error.UnknownStatePanic;
const newTexture = gc.allocator.create(Texture) catch return error.UnknownStatePanic; const newTexture = gc.allocator.create(Texture) catch return error.UnknownStatePanic;
newTexture.* = Texture{ newTexture.* = Texture{
.image = image, .image = image,
.imageView = imageView, .imageView = imageView,
}; };
const sampler = if (properties.textureUseBlockySampler) gc.blockySampler else gc.linearSampler; const sampler = if (properties.textureUseBlockySampler) gc.blockySampler else gc.linearSampler;
const rv = vk_utils.createDescriptorSetForImage( const rv = vk_utils.createDescriptorSetForImage(
gc.dev, gc.dev,
gc.descriptorPool, gc.descriptorPool,
gc.singleTextureSetLayout, gc.singleTextureSetLayout,
imageView, imageView,
sampler, sampler,
true, true,
) catch return error.UnknownStatePanic; ) catch return error.UnknownStatePanic;
self.rtAssetsReady.pushLocked(.{ self.rtAssetsReady.pushLocked(.{
.name = name, .name = name,
.texture = newTexture, .texture = newTexture,
.textureSet = rv.textureSet, .textureSet = rv.textureSet,
.textureId = rv.textureId, .textureId = rv.textureId,
}) catch return error.UnknownStatePanic; }) catch return error.UnknownStatePanic;
} }
} }
fn processEventInner(self: *@This()) core.EngineDataEventError!void { fn processEventInner(self: *@This()) core.EngineDataEventError!void {
if (self.assetsReady.count() > 0) { if (self.assetsReady.count() > 0) {
self.assetsReady.lock(); self.assetsReady.lock();
defer self.assetsReady.unlock(); defer self.assetsReady.unlock();
while (self.assetsReady.popFromUnlocked()) |ar| { while (self.assetsReady.popFromUnlocked()) |ar| {
var assetReady = ar; var assetReady = ar;
var z1 = tracy.ZoneN(@src(), "Uploading asset loaded by TextureLoader"); var z1 = tracy.ZoneN(@src(), "Uploading asset loaded by TextureLoader");
tracy.Message("TextureLoader"); tracy.Message("TextureLoader");
tracy.Message(assetReady.assetRef.name.utf8()); tracy.Message(assetReady.assetRef.name.utf8());
tracy.Message(assetReady.properties.path); tracy.Message(assetReady.properties.path);
core.engine_log("async texture load complete registry: {s}", .{assetReady.name.utf8()}); core.engine_log("async texture load complete registry: {s}", .{assetReady.name.utf8()});
try self.createImageFromStagingResult(assetReady.name, &assetReady.stagingResults, assetReady.properties); try self.createImageFromStagingResult(assetReady.name, &assetReady.stagingResults, assetReady.properties);
if (assetReady.textureListResults) |results| { if (assetReady.textureListResults) |results| {
var buf: [256]u8 = undefined; var buf: [256]u8 = undefined;
for (results, 0..) |res, i| { for (results, 0..) |res, i| {
var r = res; var r = res;
var arName = assetReady.name; var arName = assetReady.name;
const newName = std.fmt.bufPrint(&buf, "{s}[{d}]", .{ arName.utf8(), i }) catch return core.EngineDataEventError.OutOfMemory; const newName = std.fmt.bufPrint(&buf, "{s}[{d}]", .{ arName.utf8(), i }) catch return core.EngineDataEventError.OutOfMemory;
try self.createImageFromStagingResult(core.MakeName(newName), &r, assetReady.properties); try self.createImageFromStagingResult(core.MakeName(newName), &r, assetReady.properties);
} }
self.gc.allocator.free(results); self.gc.allocator.free(results);
} }
z1.End(); z1.End();
} }
} }
} }
// processing events, some should really be processing events rather than // processing events, some should really be processing events rather than
pub fn processEvents(self: *@This(), frameNumber: u64) core.EngineDataEventError!void { pub fn processEvents(self: *@This(), frameNumber: u64) core.EngineDataEventError!void {
_ = frameNumber; _ = frameNumber;
if (self.rtAssetsReady.count() > 0) { if (self.rtAssetsReady.count() > 0) {
self.rtAssetsReady.lock(); self.rtAssetsReady.lock();
defer self.rtAssetsReady.unlock(); defer self.rtAssetsReady.unlock();
while (self.rtAssetsReady.popFromUnlocked()) |a| { while (self.rtAssetsReady.popFromUnlocked()) |a| {
self.gc.install_texture_into_registry(a.name, a.texture, a.textureSet, a.textureId) catch return error.UnknownStatePanic; self.gc.install_texture_into_registry(a.name, a.texture, a.textureSet, a.textureId) catch return error.UnknownStatePanic;
} }
} }
} }
pub fn discardAll(self: *@This()) void { pub fn discardAll(self: *@This()) void {
self.discarding.store(true, .seq_cst); self.discarding.store(true, .seq_cst);
core.graphics_log("discarding {d} outstanding jobs", .{self.assetsReady.count()}); core.graphics_log("discarding {d} outstanding jobs", .{self.assetsReady.count()});
self.assetsReady.lock(); self.assetsReady.lock();
defer self.assetsReady.unlock(); defer self.assetsReady.unlock();
while (self.assetsReady.popFromUnlocked()) |assetReady| { while (self.assetsReady.popFromUnlocked()) |assetReady| {
var copy = assetReady; var copy = assetReady;
StagedTextureDescription.deinit(&copy, self.gc); StagedTextureDescription.deinit(&copy, self.gc);
} }
} }
pub fn init(allocator: std.mem.Allocator) !*@This() { pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This()); const self = try allocator.create(@This());
self.* = .{ self.* = .{
.gc = vk_renderer.gContext, .gc = vk_renderer.gContext,
//todo: the EngineObjectVTable init function should have a handleable error //todo: the EngineObjectVTable init function should have a handleable error
.assetsReady = core.RingQueue(StagedTextureDescription).init(allocator, 1024) catch unreachable, .assetsReady = core.RingQueue(StagedTextureDescription).init(allocator, 1024) catch unreachable,
.rtAssetsReady = core.RingQueue(RTAssetsReady).init(allocator, 1024) catch unreachable, .rtAssetsReady = core.RingQueue(RTAssetsReady).init(allocator, 1024) catch unreachable,
}; };
try self.gc.renderthread.installListener(self, processRenderThreadEvents); try self.gc.renderthread.installListener(self, processRenderThreadEvents);
return self; return self;
} }
pub fn destroy(self: *@This(), allocator: std.mem.Allocator) void { pub fn destroy(self: *@This(), allocator: std.mem.Allocator) void {
self.assetsReady.deinit(); self.assetsReady.deinit();
self.rtAssetsReady.deinit(); self.rtAssetsReady.deinit();
allocator.destroy(self); allocator.destroy(self);
} }
}; };
pub const MeshLoader = struct { pub const MeshLoader = struct {
pub var LoaderInterfaceVTable = assets.AssetLoaderInterface.from("Mesh", @This()); pub var LoaderInterfaceVTable = assets.AssetLoaderInterface.from("Mesh", @This());
pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This());
gc: *NeonVkContext, gc: *NeonVkContext,
pub fn init(allocator: std.mem.Allocator) !*@This() { pub fn init(allocator: std.mem.Allocator) !*@This() {
const self = try allocator.create(@This()); const self = try allocator.create(@This());
self.* = .{ self.* = .{
.gc = vk_renderer.gContext, .gc = vk_renderer.gContext,
}; };
return self; return self;
} }
pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, propertiesBag: ?assets.AssetPropertiesBag) assets.AssetLoaderError!void { pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, propertiesBag: ?assets.AssetPropertiesBag) assets.AssetLoaderError!void {
_ = self; _ = self;
const sourceType = getSourceType(propertiesBag); const sourceType = getSourceType(propertiesBag);
core.engine_log("loading mesh asset {s} [{s}]", .{ propertiesBag.?.path, if (sourceType) |s| @tagName(s) else "default" }); core.engine_log("loading mesh asset {s} [{s}]", .{ propertiesBag.?.path, if (sourceType) |s| @tagName(s) else "default" });
graphics.loadIndexedMeshForPooling(assetRef.name, .{ graphics.loadIndexedMeshForPooling(assetRef.name, .{
.path = propertiesBag.?.path, .path = propertiesBag.?.path,
.sourceType = getSourceType(propertiesBag), .sourceType = getSourceType(propertiesBag),
.skeletonName = if (propertiesBag.?.skeletonName) |skName| core.MakeName(skName) else null, .skeletonName = if (propertiesBag.?.skeletonName) |skName| core.MakeName(skName) else null,
}) catch return error.UnableToLoad; }) catch return error.UnableToLoad;
} }
fn getSourceType(propertiesBag: ?assets.AssetPropertiesBag) ?graphics.MeshSourceType { fn getSourceType(propertiesBag: ?assets.AssetPropertiesBag) ?graphics.MeshSourceType {
if (propertiesBag) |bag| { if (propertiesBag) |bag| {
if (bag.meshType) |meshType| { if (bag.meshType) |meshType| {
if (std.mem.eql(u8, meshType, "obj")) { if (std.mem.eql(u8, meshType, "obj")) {
return graphics.MeshSourceType.obj; return graphics.MeshSourceType.obj;
} }
if (std.mem.eql(u8, meshType, "gltf")) { if (std.mem.eql(u8, meshType, "gltf")) {
return graphics.MeshSourceType.gltf; return graphics.MeshSourceType.gltf;
} }
} }
// try to deduce it by file name, if nothing is set. // try to deduce it by file name, if nothing is set.
const ext = core.getFileExtension(bag.path); const ext = core.getFileExtension(bag.path);
if (std.mem.eql(u8, ext, ".obj")) { if (std.mem.eql(u8, ext, ".obj")) {
return graphics.MeshSourceType.obj; return graphics.MeshSourceType.obj;
} }
if (std.mem.eql(u8, ext, ".gltf")) { if (std.mem.eql(u8, ext, ".gltf")) {
return graphics.MeshSourceType.gltf; return graphics.MeshSourceType.gltf;
} }
if (std.mem.eql(u8, ext, ".glb")) { if (std.mem.eql(u8, ext, ".glb")) {
return graphics.MeshSourceType.gltf; return graphics.MeshSourceType.gltf;
} }
} }
return null; return null;
} }
pub fn discardAll(self: *@This()) void { pub fn discardAll(self: *@This()) void {
// totally synchronous, nothing to do for a discard // totally synchronous, nothing to do for a discard
_ = self; _ = self;
} }
pub fn destroy(self: *@This(), allocator: std.mem.Allocator) void { pub fn destroy(self: *@This(), allocator: std.mem.Allocator) void {
allocator.destroy(self); allocator.destroy(self);
} }
}; };
pub var gTextureLoader: *TextureLoader = undefined; pub var gTextureLoader: *TextureLoader = undefined;
pub var gMeshLoader: *MeshLoader = undefined; pub var gMeshLoader: *MeshLoader = undefined;
pub fn init_loaders(allocator: std.mem.Allocator) !void { pub fn init_loaders(allocator: std.mem.Allocator) !void {
gTextureLoader = try core.createObject(TextureLoader, .{ gTextureLoader = try core.createObject(TextureLoader, .{
.responds_to_events = true, .responds_to_events = true,
}); });
gMeshLoader = try allocator.create(MeshLoader); gMeshLoader = try allocator.create(MeshLoader);
gMeshLoader.* = .{ .gc = vk_renderer.gContext }; gMeshLoader.* = .{ .gc = vk_renderer.gContext };
try assets.gAssetSys.registerLoader(gTextureLoader); try assets.gAssetSys.registerLoader(gTextureLoader);
try assets.gAssetSys.registerLoader(gMeshLoader); try assets.gAssetSys.registerLoader(gMeshLoader);
} }
// submit an abort message to TextureLoader and MeshLoader // submit an abort message to TextureLoader and MeshLoader
pub fn discardAll() void { pub fn discardAll() void {
gTextureLoader.discardAll(); gTextureLoader.discardAll();
gMeshLoader.discardAll(); gMeshLoader.discardAll();
} }

View File

@ -1,25 +1,25 @@
// higher level descriptor and SSBO wrangling libraries. // higher level descriptor and SSBO wrangling libraries.
const std = @import("std"); const std = @import("std");
const core = @import("core"); const core = @import("core");
const vk_renderer = @import("vk_renderer.zig"); const vk_renderer = @import("vk_renderer.zig");
const vma = @import("vma"); const vma = @import("vma");
const vk = @import("vulkan"); const vk = @import("vulkan");
const obj_loader = @import("objLoader"); const obj_loader = @import("objLoader");
const vkinit = @import("vk_init.zig"); const vkinit = @import("vk_init.zig");
const vk_constants = @import("vk_constants.zig"); const vk_constants = @import("vk_constants.zig");
const tracy = core.tracy; const tracy = core.tracy;
const spng = core.spng; const spng = core.spng;
const ObjMesh = obj_loader.ObjMesh; const ObjMesh = obj_loader.ObjMesh;
const ArrayList = std.ArrayList; const ArrayList = std.ArrayList;
const Vectorf = core.Vectorf; const Vectorf = core.Vectorf;
const NeonVkContext = vk_renderer.NeonVkContext; const NeonVkContext = vk_renderer.NeonVkContext;
const NeonVkBuffer = vk_renderer.NeonVkBuffer; const NeonVkBuffer = vk_renderer.NeonVkBuffer;
const NeonVkImage = vk_renderer.NeonVkImage; const NeonVkImage = vk_renderer.NeonVkImage;
const NumFrames = vk_constants.NUM_FRAMES; const NumFrames = vk_constants.NUM_FRAMES;
pub const DescriptorSetLayoutInfo = struct { pub const DescriptorSetLayoutInfo = struct {
bindingCount: u32, bindingCount: u32,
}; };

View File

@ -1,435 +1,435 @@
const std = @import("std"); const std = @import("std");
const core = @import("core"); const core = @import("core");
const vk_renderer = @import("vk_renderer.zig"); const vk_renderer = @import("vk_renderer.zig");
const vma = @import("vma"); const vma = @import("vma");
const vk = @import("vulkan"); const vk = @import("vulkan");
const obj_loader = @import("objLoader"); const obj_loader = @import("objLoader");
const constants = @import("vk_constants.zig"); const constants = @import("vk_constants.zig");
const vk_utils = @import("vk_utils.zig"); const vk_utils = @import("vk_utils.zig");
const NeonVkUploader = vk_utils.NeonVkUploader; const NeonVkUploader = vk_utils.NeonVkUploader;
const NeonVkBuffer = vk_renderer.NeonVkBuffer; const NeonVkBuffer = vk_renderer.NeonVkBuffer;
const ObjMesh = obj_loader.ObjMesh; const ObjMesh = obj_loader.ObjMesh;
const ArrayList = std.ArrayList; const ArrayList = std.ArrayList;
const Vectorf = core.Vectorf; const Vectorf = core.Vectorf;
const Vector2f = core.Vector2f; const Vector2f = core.Vector2f;
const LinearColor = core.colors.Color; const LinearColor = core.colors.Color;
const NeonVkContext = vk_renderer.NeonVkContext; const NeonVkContext = vk_renderer.NeonVkContext;
const mesh = @import("mesh.zig"); const mesh = @import("mesh.zig");
const MeshVertex = mesh.MeshVertex; const MeshVertex = mesh.MeshVertex;
const debug_struct = core.debug_struct; const debug_struct = core.debug_struct;
pub const DynamicMeshManager = struct { pub const DynamicMeshManager = struct {
gc: *NeonVkContext, gc: *NeonVkContext,
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
dynMeshes: std.ArrayListUnmanaged(*DynamicMesh) = .{}, dynMeshes: std.ArrayListUnmanaged(*DynamicMesh) = .{},
uploader: NeonVkUploader, uploader: NeonVkUploader,
first: bool = true, first: bool = true,
pub fn init(gc: *NeonVkContext) !*@This() { pub fn init(gc: *NeonVkContext) !*@This() {
const self = try gc.allocator.create(@This()); const self = try gc.allocator.create(@This());
self.* = @This(){ self.* = @This(){
.gc = gc, .gc = gc,
.allocator = gc.allocator, .allocator = gc.allocator,
.uploader = try NeonVkUploader.init(gc, "dynamic mesh manager uploader"), .uploader = try NeonVkUploader.init(gc, "dynamic mesh manager uploader"),
}; };
// core.graphics_log("creating the mesh manager", .{}); // core.graphics_log("creating the mesh manager", .{});
return self; return self;
} }
pub fn deinit(self: *@This()) void { pub fn deinit(self: *@This()) void {
self.uploader.deinit(); self.uploader.deinit();
self.dynMeshes.deinit(self.allocator); self.dynMeshes.deinit(self.allocator);
self.allocator.destroy(self); self.allocator.destroy(self);
} }
pub fn addDynamicMesh(self: *@This(), dynamicMesh: *DynamicMesh) !void { pub fn addDynamicMesh(self: *@This(), dynamicMesh: *DynamicMesh) !void {
try self.dynMeshes.append(self.allocator, dynamicMesh); try self.dynMeshes.append(self.allocator, dynamicMesh);
} }
pub fn updateMeshes(self: *@This(), cmd: vk.CommandBuffer) !void { pub fn updateMeshes(self: *@This(), cmd: vk.CommandBuffer) !void {
for (self.dynMeshes.items) |dynMesh| { for (self.dynMeshes.items) |dynMesh| {
try dynMesh.maybeUpdateVertices(cmd); try dynMesh.maybeUpdateVertices(cmd);
} }
} }
pub fn finishUpload(self: *@This()) !void { pub fn finishUpload(self: *@This()) !void {
if (self.uploader.isActive) { if (self.uploader.isActive) {
var t3 = core.tracy.ZoneN(@src(), "finishing dynamic mesh upload context"); var t3 = core.tracy.ZoneN(@src(), "finishing dynamic mesh upload context");
defer t3.End(); defer t3.End();
try self.uploader.waitForFences(); try self.uploader.waitForFences();
for (self.dynMeshes.items) |dynMesh| { for (self.dynMeshes.items) |dynMesh| {
if (dynMesh.isDirty) { if (dynMesh.isDirty) {
dynMesh.bumpSwapId(); dynMesh.bumpSwapId();
} }
} }
} }
} }
}; };
pub const DynamicMesh = struct { pub const DynamicMesh = struct {
pub const GeometryMode = enum { quads, triangles }; pub const GeometryMode = enum { quads, triangles };
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
gc: *NeonVkContext, gc: *NeonVkContext,
vertices: []MeshVertex = undefined, vertices: []MeshVertex = undefined,
geometryMode: GeometryMode = .quads, // geometry elaboration mode geometryMode: GeometryMode = .quads, // geometry elaboration mode
indicesMaxCount: u32 = 0, indicesMaxCount: u32 = 0,
indexBuffers: [2]NeonVkBuffer = undefined, indexBuffers: [2]NeonVkBuffer = undefined,
indexBufferLen: [2]u32 = .{ 0, 0 }, indexBufferLen: [2]u32 = .{ 0, 0 },
vertexBuffers: [2]NeonVkBuffer = undefined, vertexBuffers: [2]NeonVkBuffer = undefined,
vertexBufferLen: [2]u32 = .{ 0, 0 }, vertexBufferLen: [2]u32 = .{ 0, 0 },
swapId: usize = 0, // the index of the previously uploaded vertex buffer swapId: usize = 0, // the index of the previously uploaded vertex buffer
vertexCount: u32 = 0, // vertexCount: u32 = 0, //
stagingVertexBuffer: NeonVkBuffer = undefined, stagingVertexBuffer: NeonVkBuffer = undefined,
stagingIndexBuffer: NeonVkBuffer = undefined, stagingIndexBuffer: NeonVkBuffer = undefined,
isDirty: bool = true, isDirty: bool = true,
maxVertexCount: u32, maxVertexCount: u32,
pub fn init(gc: *NeonVkContext, allocator: std.mem.Allocator, opts: struct { pub fn init(gc: *NeonVkContext, allocator: std.mem.Allocator, opts: struct {
maxVertexCount: u32 = 4096, maxVertexCount: u32 = 4096,
maxIndexCount: u32 = 4096 * 6 / 4, maxIndexCount: u32 = 4096 * 6 / 4,
mode: GeometryMode = .quads, mode: GeometryMode = .quads,
}) !*@This() { }) !*@This() {
var self = try allocator.create(@This()); var self = try allocator.create(@This());
self.* = .{ self.* = .{
.maxVertexCount = opts.maxVertexCount, .maxVertexCount = opts.maxVertexCount,
.allocator = allocator, .allocator = allocator,
.vertices = try allocator.alloc(MeshVertex, opts.maxVertexCount), .vertices = try allocator.alloc(MeshVertex, opts.maxVertexCount),
.gc = gc, .gc = gc,
.geometryMode = opts.mode, .geometryMode = opts.mode,
}; };
try gc.dynamicMeshManager.addDynamicMesh(self); try gc.dynamicMeshManager.addDynamicMesh(self);
self.allocator = allocator; self.allocator = allocator;
self.gc = gc; self.gc = gc;
{ {
self.stagingIndexBuffer = try gc.vkAllocator.createStagingBuffer(opts.maxIndexCount * @sizeOf(u32), "DynamicMesh.init - index staging"); self.stagingIndexBuffer = try gc.vkAllocator.createStagingBuffer(opts.maxIndexCount * @sizeOf(u32), "DynamicMesh.init - index staging");
self.stagingVertexBuffer = try gc.vkAllocator.createStagingBuffer(opts.maxVertexCount * @sizeOf(MeshVertex), "DynamicMesh.init - vertex staging"); self.stagingVertexBuffer = try gc.vkAllocator.createStagingBuffer(opts.maxVertexCount * @sizeOf(MeshVertex), "DynamicMesh.init - vertex staging");
inline for (0..2) |i| { inline for (0..2) |i| {
self.indexBuffers[i] = try gc.vkAllocator.createGpuBuffer(opts.maxIndexCount * @sizeOf(u32), .{ self.indexBuffers[i] = try gc.vkAllocator.createGpuBuffer(opts.maxIndexCount * @sizeOf(u32), .{
.index_buffer_bit = true, .index_buffer_bit = true,
}, "DynamicMesh.init - gpu indexBuffer" ++ std.fmt.comptimePrint("[{d}]", .{i})); }, "DynamicMesh.init - gpu indexBuffer" ++ std.fmt.comptimePrint("[{d}]", .{i}));
self.vertexBuffers[i] = try gc.vkAllocator.createGpuBuffer(opts.maxVertexCount * @sizeOf(MeshVertex), .{ self.vertexBuffers[i] = try gc.vkAllocator.createGpuBuffer(opts.maxVertexCount * @sizeOf(MeshVertex), .{
.vertex_buffer_bit = true, .vertex_buffer_bit = true,
}, "DynamicMesh.init - gpu vertexBuffer" ++ std.fmt.comptimePrint("[{d}]", .{i})); }, "DynamicMesh.init - gpu vertexBuffer" ++ std.fmt.comptimePrint("[{d}]", .{i}));
} }
} }
return self; return self;
} }
pub fn getIndexBuffer(self: *@This()) NeonVkBuffer { pub fn getIndexBuffer(self: *@This()) NeonVkBuffer {
return self.indexBuffers[self.swapId]; return self.indexBuffers[self.swapId];
} }
pub fn getVertexBuffer(self: *@This()) NeonVkBuffer { pub fn getVertexBuffer(self: *@This()) NeonVkBuffer {
return self.vertexBuffers[self.swapId]; return self.vertexBuffers[self.swapId];
} }
pub fn getIndexBufferLen(self: *@This()) u32 { pub fn getIndexBufferLen(self: *@This()) u32 {
return self.indexBufferLen[self.swapId]; return self.indexBufferLen[self.swapId];
} }
pub fn getVertexBufferLen(self: *@This()) u32 { pub fn getVertexBufferLen(self: *@This()) u32 {
return self.vertexBufferLen[self.swapId]; return self.vertexBufferLen[self.swapId];
} }
pub fn maybeUpdateVertices(self: *@This(), cmd: vk.CommandBuffer) !void { pub fn maybeUpdateVertices(self: *@This(), cmd: vk.CommandBuffer) !void {
if (!self.isDirty) { if (!self.isDirty) {
return; return;
} }
var t1 = core.tracy.ZoneN(@src(), "Dynamic Mesh upload with barriers"); var t1 = core.tracy.ZoneN(@src(), "Dynamic Mesh upload with barriers");
defer t1.End(); defer t1.End();
self.isDirty = false; self.isDirty = false;
try self.stageDirtyVertices(); try self.stageDirtyVertices();
if (self.indexBufferLen[self.swapId] == 0 or self.vertexCount == 0) { if (self.indexBufferLen[self.swapId] == 0 or self.vertexCount == 0) {
return; return;
} }
var vkd = self.gc.vkd; var vkd = self.gc.vkd;
var copy = vk.BufferCopy{ var copy = vk.BufferCopy{
.dst_offset = 0, .dst_offset = 0,
.src_offset = 0, .src_offset = 0,
.size = self.indexBufferLen[self.swapId] * @as(u32, @intCast(@sizeOf(u32))), .size = self.indexBufferLen[self.swapId] * @as(u32, @intCast(@sizeOf(u32))),
}; };
// submit index Buffer // submit index Buffer
self.gc.vkd.cmdCopyBuffer( self.gc.vkd.cmdCopyBuffer(
cmd, cmd,
self.stagingIndexBuffer.buffer, self.stagingIndexBuffer.buffer,
self.indexBuffers[self.swapId].buffer, self.indexBuffers[self.swapId].buffer,
1, 1,
@as([*]const vk.BufferCopy, @ptrCast(&copy)), @as([*]const vk.BufferCopy, @ptrCast(&copy)),
); );
var indexMemoryBarrier = vk.BufferMemoryBarrier{ var indexMemoryBarrier = vk.BufferMemoryBarrier{
.buffer = self.indexBuffers[self.swapId].buffer, .buffer = self.indexBuffers[self.swapId].buffer,
.src_access_mask = .{ .transfer_read_bit = true }, .src_access_mask = .{ .transfer_read_bit = true },
.dst_access_mask = .{ .index_read_bit = true }, .dst_access_mask = .{ .index_read_bit = true },
.src_queue_family_index = 0, .src_queue_family_index = 0,
.dst_queue_family_index = 0, .dst_queue_family_index = 0,
.offset = 0, .offset = 0,
.size = copy.size, .size = copy.size,
}; };
// Insert Barrier for indexBuffer // Insert Barrier for indexBuffer
vkd.cmdPipelineBarrier( vkd.cmdPipelineBarrier(
cmd, cmd,
.{ .transfer_bit = true }, .{ .transfer_bit = true },
.{ .vertex_input_bit = true }, .{ .vertex_input_bit = true },
.{}, .{},
0, 0,
undefined, undefined,
1, 1,
@ptrCast(&indexMemoryBarrier), @ptrCast(&indexMemoryBarrier),
0, 0,
undefined, undefined,
); );
copy.size = self.vertexCount * @as(u32, @intCast(@sizeOf(MeshVertex))); copy.size = self.vertexCount * @as(u32, @intCast(@sizeOf(MeshVertex)));
// submit vertex Buffer // submit vertex Buffer
self.gc.vkd.cmdCopyBuffer( self.gc.vkd.cmdCopyBuffer(
cmd, cmd,
self.stagingVertexBuffer.buffer, self.stagingVertexBuffer.buffer,
self.vertexBuffers[self.swapId].buffer, self.vertexBuffers[self.swapId].buffer,
1, 1,
@as([*]const vk.BufferCopy, @ptrCast(&copy)), @as([*]const vk.BufferCopy, @ptrCast(&copy)),
); );
// Insert Barrier for vertexBuffer // Insert Barrier for vertexBuffer
var vertexMemoryBarrier = vk.BufferMemoryBarrier{ var vertexMemoryBarrier = vk.BufferMemoryBarrier{
.buffer = self.vertexBuffers[self.swapId].buffer, .buffer = self.vertexBuffers[self.swapId].buffer,
.src_access_mask = .{ .src_access_mask = .{
.transfer_read_bit = true, .transfer_read_bit = true,
}, },
.dst_access_mask = .{ .dst_access_mask = .{
// .transfer_write_bit = true, // .transfer_write_bit = true,
.vertex_attribute_read_bit = true, .vertex_attribute_read_bit = true,
}, },
.src_queue_family_index = 0, .src_queue_family_index = 0,
.dst_queue_family_index = 0, .dst_queue_family_index = 0,
.offset = 0, .offset = 0,
.size = copy.size, .size = copy.size,
}; };
vkd.cmdPipelineBarrier( vkd.cmdPipelineBarrier(
cmd, cmd,
.{ .transfer_bit = true }, .{ .transfer_bit = true },
.{ .vertex_input_bit = true }, .{ .vertex_input_bit = true },
.{}, .{},
0, 0,
undefined, undefined,
1, 1,
@ptrCast(&vertexMemoryBarrier), @ptrCast(&vertexMemoryBarrier),
0, 0,
undefined, undefined,
); );
} }
pub fn stageDirtyVertices(self: *@This()) !void { pub fn stageDirtyVertices(self: *@This()) !void {
const newSwapId = (self.swapId + 1) % 2; const newSwapId = (self.swapId + 1) % 2;
// map buffers // map buffers
var slice = try self.gc.vkAllocator.mapMemorySlice(MeshVertex, self.stagingVertexBuffer, self.vertices.len); var slice = try self.gc.vkAllocator.mapMemorySlice(MeshVertex, self.stagingVertexBuffer, self.vertices.len);
var indexSlice = try self.gc.vkAllocator.mapMemorySlice(u32, self.stagingIndexBuffer, self.vertices.len * 6 / 4); var indexSlice = try self.gc.vkAllocator.mapMemorySlice(u32, self.stagingIndexBuffer, self.vertices.len * 6 / 4);
defer self.gc.vkAllocator.unmapMemory(self.stagingVertexBuffer); defer self.gc.vkAllocator.unmapMemory(self.stagingVertexBuffer);
defer self.gc.vkAllocator.unmapMemory(self.stagingIndexBuffer); defer self.gc.vkAllocator.unmapMemory(self.stagingIndexBuffer);
// copy over vertices to mapped buffer // copy over vertices to mapped buffer
for (0..self.vertexCount) |i| { for (0..self.vertexCount) |i| {
slice[i] = self.vertices[i]; slice[i] = self.vertices[i];
} }
self.vertexBufferLen[newSwapId] = self.vertexCount; self.vertexBufferLen[newSwapId] = self.vertexCount;
// interpret vertices as quads. // interpret vertices as quads.
if (self.geometryMode == .quads) { if (self.geometryMode == .quads) {
var index: u32 = 0; var index: u32 = 0;
var vertex: u32 = 0; var vertex: u32 = 0;
while (vertex < self.vertexCount) { while (vertex < self.vertexCount) {
indexSlice[index + 0] = vertex + 0; indexSlice[index + 0] = vertex + 0;
indexSlice[index + 1] = vertex + 1; indexSlice[index + 1] = vertex + 1;
indexSlice[index + 2] = vertex + 2; indexSlice[index + 2] = vertex + 2;
indexSlice[index + 3] = vertex + 2; indexSlice[index + 3] = vertex + 2;
indexSlice[index + 4] = vertex + 3; indexSlice[index + 4] = vertex + 3;
indexSlice[index + 5] = vertex + 0; indexSlice[index + 5] = vertex + 0;
vertex += 4; vertex += 4;
index += 6; index += 6;
} }
self.indexBufferLen[newSwapId] = index; self.indexBufferLen[newSwapId] = index;
} }
self.swapId = newSwapId; self.swapId = newSwapId;
} }
// a stream-like interface for creating vertices // a stream-like interface for creating vertices
// pub fn uploadVertices(self: *@This(), uploader: *NeonVkUploader) !void { // pub fn uploadVertices(self: *@This(), uploader: *NeonVkUploader) !void {
// if (!self.isDirty) { // if (!self.isDirty) {
// return; // return;
// } // }
// self.dirty = false; // self.dirty = false;
// const newSwapId = (self.swapId + 1) % 2; // const newSwapId = (self.swapId + 1) % 2;
// // map buffers // // map buffers
// var slice = try self.gc.vkAllocator.mapMemorySlice(MeshVertex, self.stagingVertexBuffer, self.vertices.len); // var slice = try self.gc.vkAllocator.mapMemorySlice(MeshVertex, self.stagingVertexBuffer, self.vertices.len);
// var indexSlice = try self.gc.vkAllocator.mapMemorySlice(u32, self.stagingIndexBuffer, self.vertices.len * 6 / 4); // var indexSlice = try self.gc.vkAllocator.mapMemorySlice(u32, self.stagingIndexBuffer, self.vertices.len * 6 / 4);
// defer self.gc.vkAllocator.unmapMemory(self.stagingVertexBuffer); // defer self.gc.vkAllocator.unmapMemory(self.stagingVertexBuffer);
// defer self.gc.vkAllocator.unmapMemory(self.stagingIndexBuffer); // defer self.gc.vkAllocator.unmapMemory(self.stagingIndexBuffer);
// // copy over vertices to mapped buffer // // copy over vertices to mapped buffer
// // so... this right here would need to lock.. actually this would be a try-lock // // so... this right here would need to lock.. actually this would be a try-lock
// // if we fail to lock it... that's ok. we can just try again at the end of the frame. // // if we fail to lock it... that's ok. we can just try again at the end of the frame.
// // what happens if we always fail to lock it? // // what happens if we always fail to lock it?
// for (0..self.vertexCount) |i| { // for (0..self.vertexCount) |i| {
// slice[i] = self.vertices[i]; // slice[i] = self.vertices[i];
// } // }
// self.vertexBufferLen[newSwapId] = self.vertexCount; // self.vertexBufferLen[newSwapId] = self.vertexCount;
// // interpret vertices as quads. // // interpret vertices as quads.
// if (self.geometryMode == .quads) { // if (self.geometryMode == .quads) {
// var index: u32 = 0; // var index: u32 = 0;
// var vertex: u32 = 0; // var vertex: u32 = 0;
// while (vertex < self.vertexCount) { // while (vertex < self.vertexCount) {
// indexSlice[index + 0] = vertex + 0; // indexSlice[index + 0] = vertex + 0;
// indexSlice[index + 1] = vertex + 1; // indexSlice[index + 1] = vertex + 1;
// indexSlice[index + 2] = vertex + 2; // indexSlice[index + 2] = vertex + 2;
// indexSlice[index + 3] = vertex + 2; // indexSlice[index + 3] = vertex + 2;
// indexSlice[index + 4] = vertex + 3; // indexSlice[index + 4] = vertex + 3;
// indexSlice[index + 5] = vertex + 0; // indexSlice[index + 5] = vertex + 0;
// vertex += 4; // vertex += 4;
// index += 6; // index += 6;
// } // }
// self.indexBufferLen[newSwapId] = index; // self.indexBufferLen[newSwapId] = index;
// } // }
// // upload index and vertex buffers // // upload index and vertex buffers
// try uploader.addBufferUpload( // try uploader.addBufferUpload(
// self.stagingIndexBuffer, // self.stagingIndexBuffer,
// self.indexBuffers[newSwapId], // self.indexBuffers[newSwapId],
// self.indexBufferLen[newSwapId] * @as(u32, @intCast(@sizeOf(u32))), // self.indexBufferLen[newSwapId] * @as(u32, @intCast(@sizeOf(u32))),
// ); // );
// try uploader.addBufferUpload( // try uploader.addBufferUpload(
// self.stagingVertexBuffer, // self.stagingVertexBuffer,
// self.vertexBuffers[newSwapId], // self.vertexBuffers[newSwapId],
// self.vertexCount * @as(u32, @intCast(@sizeOf(MeshVertex))), // self.vertexCount * @as(u32, @intCast(@sizeOf(MeshVertex))),
// ); // );
// } // }
pub fn bumpSwapId(self: *@This()) void { pub fn bumpSwapId(self: *@This()) void {
self.swapId = (self.swapId + 1) % 2; self.swapId = (self.swapId + 1) % 2;
self.isDirty = false; self.isDirty = false;
} }
pub fn clearVertices(self: *@This()) void { pub fn clearVertices(self: *@This()) void {
self.vertexCount = 0; self.vertexCount = 0;
self.isDirty = true; self.isDirty = true;
} }
pub fn addVertexList(self: *@This(), list: []const MeshVertex) void { pub fn addVertexList(self: *@This(), list: []const MeshVertex) void {
if (list.len > 0) { if (list.len > 0) {
self.isDirty = true; self.isDirty = true;
} }
for (list) |v| { for (list) |v| {
self.vertices[self.vertexCount] = v; self.vertices[self.vertexCount] = v;
self.vertexCount += 1; self.vertexCount += 1;
} }
} }
// adds a quad only in the X and y Space, // adds a quad only in the X and y Space,
pub fn addQuad2D( pub fn addQuad2D(
self: *@This(), self: *@This(),
_topLeft: core.Vectorf, // only x and y is considered _topLeft: core.Vectorf, // only x and y is considered
_size: core.Vectorf, // only x and y is considered _size: core.Vectorf, // only x and y is considered
topLeftUV: core.Vector2f, topLeftUV: core.Vector2f,
uvSize: core.Vector2f, uvSize: core.Vector2f,
color: LinearColor, color: LinearColor,
) void { ) void {
var topLeft = _topLeft; var topLeft = _topLeft;
var size = _size; var size = _size;
topLeft.z = 0; topLeft.z = 0;
size.z = 0; size.z = 0;
const normal = Vectorf{ .x = 0, .y = 0, .z = -1 }; const normal = Vectorf{ .x = 0, .y = 0, .z = -1 };
var vertices: [4]MeshVertex = undefined; var vertices: [4]MeshVertex = undefined;
vertices[0] = .{ vertices[0] = .{
.position = topLeft, .position = topLeft,
.normal = normal, .normal = normal,
.uv = topLeftUV, .uv = topLeftUV,
.color = color, .color = color,
}; };
vertices[1] = .{ vertices[1] = .{
.position = topLeft.add(.{ .x = size.x }), .position = topLeft.add(.{ .x = size.x }),
.normal = normal, .normal = normal,
.uv = topLeftUV.add(core.Vector2f{ .x = uvSize.x }), .uv = topLeftUV.add(core.Vector2f{ .x = uvSize.x }),
.color = color, .color = color,
}; };
vertices[2] = .{ vertices[2] = .{
.position = topLeft.add(size), .position = topLeft.add(size),
.normal = normal, .normal = normal,
.uv = topLeftUV.add(uvSize), .uv = topLeftUV.add(uvSize),
.color = color, .color = color,
}; };
vertices[3] = .{ vertices[3] = .{
.position = topLeft.add(.{ .y = size.y }), .position = topLeft.add(.{ .y = size.y }),
.normal = normal, .normal = normal,
.uv = topLeftUV.add(core.Vector2f{ .y = uvSize.y }), .uv = topLeftUV.add(core.Vector2f{ .y = uvSize.y }),
.color = color, .color = color,
}; };
self.addVertexList(&vertices); self.addVertexList(&vertices);
} }
pub fn deinit(self: *@This()) void { pub fn deinit(self: *@This()) void {
self.allocator.free(self.vertices); self.allocator.free(self.vertices);
const vkAllocator = self.gc.vkAllocator; const vkAllocator = self.gc.vkAllocator;
self.stagingVertexBuffer.deinit(vkAllocator); self.stagingVertexBuffer.deinit(vkAllocator);
self.stagingIndexBuffer.deinit(vkAllocator); self.stagingIndexBuffer.deinit(vkAllocator);
for (0..self.indexBuffers.len) |i| { for (0..self.indexBuffers.len) |i| {
self.indexBuffers[i].deinit(vkAllocator); self.indexBuffers[i].deinit(vkAllocator);
self.vertexBuffers[i].deinit(vkAllocator); self.vertexBuffers[i].deinit(vkAllocator);
} }
self.allocator.destroy(self); self.allocator.destroy(self);
// should remove ourselves from the manager // should remove ourselves from the manager
} }
}; };

View File

@ -1,174 +1,174 @@
pub fn MakeCubeMapList( pub fn MakeCubeMapList(
comptime left: []const u8, comptime left: []const u8,
comptime up: []const u8, comptime up: []const u8,
comptime down: []const u8, comptime down: []const u8,
comptime front: []const u8, comptime front: []const u8,
comptime back: []const u8, comptime back: []const u8,
) []const []const u8 { ) []const []const u8 {
return &.{ return &.{
left, left,
up, up,
down, down,
front, front,
back, back,
}; };
} }
pub const CubeMapDirs = enum(u8) { pub const CubeMapDirs = enum(u8) {
right, right,
left, left,
up, up,
down, down,
front, front,
back, back,
}; };
const vk_utils = @import("../vk_utils.zig"); const vk_utils = @import("../vk_utils.zig");
const LoadAndStageImage = vk_utils.LoadAndStageImage; const LoadAndStageImage = vk_utils.LoadAndStageImage;
pub fn stageCubeTexture(list: []const []const u8) !LoadAndStageImage { pub fn stageCubeTexture(list: []const []const u8) !LoadAndStageImage {
try core.assert(list.len == 6); try core.assert(list.len == 6);
const gc = graphics.getContext(); const gc = graphics.getContext();
const allocator = gc.allocator; const allocator = gc.allocator;
var pngs: [6]core.png.PngContents = undefined; var pngs: [6]core.png.PngContents = undefined;
for (0..6) |i| { for (0..6) |i| {
pngs[i] = try core.png.PngContents.initFromPathSpec(list[i], allocator); pngs[i] = try core.png.PngContents.initFromPathSpec(list[i], allocator);
} }
defer { defer {
for (&pngs) |*png| { for (&pngs) |*png| {
png.deinit(); png.deinit();
} }
} }
const width = pngs[0].size.x; const width = pngs[0].size.x;
const height = pngs[0].size.y; const height = pngs[0].size.y;
try core.assert(width == height); try core.assert(width == height);
core.engine_log("cubemap dimensionss {d}x{d}", .{ width, height }); core.engine_log("cubemap dimensionss {d}x{d}", .{ width, height });
var totalLen: u32 = 0; var totalLen: u32 = 0;
for (pngs) |png| { for (pngs) |png| {
try core.assertf(width == png.size.x, "inconsistent cubemap dimensions", .{}); try core.assertf(width == png.size.x, "inconsistent cubemap dimensions", .{});
try core.assertf(height == png.size.y, "inconsistent cubemap dimensions", .{}); try core.assertf(height == png.size.y, "inconsistent cubemap dimensions", .{});
totalLen += @intCast(png.pixels.len); totalLen += @intCast(png.pixels.len);
} }
const stagingBuffer = try gc.vkAllocator.createStagingBuffer(totalLen, "cubemap creation staging texture map"); const stagingBuffer = try gc.vkAllocator.createStagingBuffer(totalLen, "cubemap creation staging texture map");
const pixelBuffer = try gc.vkAllocator.mapBuffer(u8, stagingBuffer); const pixelBuffer = try gc.vkAllocator.mapBuffer(u8, stagingBuffer);
var offset: u32 = 0; var offset: u32 = 0;
var bufferOffsets: [6]u32 = undefined; var bufferOffsets: [6]u32 = undefined;
for (pngs, 0..) |png, i| { for (pngs, 0..) |png, i| {
const dest = pixelBuffer[offset .. offset + png.pixels.len]; const dest = pixelBuffer[offset .. offset + png.pixels.len];
bufferOffsets[i] = offset; bufferOffsets[i] = offset;
offset += @intCast(png.pixels.len); offset += @intCast(png.pixels.len);
@memcpy(dest, png.pixels); @memcpy(dest, png.pixels);
} }
const imageExtent = vk.Extent3D{ const imageExtent = vk.Extent3D{
.width = @as(u32, @intCast(width)), .width = @as(u32, @intCast(width)),
.height = @as(u32, @intCast(height)), .height = @as(u32, @intCast(height)),
.depth = 1, .depth = 1,
}; };
//const mipLevel = std.math.log2(@max(imageExtent.width, imageExtent.height)) + 1; //const mipLevel = std.math.log2(@max(imageExtent.width, imageExtent.height)) + 1;
const mipLevel = 1; const mipLevel = 1;
var imgCreateInfo = vkinit.imageCreateInfo(.r8g8b8a8_srgb, .{ var imgCreateInfo = vkinit.imageCreateInfo(.r8g8b8a8_srgb, .{
.sampled_bit = true, .sampled_bit = true,
.transfer_dst_bit = true, .transfer_dst_bit = true,
}, imageExtent, mipLevel); }, imageExtent, mipLevel);
imgCreateInfo.array_layers = 6; imgCreateInfo.array_layers = 6;
imgCreateInfo.flags.cube_compatible_bit = true; imgCreateInfo.flags.cube_compatible_bit = true;
if (mipLevel > 1) { if (mipLevel > 1) {
imgCreateInfo.usage.transfer_src_bit = true; imgCreateInfo.usage.transfer_src_bit = true;
} }
const imgAllocInfo = vma.AllocationCreateInfo{ const imgAllocInfo = vma.AllocationCreateInfo{
.requiredFlags = .{}, .requiredFlags = .{},
.usage = .gpuOnly, .usage = .gpuOnly,
}; };
const newImage = try gc.vkAllocator.createImage(imgCreateInfo, imgAllocInfo, "cubemap creation image"); const newImage = try gc.vkAllocator.createImage(imgCreateInfo, imgAllocInfo, "cubemap creation image");
gc.vkAllocator.unmapMemory(stagingBuffer); gc.vkAllocator.unmapMemory(stagingBuffer);
return .{ return .{
.stagingBuffer = stagingBuffer, .stagingBuffer = stagingBuffer,
.image = newImage, .image = newImage,
.mipLevel = mipLevel, .mipLevel = mipLevel,
.cubeOffsets = bufferOffsets, .cubeOffsets = bufferOffsets,
}; };
} }
pub fn submitTextureCube(uploader: *vk_utils.NeonVkUploader, state: *const LoadAndStageImage) !void { pub fn submitTextureCube(uploader: *vk_utils.NeonVkUploader, state: *const LoadAndStageImage) !void {
try core.assert(state.cubeOffsets != null); try core.assert(state.cubeOffsets != null);
if (state.cubeOffsets) |cubeOffsets| { if (state.cubeOffsets) |cubeOffsets| {
try uploader.startUploadContext(); try uploader.startUploadContext();
{ {
const newImage = state.image; const newImage = state.image;
const mipLevel = state.mipLevel; const mipLevel = state.mipLevel;
const cmd = uploader.commandBuffer; const cmd = uploader.commandBuffer;
transitions.into_transferDst(cmd, newImage.image, mipLevel, 0, 6); transitions.into_transferDst(cmd, newImage.image, mipLevel, 0, 6);
for (cubeOffsets, 0..) |offset, face| { for (cubeOffsets, 0..) |offset, face| {
var copyRegion = vk.BufferImageCopy{ var copyRegion = vk.BufferImageCopy{
.buffer_offset = offset, .buffer_offset = offset,
.buffer_row_length = 0, .buffer_row_length = 0,
.buffer_image_height = 0, .buffer_image_height = 0,
.image_offset = std.mem.zeroes(vk.Offset3D), .image_offset = std.mem.zeroes(vk.Offset3D),
.image_subresource = .{ .image_subresource = .{
.aspect_mask = .{ .color_bit = true }, .aspect_mask = .{ .color_bit = true },
.mip_level = 0, .mip_level = 0,
.base_array_layer = @intCast(face), .base_array_layer = @intCast(face),
.layer_count = 1, .layer_count = 1,
}, },
.image_extent = .{ .image_extent = .{
.width = newImage.pixelWidth, .width = newImage.pixelWidth,
.height = newImage.pixelHeight, .height = newImage.pixelHeight,
.depth = 1, .depth = 1,
}, },
}; };
vkd.cmdCopyBufferToImage( vkd.cmdCopyBufferToImage(
cmd, cmd,
state.stagingBuffer.buffer, state.stagingBuffer.buffer,
newImage.image, newImage.image,
.transfer_dst_optimal, .transfer_dst_optimal,
1, 1,
@ptrCast(&copyRegion), @ptrCast(&copyRegion),
); );
try vk_utils.generateMipMaps(cmd, newImage, mipLevel, 0); try vk_utils.generateMipMaps(cmd, newImage, mipLevel, 0);
} }
transitions.transferDst_into_shaderReadOnly(cmd, newImage.image, mipLevel, 0, 6); transitions.transferDst_into_shaderReadOnly(cmd, newImage.image, mipLevel, 0, 6);
} }
try uploader.finishUploadContext(); try uploader.finishUploadContext();
} }
} }
pub fn createDescriptorSet( pub fn createDescriptorSet(
dev: vk.Device, dev: vk.Device,
) struct { ) struct {
layout: vk.DescriptorSetLayout, layout: vk.DescriptorSetLayout,
descriptorSet: vk.DescriptorSet, descriptorSet: vk.DescriptorSet,
} { } {
_ = dev; _ = dev;
} }
const core = @import("core"); const core = @import("core");
const vk_renderer = @import("../vk_renderer.zig"); const vk_renderer = @import("../vk_renderer.zig");
const vma = @import("vma"); const vma = @import("vma");
const graphics = @import("../graphics.zig"); const graphics = @import("../graphics.zig");
const vk = @import("vulkan"); const vk = @import("vulkan");
const vkinit = @import("../vk_init.zig"); const vkinit = @import("../vk_init.zig");
const vk_constants = @import("../vk_constants.zig"); const vk_constants = @import("../vk_constants.zig");
const std = @import("std"); const std = @import("std");
const vkd = vk_api.vkd; const vkd = vk_api.vkd;
const vk_api = @import("../vk_api.zig"); const vk_api = @import("../vk_api.zig");
const transitions = @import("../vk_transitions.zig"); const transitions = @import("../vk_transitions.zig");

View File

@ -1,72 +1,72 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const core = @import("core"); const core = @import("core");
const vk_renderer = @import("../vk_renderer.zig"); const vk_renderer = @import("../vk_renderer.zig");
const NeonVkContext = vk_renderer.NeonVkContext; const NeonVkContext = vk_renderer.NeonVkContext;
const vk_allocator = @import("../vk_allocator.zig"); const vk_allocator = @import("../vk_allocator.zig");
const vk_constants = @import("../vk_constants.zig"); const vk_constants = @import("../vk_constants.zig");
pub const NeonVkQueue = struct { pub const NeonVkQueue = struct {
handle: vk.Queue, handle: vk.Queue,
family: u32, family: u32,
pub fn init(vkd: vk_constants.DeviceDispatch, dev: vk.Device, family: u32, index: u32) @This() { pub fn init(vkd: vk_constants.DeviceDispatch, dev: vk.Device, family: u32, index: u32) @This() {
return .{ return .{
.handle = vkd.getDeviceQueue(dev, family, index), .handle = vkd.getDeviceQueue(dev, family, index),
.family = family, .family = family,
}; };
} }
}; };
pub const NeonVkFrameData = struct { pub const NeonVkFrameData = struct {
// descriptors // descriptors
globalDescriptorSet: vk.DescriptorSet, globalDescriptorSet: vk.DescriptorSet,
objectDescriptorSet: vk.DescriptorSet, objectDescriptorSet: vk.DescriptorSet,
spriteDescriptorSet: vk.DescriptorSet, spriteDescriptorSet: vk.DescriptorSet,
// buffers // buffers
spriteBuffer: vk_allocator.NeonVkBuffer, spriteBuffer: vk_allocator.NeonVkBuffer,
objectBuffer: vk_allocator.NeonVkBuffer, objectBuffer: vk_allocator.NeonVkBuffer,
animationsBuffer: vk_allocator.NeonVkBuffer, animationsBuffer: vk_allocator.NeonVkBuffer,
cameraBuffer: vk_allocator.NeonVkBuffer, cameraBuffer: vk_allocator.NeonVkBuffer,
}; };
pub const triangle_mesh_vert = @import("triangle_mesh_vert"); pub const triangle_mesh_vert = @import("triangle_mesh_vert");
pub const NeonVkObjectDataGpu = triangle_mesh_vert.ObjectData; pub const NeonVkObjectDataGpu = triangle_mesh_vert.ObjectData;
pub const VertexBoneData = triangle_mesh_vert.VertexBoneData; pub const VertexBoneData = triangle_mesh_vert.VertexBoneData;
pub const NeonVkSceneDataGpu = struct { pub const NeonVkSceneDataGpu = struct {
fogColor: core.zm.Vec = .{ 0.0, 0.0, 0.0, 0.0 }, fogColor: core.zm.Vec = .{ 0.0, 0.0, 0.0, 0.0 },
fogDistances: core.zm.Vec = .{ 0.0, 0.0, 0.0, 0.0 }, fogDistances: core.zm.Vec = .{ 0.0, 0.0, 0.0, 0.0 },
ambientColor: core.zm.Vec = .{ 0.0, 0.0, 0.0, 0.0 }, ambientColor: core.zm.Vec = .{ 0.0, 0.0, 0.0, 0.0 },
sunlightDirection: core.zm.Vec = .{ 0.0, 0.0, 0.0, 0.0 }, sunlightDirection: core.zm.Vec = .{ 0.0, 0.0, 0.0, 0.0 },
sunlightColor: core.zm.Vec = .{ 0.0, 0.0, 0.0, 0.0 }, sunlightColor: core.zm.Vec = .{ 0.0, 0.0, 0.0, 0.0 },
}; };
pub const descriptorPoolSizes = [_]vk.DescriptorPoolSize{ pub const descriptorPoolSizes = [_]vk.DescriptorPoolSize{
.{ .type = .uniform_buffer, .descriptor_count = 1000 }, .{ .type = .uniform_buffer, .descriptor_count = 1000 },
.{ .type = .uniform_buffer_dynamic, .descriptor_count = 1000 }, .{ .type = .uniform_buffer_dynamic, .descriptor_count = 1000 },
.{ .type = .storage_buffer, .descriptor_count = 1000 }, .{ .type = .storage_buffer, .descriptor_count = 1000 },
.{ .type = .combined_image_sampler, .descriptor_count = 2000 }, .{ .type = .combined_image_sampler, .descriptor_count = 2000 },
.{ .type = .sampler, .descriptor_count = 1000 }, .{ .type = .sampler, .descriptor_count = 1000 },
.{ .type = .sampled_image, .descriptor_count = 1000 }, .{ .type = .sampled_image, .descriptor_count = 1000 },
.{ .type = .storage_image, .descriptor_count = 1000 }, .{ .type = .storage_image, .descriptor_count = 1000 },
// .{ .type = .sampler, .descriptor_count = 1000 }, // .{ .type = .sampler, .descriptor_count = 1000 },
// .{ .type = .combined_image_sampler, .descriptor_count = 1000 }, // .{ .type = .combined_image_sampler, .descriptor_count = 1000 },
// .{ .type = .sampled_image, .descriptor_count = 1000 }, // .{ .type = .sampled_image, .descriptor_count = 1000 },
// .{ .type = .storage_image, .descriptor_count = 1000 }, // .{ .type = .storage_image, .descriptor_count = 1000 },
}; };
pub const NeonVkSwapImage = struct { pub const NeonVkSwapImage = struct {
image: vk.Image, image: vk.Image,
view: vk.ImageView, view: vk.ImageView,
imageIndex: usize, imageIndex: usize,
pub fn deinit(self: *NeonVkSwapImage, vkd: vk_constants.DeviceDispatch, dev: vk.Device) void { pub fn deinit(self: *NeonVkSwapImage, vkd: vk_constants.DeviceDispatch, dev: vk.Device) void {
vkd.destroyImageView(dev, self.view, null); vkd.destroyImageView(dev, self.view, null);
} }
}; };

View File

@ -1,44 +1,44 @@
pub const SkeletalBuffers = struct { pub const SkeletalBuffers = struct {
descriptorSet: vk.DescriptorSet, descriptorSet: vk.DescriptorSet,
gc: *NeonVkContext, gc: *NeonVkContext,
vkAllocator: *NeonVkAllocator, vkAllocator: *NeonVkAllocator,
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
finalsBuffer: [2]NeonVkBuffer = undefined, finalsBuffer: [2]NeonVkBuffer = undefined,
pub fn init(gc: *NeonVkContext) !*@This() { pub fn init(gc: *NeonVkContext) !*@This() {
const self = try gc.allocator.create(@This()); const self = try gc.allocator.create(@This());
self.* = .{ self.* = .{
.gc = gc, .gc = gc,
.allocator = gc.allocator, .allocator = gc.allocator,
.vkAllocator = gc.vkAllocator, .vkAllocator = gc.vkAllocator,
.skeletalPipeData = undefined, .skeletalPipeData = undefined,
}; };
self.buildBuffers(); self.buildBuffers();
return self; return self;
} }
pub fn buildBuffers(self: *@This()) !void { pub fn buildBuffers(self: *@This()) !void {
const vkAllocator: *NeonVkAllocator = self.vkAllocator; const vkAllocator: *NeonVkAllocator = self.vkAllocator;
// 100k animated skeletal mesh vertices ought to be enough for anyone right? // 100k animated skeletal mesh vertices ought to be enough for anyone right?
for (0..2) |i| { for (0..2) |i| {
self.finalsBuffer[i] = try vkAllocator.createSsboBuffer(@sizeOf(core.Mat) * vk_constants.MAX_SKIN_SLOTS, "bones buffer."); self.finalsBuffer[i] = try vkAllocator.createSsboBuffer(@sizeOf(core.Mat) * vk_constants.MAX_SKIN_SLOTS, "bones buffer.");
} }
} }
}; };
const std = @import("std"); const std = @import("std");
const core = @import("core"); const core = @import("core");
const assets = @import("assets"); const assets = @import("assets");
const graphics = @import("../graphics.zig"); const graphics = @import("../graphics.zig");
const vk_renderer_types = @import("vk_renderer_types.zig"); const vk_renderer_types = @import("vk_renderer_types.zig");
const VertexBoneData = vk_renderer_types.VertexBoneData; const VertexBoneData = vk_renderer_types.VertexBoneData;
const gpd = graphics.gpu_pipe_data; const gpd = graphics.gpu_pipe_data;
const NeonVkContext = graphics.NeonVkContext; const NeonVkContext = graphics.NeonVkContext;
const NeonVkBuffer = graphics.NeonVkBuffer; const NeonVkBuffer = graphics.NeonVkBuffer;
const NeonVkAllocator = graphics.NeonVkAllocator; const NeonVkAllocator = graphics.NeonVkAllocator;
const vk = @import("vulkan"); const vk = @import("vulkan");
const vk_constants = @import("../vk_constants.zig"); const vk_constants = @import("../vk_constants.zig");

View File

@ -1,87 +1,87 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const core = @import("core"); const core = @import("core");
const vk_constants = @import("../vk_constants.zig"); const vk_constants = @import("../vk_constants.zig");
const vk_renderer_types = @import("vk_renderer_types.zig"); const vk_renderer_types = @import("vk_renderer_types.zig");
const vk_api = @import("../vk_api.zig"); const vk_api = @import("../vk_api.zig");
const vkd = vk_api.vkd; const vkd = vk_api.vkd;
const vki = vk_api.vki; const vki = vk_api.vki;
const vkb = vk_api.vkb; const vkb = vk_api.vkb;
const force_mailbox = core.BuildOption("force_mailbox"); const force_mailbox = core.BuildOption("force_mailbox");
pub fn findSurfaceFormat( pub fn findSurfaceFormat(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
pdev: vk.PhysicalDevice, pdev: vk.PhysicalDevice,
surface: vk.SurfaceKHR, surface: vk.SurfaceKHR,
) !vk.SurfaceFormatKHR { ) !vk.SurfaceFormatKHR {
const preferred = vk.SurfaceFormatKHR{ const preferred = vk.SurfaceFormatKHR{
.format = .b8g8r8a8_srgb, .format = .b8g8r8a8_srgb,
.color_space = .srgb_nonlinear_khr, .color_space = .srgb_nonlinear_khr,
}; };
var count: u32 = 0; var count: u32 = 0;
_ = try vki.getPhysicalDeviceSurfaceFormatsKHR(pdev, surface, &count, null); _ = try vki.getPhysicalDeviceSurfaceFormatsKHR(pdev, surface, &count, null);
const surface_formats = try allocator.alloc(vk.SurfaceFormatKHR, count); const surface_formats = try allocator.alloc(vk.SurfaceFormatKHR, count);
defer allocator.free(surface_formats); defer allocator.free(surface_formats);
_ = try vki.getPhysicalDeviceSurfaceFormatsKHR(pdev, surface, &count, surface_formats.ptr); _ = try vki.getPhysicalDeviceSurfaceFormatsKHR(pdev, surface, &count, surface_formats.ptr);
for (surface_formats) |sfmt| { for (surface_formats) |sfmt| {
if (std.meta.eql(sfmt, preferred)) { if (std.meta.eql(sfmt, preferred)) {
return preferred; return preferred;
} }
} }
const rv = surface_formats[0]; const rv = surface_formats[0];
core.graphics_log("Selected surface format\n {any}", .{rv}); core.graphics_log("Selected surface format\n {any}", .{rv});
return rv; return rv;
} }
pub fn findPresentMode( pub fn findPresentMode(
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
pdev: vk.PhysicalDevice, pdev: vk.PhysicalDevice,
surface: vk.SurfaceKHR, surface: vk.SurfaceKHR,
) !vk.PresentModeKHR { ) !vk.PresentModeKHR {
var count: u32 = undefined; var count: u32 = undefined;
_ = try vki.getPhysicalDeviceSurfacePresentModesKHR(pdev, surface, &count, null); _ = try vki.getPhysicalDeviceSurfacePresentModesKHR(pdev, surface, &count, null);
const present_modes = try allocator.alloc(vk.PresentModeKHR, count); const present_modes = try allocator.alloc(vk.PresentModeKHR, count);
defer allocator.free(present_modes); defer allocator.free(present_modes);
_ = try vki.getPhysicalDeviceSurfacePresentModesKHR(pdev, surface, &count, present_modes.ptr); _ = try vki.getPhysicalDeviceSurfacePresentModesKHR(pdev, surface, &count, present_modes.ptr);
const preferred = [_]vk.PresentModeKHR{ const preferred = [_]vk.PresentModeKHR{
.fifo_khr, .fifo_khr,
.mailbox_khr, .mailbox_khr,
.immediate_khr, .immediate_khr,
}; };
if (force_mailbox) { if (force_mailbox) {
return .mailbox_khr; return .mailbox_khr;
} }
for (preferred) |mode| { for (preferred) |mode| {
if (std.mem.indexOfScalar(vk.PresentModeKHR, present_modes, mode) != null) { if (std.mem.indexOfScalar(vk.PresentModeKHR, present_modes, mode) != null) {
return mode; return mode;
} }
} }
return error.UnableToFindPresentMode; return error.UnableToFindPresentMode;
} }
pub fn findActualExtent( pub fn findActualExtent(
extent: vk.Extent2D, extent: vk.Extent2D,
caps: vk.SurfaceCapabilitiesKHR, caps: vk.SurfaceCapabilitiesKHR,
) !vk.Extent2D { ) !vk.Extent2D {
if (caps.current_extent.width != 0xFFFF_FFFF) { if (caps.current_extent.width != 0xFFFF_FFFF) {
return caps.current_extent; return caps.current_extent;
} else { } else {
return .{ return .{
.width = std.math.clamp(extent.width, caps.min_image_extent.width, caps.max_image_extent.width), .width = std.math.clamp(extent.width, caps.min_image_extent.width, caps.max_image_extent.width),
.height = std.math.clamp(extent.height, caps.min_image_extent.height, caps.max_image_extent.height), .height = std.math.clamp(extent.height, caps.min_image_extent.height, caps.max_image_extent.height),
}; };
} }
} }

View File

@ -1,128 +1,128 @@
// this implements the global texture list // this implements the global texture list
const gTextureList: *TextureList = undefined; const gTextureList: *TextureList = undefined;
pub const ArrayedTexture = struct {}; pub const ArrayedTexture = struct {};
pub const TextureList = struct { pub const TextureList = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
textures: std.AutoHashMapUnmanaged(u32, *Texture), textures: std.AutoHashMapUnmanaged(u32, *Texture),
gc: *NeonVkContext, gc: *NeonVkContext,
listSet: vk.DescriptorSet = undefined, listSet: vk.DescriptorSet = undefined,
dsl: vk.DescriptorSetLayout = undefined, dsl: vk.DescriptorSetLayout = undefined,
// descriptorPool: vk.DescriptorPool = undefined, // descriptorPool: vk.DescriptorPool = undefined,
// const descriptorPoolSizes = [_]vk.DescriptorPoolSize{ // const descriptorPoolSizes = [_]vk.DescriptorPoolSize{
// .{ .type = .sampler, .descriptor_count = 1000 }, // .{ .type = .sampler, .descriptor_count = 1000 },
// .{ .type = .combined_image_sampler, .descriptor_count = 1000 }, // .{ .type = .combined_image_sampler, .descriptor_count = 1000 },
// .{ .type = .sampled_image, .descriptor_count = 1000 }, // .{ .type = .sampled_image, .descriptor_count = 1000 },
// .{ .type = .storage_image, .descriptor_count = 1000 }, // .{ .type = .storage_image, .descriptor_count = 1000 },
// }; // };
pub fn create(gc: *NeonVkContext) !*@This() { pub fn create(gc: *NeonVkContext) !*@This() {
const self = try gc.allocator.create(@This()); const self = try gc.allocator.create(@This());
self.* = .{ self.* = .{
.allocator = gc.allocator, .allocator = gc.allocator,
.textures = .{}, .textures = .{},
.gc = gc, .gc = gc,
}; };
try self.initTextureList(); try self.initTextureList();
return self; return self;
} }
pub fn initTextureList(self: *@This()) !void { pub fn initTextureList(self: *@This()) !void {
// var poolInfo = vk.DescriptorPoolCreateInfo{ // var poolInfo = vk.DescriptorPoolCreateInfo{
// .flags = .{}, // .flags = .{},
// .max_sets = 1000, // .max_sets = 1000,
// .pool_size_count = @intCast(descriptorPoolSizes.len), // .pool_size_count = @intCast(descriptorPoolSizes.len),
// .p_pool_sizes = &descriptorPoolSizes, // .p_pool_sizes = &descriptorPoolSizes,
// }; // };
// self.descriptorPool = try vkd.createDescriptorPool(self.gc.dev, &poolInfo, null); // self.descriptorPool = try vkd.createDescriptorPool(self.gc.dev, &poolInfo, null);
const bindings = [_]vk.DescriptorSetLayoutBinding{ const bindings = [_]vk.DescriptorSetLayoutBinding{
.{ .{
.binding = 0, .binding = 0,
.descriptor_type = .storage_buffer, .descriptor_type = .storage_buffer,
.descriptor_count = 500, .descriptor_count = 500,
.stage_flags = .{ .stage_flags = .{
.vertex_bit = true, .vertex_bit = true,
.geometry_bit = true, .geometry_bit = true,
.compute_bit = true, .compute_bit = true,
.fragment_bit = true, .fragment_bit = true,
}, },
.p_immutable_samplers = null, .p_immutable_samplers = null,
}, },
.{ .{
.binding = 1, .binding = 1,
.descriptor_type = .combined_image_sampler, .descriptor_type = .combined_image_sampler,
.descriptor_count = 500, .descriptor_count = 500,
.stage_flags = .{ .stage_flags = .{
.vertex_bit = true, .vertex_bit = true,
.geometry_bit = true, .geometry_bit = true,
.compute_bit = true, .compute_bit = true,
.fragment_bit = true, .fragment_bit = true,
}, },
.p_immutable_samplers = null, .p_immutable_samplers = null,
}, },
.{ .{
.binding = 2, .binding = 2,
.descriptor_type = .storage_image, .descriptor_type = .storage_image,
.descriptor_count = 500, .descriptor_count = 500,
.stage_flags = .{ .stage_flags = .{
.vertex_bit = true, .vertex_bit = true,
.geometry_bit = true, .geometry_bit = true,
.compute_bit = true, .compute_bit = true,
.fragment_bit = true, .fragment_bit = true,
}, },
.p_immutable_samplers = null, .p_immutable_samplers = null,
}, },
}; };
const flags = [_]vk.DescriptorBindingFlags{ const flags = [_]vk.DescriptorBindingFlags{
.{ .partially_bound_bit = true }, .{ .partially_bound_bit = true },
.{ .partially_bound_bit = true }, .{ .partially_bound_bit = true },
.{ .partially_bound_bit = true }, .{ .partially_bound_bit = true },
}; };
const fci = vk.DescriptorSetLayoutBindingFlagsCreateInfo{ .binding_count = 3, .p_binding_flags = @ptrCast(&flags) }; const fci = vk.DescriptorSetLayoutBindingFlagsCreateInfo{ .binding_count = 3, .p_binding_flags = @ptrCast(&flags) };
const dsci = vk.DescriptorSetLayoutCreateInfo{ const dsci = vk.DescriptorSetLayoutCreateInfo{
.flags = .{}, .flags = .{},
.binding_count = bindings.len, .binding_count = bindings.len,
.p_bindings = @ptrCast(&bindings), .p_bindings = @ptrCast(&bindings),
.p_next = &fci, .p_next = &fci,
}; };
self.dsl = try vkd.createDescriptorSetLayout(self.gc.dev, &dsci, null); self.dsl = try vkd.createDescriptorSetLayout(self.gc.dev, &dsci, null);
const dsai = vk.DescriptorSetAllocateInfo{ const dsai = vk.DescriptorSetAllocateInfo{
.descriptor_pool = self.gc.descriptorPool, .descriptor_pool = self.gc.descriptorPool,
.descriptor_set_count = 1, .descriptor_set_count = 1,
.p_set_layouts = @ptrCast(&self.dsl), .p_set_layouts = @ptrCast(&self.dsl),
}; };
try vkd.allocateDescriptorSets(self.gc.dev, &dsai, @ptrCast(&self.listSet)); try vkd.allocateDescriptorSets(self.gc.dev, &dsai, @ptrCast(&self.listSet));
} }
pub fn destroy(self: *@This()) void { pub fn destroy(self: *@This()) void {
vkd.destroyDescriptorSetLayout(self.gc.dev, self.dsl, null); vkd.destroyDescriptorSetLayout(self.gc.dev, self.dsl, null);
// vkd.destroyDescriptorPool(self.gc.dev, self.descriptorPool, null); // vkd.destroyDescriptorPool(self.gc.dev, self.descriptorPool, null);
self.textures.deinit(self.allocator); self.textures.deinit(self.allocator);
self.allocator.destroy(self); self.allocator.destroy(self);
} }
}; };
const graphics = @import("../graphics.zig"); const graphics = @import("../graphics.zig");
const NeonVkContext = graphics.NeonVkContext; const NeonVkContext = graphics.NeonVkContext;
const texture = @import("../texture.zig"); const texture = @import("../texture.zig");
const Texture = texture.Texture; const Texture = texture.Texture;
const vk = @import("vulkan"); const vk = @import("vulkan");
const std = @import("std"); const std = @import("std");
const vk_api = @import("../vk_api.zig"); const vk_api = @import("../vk_api.zig");
const vkd = vk_api.vkd; const vkd = vk_api.vkd;

View File

@ -1,35 +1,35 @@
const vk_constants = @import("../vk_constants.zig"); const vk_constants = @import("../vk_constants.zig");
const vk_api = @import("../vk_api.zig"); const vk_api = @import("../vk_api.zig");
const vkd = vk_api.vkd; const vkd = vk_api.vkd;
const vki = vk_api.vki; const vki = vk_api.vki;
const vkb = vk_api.vkb; const vkb = vk_api.vkb;
const vk = @import("vulkan"); const vk = @import("vulkan");
const graphics = @import("../graphics.zig"); const graphics = @import("../graphics.zig");
const NeonVkBuffer = graphics.NeonVkBuffer; const NeonVkBuffer = graphics.NeonVkBuffer;
pub fn copyStagingSlice( pub fn copyStagingSlice(
comptime Element: type, comptime Element: type,
cmd: vk.CommandBuffer, cmd: vk.CommandBuffer,
params: struct { params: struct {
src: *NeonVkBuffer, src: *NeonVkBuffer,
dst: *NeonVkBuffer, dst: *NeonVkBuffer,
size: u32, // in element count size: u32, // in element count
src_offset: u32 = 0, // in element counts src_offset: u32 = 0, // in element counts
dst_offset: u32 = 0, // in element counts dst_offset: u32 = 0, // in element counts
}, },
) void { ) void {
const elementSize = @sizeOf(Element); const elementSize = @sizeOf(Element);
var copy = vk.BufferCopy{ var copy = vk.BufferCopy{
.dst_offset = params.dst_offset * elementSize, .dst_offset = params.dst_offset * elementSize,
.src_offset = params.src_offset * elementSize, .src_offset = params.src_offset * elementSize,
.size = params.size * elementSize, .size = params.size * elementSize,
}; };
vkd.cmdCopyBuffer( vkd.cmdCopyBuffer(
cmd, cmd,
params.src.buffer, params.src.buffer,
params.dst.buffer, params.dst.buffer,
1, 1,
@as([*]const vk.BufferCopy, @ptrCast(&copy)), @as([*]const vk.BufferCopy, @ptrCast(&copy)),
); );
} }

View File

@ -1,11 +1,11 @@
const std = @import("std"); const std = @import("std");
const core = @import("core"); const core = @import("core");
const graphics = @import("graphics.zig"); const graphics = @import("graphics.zig");
const PixelBufferRGA8 = @import("PixelBufferRGBA8.zig"); const PixelBufferRGA8 = @import("PixelBufferRGBA8.zig");
pub fn updateTextureFromPixelsSync( pub fn updateTextureFromPixelsSync(
textureName: core.Name, textureName: core.Name,
pixelBuffer: PixelBufferRGA8, pixelBuffer: PixelBufferRGA8,
) void { ) void {
graphics.getContext().updateTextureFromPixelsSync(textureName, pixelBuffer); graphics.getContext().updateTextureFromPixelsSync(textureName, pixelBuffer);
} }

View File

@ -1,95 +1,95 @@
// REEEEEEEEEEEEEE // REEEEEEEEEEEEEE
const std = @import("std"); const std = @import("std");
const core = @import("core"); const core = @import("core");
const vk = @import("vulkan"); const vk = @import("vulkan");
const vma = @import("vma"); const vma = @import("vma");
const vk_constants = @import("vk_constants.zig"); const vk_constants = @import("vk_constants.zig");
const vk_api = @import("vk_api.zig"); const vk_api = @import("vk_api.zig");
const vkd = vk_api.vkd; const vkd = vk_api.vkd;
pub fn transferDst_into_shaderReadOnly( pub fn transferDst_into_shaderReadOnly(
cmd: vk.CommandBuffer, cmd: vk.CommandBuffer,
image: vk.Image, image: vk.Image,
mipLevel: u32, mipLevel: u32,
baseArrayLayer: u32, baseArrayLayer: u32,
layerCount: u32, layerCount: u32,
) void { ) void {
if (mipLevel == 0) { if (mipLevel == 0) {
core.engine_logs("mipLevel 0 detected into_shaderReadOnly"); core.engine_logs("mipLevel 0 detected into_shaderReadOnly");
} }
const range = vk.ImageSubresourceRange{ const range = vk.ImageSubresourceRange{
.aspect_mask = .{ .color_bit = true }, .aspect_mask = .{ .color_bit = true },
.base_mip_level = 0, .base_mip_level = 0,
.level_count = mipLevel, .level_count = mipLevel,
.base_array_layer = baseArrayLayer, .base_array_layer = baseArrayLayer,
.layer_count = layerCount, .layer_count = layerCount,
}; };
var imageBarrier_toReadable = vk.ImageMemoryBarrier{ var imageBarrier_toReadable = vk.ImageMemoryBarrier{
.old_layout = .undefined, .old_layout = .undefined,
.new_layout = .shader_read_only_optimal, .new_layout = .shader_read_only_optimal,
.image = image, .image = image,
.subresource_range = range, .subresource_range = range,
.src_access_mask = .{ .transfer_write_bit = true }, .src_access_mask = .{ .transfer_write_bit = true },
.dst_access_mask = .{ .shader_read_bit = false }, .dst_access_mask = .{ .shader_read_bit = false },
.src_queue_family_index = 0, .src_queue_family_index = 0,
.dst_queue_family_index = 0, .dst_queue_family_index = 0,
}; };
vkd.cmdPipelineBarrier( vkd.cmdPipelineBarrier(
cmd, cmd,
.{ .transfer_bit = true }, .{ .transfer_bit = true },
.{ .fragment_shader_bit = true }, .{ .fragment_shader_bit = true },
.{}, .{},
0, 0,
undefined, undefined,
0, 0,
undefined, undefined,
1, 1,
@ptrCast(&imageBarrier_toReadable), @ptrCast(&imageBarrier_toReadable),
); );
} }
pub fn into_transferDst( pub fn into_transferDst(
cmd: vk.CommandBuffer, cmd: vk.CommandBuffer,
image: vk.Image, image: vk.Image,
mipLevel: u32, mipLevel: u32,
baseArrayLayer: u32, baseArrayLayer: u32,
layerCount: u32, layerCount: u32,
) void { ) void {
if (mipLevel == 0) { if (mipLevel == 0) {
core.engine_logs("mipLevel 0 detected into_transferDst"); core.engine_logs("mipLevel 0 detected into_transferDst");
} }
const range = vk.ImageSubresourceRange{ const range = vk.ImageSubresourceRange{
.aspect_mask = .{ .color_bit = true }, .aspect_mask = .{ .color_bit = true },
.base_mip_level = 0, .base_mip_level = 0,
.level_count = mipLevel, .level_count = mipLevel,
.base_array_layer = baseArrayLayer, .base_array_layer = baseArrayLayer,
.layer_count = layerCount, .layer_count = layerCount,
}; };
var imageBarrier_toTransfer = vk.ImageMemoryBarrier{ var imageBarrier_toTransfer = vk.ImageMemoryBarrier{
.old_layout = .undefined, .old_layout = .undefined,
.new_layout = .transfer_dst_optimal, .new_layout = .transfer_dst_optimal,
.image = image, .image = image,
.subresource_range = range, .subresource_range = range,
.src_access_mask = .{}, .src_access_mask = .{},
.dst_access_mask = .{ .transfer_write_bit = true }, .dst_access_mask = .{ .transfer_write_bit = true },
.src_queue_family_index = 0, .src_queue_family_index = 0,
.dst_queue_family_index = 0, .dst_queue_family_index = 0,
}; };
vkd.cmdPipelineBarrier( vkd.cmdPipelineBarrier(
cmd, cmd,
.{ .top_of_pipe_bit = true }, .{ .top_of_pipe_bit = true },
.{ .transfer_bit = true }, .{ .transfer_bit = true },
.{}, .{},
0, 0,
undefined, undefined,
0, 0,
undefined, undefined,
1, 1,
@ptrCast(&imageBarrier_toTransfer), @ptrCast(&imageBarrier_toTransfer),
); );
} }

View File

@ -1,143 +1,143 @@
// Game: Deathwish // Game: Deathwish
// Format: Standard // Format: Standard
// entity 0 // entity 0
{ {
"classname" "worldspawn" "classname" "worldspawn"
// brush 0 // brush 0
{ {
( -224 -32 -16 ) ( -224 -31 -16 ) ( -224 -32 -15 ) ProtoFloor 0 -16 0 1 1 ( -224 -32 -16 ) ( -224 -31 -16 ) ( -224 -32 -15 ) ProtoFloor 0 -16 0 1 1
( -224 -32 -16 ) ( -224 -32 -15 ) ( -223 -32 -16 ) ProtoFloor 0 -16 0 1 1 ( -224 -32 -16 ) ( -224 -32 -15 ) ( -223 -32 -16 ) ProtoFloor 0 -16 0 1 1
( -224 -32 -16 ) ( -223 -32 -16 ) ( -224 -31 -16 ) ProtoFloor 0 0 0 1 1 ( -224 -32 -16 ) ( -223 -32 -16 ) ( -224 -31 -16 ) ProtoFloor 0 0 0 1 1
( -192 32 0 ) ( -192 33 0 ) ( -191 32 0 ) ProtoFloor 0 0 0 1 1 ( -192 32 0 ) ( -192 33 0 ) ( -191 32 0 ) ProtoFloor 0 0 0 1 1
( -192 32 0 ) ( -191 32 0 ) ( -192 32 1 ) ProtoFloor 0 -16 0 1 1 ( -192 32 0 ) ( -191 32 0 ) ( -192 32 1 ) ProtoFloor 0 -16 0 1 1
( -64 32 0 ) ( -64 32 1 ) ( -64 33 0 ) ProtoFloor 0 -16 0 1 1 ( -64 32 0 ) ( -64 32 1 ) ( -64 33 0 ) ProtoFloor 0 -16 0 1 1
} }
// brush 1 // brush 1
{ {
( -576 -160 -32 ) ( -576 -159 -32 ) ( -576 -160 -31 ) ProtoGrass 16 -16 0 1 1 ( -576 -160 -32 ) ( -576 -159 -32 ) ( -576 -160 -31 ) ProtoGrass 16 -16 0 1 1
( 0 -400 -32 ) ( 0 -400 -31 ) ( 1 -400 -32 ) ProtoGrass -16 -16 0 1 1 ( 0 -400 -32 ) ( 0 -400 -31 ) ( 1 -400 -32 ) ProtoGrass -16 -16 0 1 1
( 0 -160 -32 ) ( 1 -160 -32 ) ( 0 -159 -32 ) ProtoGrass -16 -16 0 1 1 ( 0 -160 -32 ) ( 1 -160 -32 ) ( 0 -159 -32 ) ProtoGrass -16 -16 0 1 1
( 48 -144 -16 ) ( 48 -143 -16 ) ( 49 -144 -16 ) ProtoGrass -16 -16 0 1 1 ( 48 -144 -16 ) ( 48 -143 -16 ) ( 49 -144 -16 ) ProtoGrass -16 -16 0 1 1
( 48 224 -16 ) ( 49 224 -16 ) ( 48 224 -15 ) ProtoGrass -16 -16 0 1 1 ( 48 224 -16 ) ( 49 224 -16 ) ( 48 224 -15 ) ProtoGrass -16 -16 0 1 1
( 224 -144 -16 ) ( 224 -144 -15 ) ( 224 -143 -16 ) ProtoGrass 16 -16 0 1 1 ( 224 -144 -16 ) ( 224 -144 -15 ) ( 224 -143 -16 ) ProtoGrass 16 -16 0 1 1
} }
// brush 2 // brush 2
{ {
( -48 -144 -32 ) ( -48 -143 -32 ) ( -48 -144 -31 ) ProtoFloor 0 -32 0 1 1 ( -48 -144 -32 ) ( -48 -143 -32 ) ( -48 -144 -31 ) ProtoFloor 0 -32 0 1 1
( -48 -144 -32 ) ( -48 -144 -31 ) ( -47 -144 -32 ) ProtoFloor 0 -32 0 1 1 ( -48 -144 -32 ) ( -48 -144 -31 ) ( -47 -144 -32 ) ProtoFloor 0 -32 0 1 1
( -48 -144 -32 ) ( -47 -144 -32 ) ( -48 -143 -32 ) ProtoFloor 0 0 0 1 1 ( -48 -144 -32 ) ( -47 -144 -32 ) ( -48 -143 -32 ) ProtoFloor 0 0 0 1 1
( 80 -64 0 ) ( 80 -63 0 ) ( 81 -64 0 ) ProtoFloor 0 0 0 1 1 ( 80 -64 0 ) ( 80 -63 0 ) ( 81 -64 0 ) ProtoFloor 0 0 0 1 1
( 80 -64 -16 ) ( 81 -64 -16 ) ( 80 -64 -15 ) ProtoFloor 0 -32 0 1 1 ( 80 -64 -16 ) ( 81 -64 -16 ) ( 80 -64 -15 ) ProtoFloor 0 -32 0 1 1
( 80 -64 -16 ) ( 80 -64 -15 ) ( 80 -63 -16 ) ProtoFloor 0 -32 0 1 1 ( 80 -64 -16 ) ( 80 -64 -15 ) ( 80 -63 -16 ) ProtoFloor 0 -32 0 1 1
} }
// brush 3 // brush 3
{ {
( -48 -48 -32 ) ( -48 -47 -32 ) ( -48 -48 -31 ) ProtoFloor 32 -32 0 1 1 ( -48 -48 -32 ) ( -48 -47 -32 ) ( -48 -48 -31 ) ProtoFloor 32 -32 0 1 1
( -48 -48 -32 ) ( -48 -48 -31 ) ( -47 -48 -32 ) ProtoFloor 0 -32 0 1 1 ( -48 -48 -32 ) ( -48 -48 -31 ) ( -47 -48 -32 ) ProtoFloor 0 -32 0 1 1
( -48 -48 -32 ) ( -47 -48 -32 ) ( -48 -47 -32 ) ProtoFloor 0 -32 0 1 1 ( -48 -48 -32 ) ( -47 -48 -32 ) ( -48 -47 -32 ) ProtoFloor 0 -32 0 1 1
( 80 32 16 ) ( 80 33 16 ) ( 81 32 16 ) ProtoFloor 0 -32 0 1 1 ( 80 32 16 ) ( 80 33 16 ) ( 81 32 16 ) ProtoFloor 0 -32 0 1 1
( 80 32 -16 ) ( 81 32 -16 ) ( 80 32 -15 ) ProtoFloor 0 -32 0 1 1 ( 80 32 -16 ) ( 81 32 -16 ) ( 80 32 -15 ) ProtoFloor 0 -32 0 1 1
( 80 32 -16 ) ( 80 32 -15 ) ( 80 33 -16 ) ProtoFloor 32 -32 0 1 1 ( 80 32 -16 ) ( 80 32 -15 ) ( 80 33 -16 ) ProtoFloor 32 -32 0 1 1
} }
// brush 4 // brush 4
{ {
( -448 -96 -16 ) ( -448 -95 -16 ) ( -448 -96 -15 ) ProtoWallsGrey 0 0 0 1 1 ( -448 -96 -16 ) ( -448 -95 -16 ) ( -448 -96 -15 ) ProtoWallsGrey 0 0 0 1 1
( -448 -96 -16 ) ( -448 -96 -15 ) ( -447 -96 -16 ) ProtoWallsGrey 0 0 0 1 1 ( -448 -96 -16 ) ( -448 -96 -15 ) ( -447 -96 -16 ) ProtoWallsGrey 0 0 0 1 1
( -448 -96 -16 ) ( -447 -96 -16 ) ( -448 -95 -16 ) ProtoWallsGrey 0 0 0 1 1 ( -448 -96 -16 ) ( -447 -96 -16 ) ( -448 -95 -16 ) ProtoWallsGrey 0 0 0 1 1
( -432 80 48 ) ( -432 81 48 ) ( -431 80 48 ) ProtoWallsGrey 0 0 0 1 1 ( -432 80 48 ) ( -432 81 48 ) ( -431 80 48 ) ProtoWallsGrey 0 0 0 1 1
( -432 80 0 ) ( -431 80 0 ) ( -432 80 1 ) ProtoWallsGrey 0 0 0 1 1 ( -432 80 0 ) ( -431 80 0 ) ( -432 80 1 ) ProtoWallsGrey 0 0 0 1 1
( -432 80 0 ) ( -432 80 1 ) ( -432 81 0 ) ProtoWallsGrey 0 0 0 1 1 ( -432 80 0 ) ( -432 80 1 ) ( -432 81 0 ) ProtoWallsGrey 0 0 0 1 1
} }
// brush 5 // brush 5
{ {
( -416 -256 -16 ) ( -416 -255 -16 ) ( -416 -256 -15 ) ProtoWallsOrange 0 0 0 1 1 ( -416 -256 -16 ) ( -416 -255 -16 ) ( -416 -256 -15 ) ProtoWallsOrange 0 0 0 1 1
( -496 -256 -16 ) ( -496 -256 -15 ) ( -495 -256 -16 ) ProtoWallsOrange 0 0 0 1 1 ( -496 -256 -16 ) ( -496 -256 -15 ) ( -495 -256 -16 ) ProtoWallsOrange 0 0 0 1 1
( -496 -256 -16 ) ( -495 -256 -16 ) ( -496 -255 -16 ) ProtoWallsOrange 0 0 0 1 1 ( -496 -256 -16 ) ( -495 -256 -16 ) ( -496 -255 -16 ) ProtoWallsOrange 0 0 0 1 1
( -304 -240 96 ) ( -304 -239 96 ) ( -303 -240 96 ) ProtoWallsOrange 0 0 0 1 1 ( -304 -240 96 ) ( -304 -239 96 ) ( -303 -240 96 ) ProtoWallsOrange 0 0 0 1 1
( -304 -240 0 ) ( -303 -240 0 ) ( -304 -240 1 ) ProtoWallsOrange 0 0 0 1 1 ( -304 -240 0 ) ( -303 -240 0 ) ( -304 -240 1 ) ProtoWallsOrange 0 0 0 1 1
( -304 -240 0 ) ( -304 -240 1 ) ( -304 -239 0 ) ProtoWallsOrange 0 0 0 1 1 ( -304 -240 0 ) ( -304 -240 1 ) ( -304 -239 0 ) ProtoWallsOrange 0 0 0 1 1
} }
// brush 6 // brush 6
{ {
( -320 -384 -16 ) ( -320 -383 -16 ) ( -320 -384 -15 ) ProtoWallsOrange 0 0 0 1 1 ( -320 -384 -16 ) ( -320 -383 -16 ) ( -320 -384 -15 ) ProtoWallsOrange 0 0 0 1 1
( -320 -320 -16 ) ( -320 -320 -15 ) ( -319 -320 -16 ) ProtoWallsOrange 0 0 0 1 1 ( -320 -320 -16 ) ( -320 -320 -15 ) ( -319 -320 -16 ) ProtoWallsOrange 0 0 0 1 1
( -320 -384 -16 ) ( -319 -384 -16 ) ( -320 -383 -16 ) ProtoWallsOrange 0 0 0 1 1 ( -320 -384 -16 ) ( -319 -384 -16 ) ( -320 -383 -16 ) ProtoWallsOrange 0 0 0 1 1
( -304 -256 96 ) ( -304 -255 96 ) ( -303 -256 96 ) ProtoWallsOrange 0 0 0 1 1 ( -304 -256 96 ) ( -304 -255 96 ) ( -303 -256 96 ) ProtoWallsOrange 0 0 0 1 1
( -304 -256 0 ) ( -303 -256 0 ) ( -304 -256 1 ) ProtoWallsOrange 0 0 0 1 1 ( -304 -256 0 ) ( -303 -256 0 ) ( -304 -256 1 ) ProtoWallsOrange 0 0 0 1 1
( -304 -256 0 ) ( -304 -256 1 ) ( -304 -255 0 ) ProtoWallsOrange 0 0 0 1 1 ( -304 -256 0 ) ( -304 -256 1 ) ( -304 -255 0 ) ProtoWallsOrange 0 0 0 1 1
} }
// brush 7 // brush 7
{ {
( -480 -256 80 ) ( -480 -255 80 ) ( -480 -256 81 ) ProtoWallsOrange 0 0 0 1 1 ( -480 -256 80 ) ( -480 -255 80 ) ( -480 -256 81 ) ProtoWallsOrange 0 0 0 1 1
( -432 -256 80 ) ( -432 -256 81 ) ( -431 -256 80 ) ProtoWallsOrange 0 0 0 1 1 ( -432 -256 80 ) ( -432 -256 81 ) ( -431 -256 80 ) ProtoWallsOrange 0 0 0 1 1
( -432 -256 64 ) ( -431 -256 64 ) ( -432 -255 64 ) ProtoWallsOrange 0 0 0 1 1 ( -432 -256 64 ) ( -431 -256 64 ) ( -432 -255 64 ) ProtoWallsOrange 0 0 0 1 1
( -416 -240 96 ) ( -416 -239 96 ) ( -415 -240 96 ) ProtoWallsOrange 0 0 0 1 1 ( -416 -240 96 ) ( -416 -239 96 ) ( -415 -240 96 ) ProtoWallsOrange 0 0 0 1 1
( -416 -240 96 ) ( -415 -240 96 ) ( -416 -240 97 ) ProtoWallsOrange 0 0 0 1 1 ( -416 -240 96 ) ( -415 -240 96 ) ( -416 -240 97 ) ProtoWallsOrange 0 0 0 1 1
( -416 -240 96 ) ( -416 -240 97 ) ( -416 -239 96 ) ProtoWallsOrange 0 0 0 1 1 ( -416 -240 96 ) ( -416 -240 97 ) ( -416 -239 96 ) ProtoWallsOrange 0 0 0 1 1
} }
// brush 8 // brush 8
{ {
( -576 -256 -16 ) ( -576 -255 -16 ) ( -576 -256 -15 ) ProtoWallsOrange 0 0 0 1 1 ( -576 -256 -16 ) ( -576 -255 -16 ) ( -576 -256 -15 ) ProtoWallsOrange 0 0 0 1 1
( -672 -256 -16 ) ( -672 -256 -15 ) ( -671 -256 -16 ) ProtoWallsOrange -16 0 0 1 1 ( -672 -256 -16 ) ( -672 -256 -15 ) ( -671 -256 -16 ) ProtoWallsOrange -16 0 0 1 1
( -672 -256 -16 ) ( -671 -256 -16 ) ( -672 -255 -16 ) ProtoWallsOrange -16 0 0 1 1 ( -672 -256 -16 ) ( -671 -256 -16 ) ( -672 -255 -16 ) ProtoWallsOrange -16 0 0 1 1
( -480 -240 96 ) ( -480 -239 96 ) ( -479 -240 96 ) ProtoWallsOrange -16 0 0 1 1 ( -480 -240 96 ) ( -480 -239 96 ) ( -479 -240 96 ) ProtoWallsOrange -16 0 0 1 1
( -480 -240 0 ) ( -479 -240 0 ) ( -480 -240 1 ) ProtoWallsOrange -16 0 0 1 1 ( -480 -240 0 ) ( -479 -240 0 ) ( -480 -240 1 ) ProtoWallsOrange -16 0 0 1 1
( -480 -240 0 ) ( -480 -240 1 ) ( -480 -239 0 ) ProtoWallsOrange 0 0 0 1 1 ( -480 -240 0 ) ( -480 -240 1 ) ( -480 -239 0 ) ProtoWallsOrange 0 0 0 1 1
} }
// brush 9 // brush 9
{ {
( -416 -400 -16 ) ( -416 -399 -16 ) ( -416 -400 -15 ) ProtoWallsOrange 16 0 0 1 1 ( -416 -400 -16 ) ( -416 -399 -16 ) ( -416 -400 -15 ) ProtoWallsOrange 16 0 0 1 1
( -496 -400 -16 ) ( -496 -400 -15 ) ( -495 -400 -16 ) ProtoWallsOrange 0 0 0 1 1 ( -496 -400 -16 ) ( -496 -400 -15 ) ( -495 -400 -16 ) ProtoWallsOrange 0 0 0 1 1
( -496 -400 -16 ) ( -495 -400 -16 ) ( -496 -399 -16 ) ProtoWallsOrange 0 -16 0 1 1 ( -496 -400 -16 ) ( -495 -400 -16 ) ( -496 -399 -16 ) ProtoWallsOrange 0 -16 0 1 1
( -304 -384 96 ) ( -304 -383 96 ) ( -303 -384 96 ) ProtoWallsOrange 0 -16 0 1 1 ( -304 -384 96 ) ( -304 -383 96 ) ( -303 -384 96 ) ProtoWallsOrange 0 -16 0 1 1
( -304 -384 0 ) ( -303 -384 0 ) ( -304 -384 1 ) ProtoWallsOrange 0 0 0 1 1 ( -304 -384 0 ) ( -303 -384 0 ) ( -304 -384 1 ) ProtoWallsOrange 0 0 0 1 1
( -304 -384 0 ) ( -304 -384 1 ) ( -304 -383 0 ) ProtoWallsOrange 16 0 0 1 1 ( -304 -384 0 ) ( -304 -384 1 ) ( -304 -383 0 ) ProtoWallsOrange 16 0 0 1 1
} }
// brush 10 // brush 10
{ {
( -320 -384 80 ) ( -320 -383 80 ) ( -320 -384 81 ) ProtoWallsOrange 0 0 0 1 1 ( -320 -384 80 ) ( -320 -383 80 ) ( -320 -384 81 ) ProtoWallsOrange 0 0 0 1 1
( -320 -384 80 ) ( -320 -384 81 ) ( -319 -384 80 ) ProtoWallsOrange 0 0 0 1 1 ( -320 -384 80 ) ( -320 -384 81 ) ( -319 -384 80 ) ProtoWallsOrange 0 0 0 1 1
( -320 -384 64 ) ( -319 -384 64 ) ( -320 -383 64 ) ProtoWallsOrange 0 0 0 1 1 ( -320 -384 64 ) ( -319 -384 64 ) ( -320 -383 64 ) ProtoWallsOrange 0 0 0 1 1
( -288 -352 96 ) ( -288 -351 96 ) ( -287 -352 96 ) ProtoWallsOrange 0 0 0 1 1 ( -288 -352 96 ) ( -288 -351 96 ) ( -287 -352 96 ) ProtoWallsOrange 0 0 0 1 1
( -288 -320 96 ) ( -287 -320 96 ) ( -288 -320 97 ) ProtoWallsOrange 0 0 0 1 1 ( -288 -320 96 ) ( -287 -320 96 ) ( -288 -320 97 ) ProtoWallsOrange 0 0 0 1 1
( -304 -352 96 ) ( -304 -352 97 ) ( -304 -351 96 ) ProtoWallsOrange 0 0 0 1 1 ( -304 -352 96 ) ( -304 -352 97 ) ( -304 -351 96 ) ProtoWallsOrange 0 0 0 1 1
} }
// brush 11 // brush 11
{ {
( -208 -304 -16 ) ( -208 -303 -16 ) ( -208 -304 -15 ) ProtoWallsGrey 32 0 0 1 1 ( -208 -304 -16 ) ( -208 -303 -16 ) ( -208 -304 -15 ) ProtoWallsGrey 32 0 0 1 1
( -208 -304 -16 ) ( -208 -304 -15 ) ( -207 -304 -16 ) ProtoWallsGrey -16 0 0 1 1 ( -208 -304 -16 ) ( -208 -304 -15 ) ( -207 -304 -16 ) ProtoWallsGrey -16 0 0 1 1
( -208 -304 -16 ) ( -207 -304 -16 ) ( -208 -303 -16 ) ProtoWallsGrey -16 -32 0 1 1 ( -208 -304 -16 ) ( -207 -304 -16 ) ( -208 -303 -16 ) ProtoWallsGrey -16 -32 0 1 1
( -144 -256 80 ) ( -144 -255 80 ) ( -143 -256 80 ) ProtoWallsGrey -16 -32 0 1 1 ( -144 -256 80 ) ( -144 -255 80 ) ( -143 -256 80 ) ProtoWallsGrey -16 -32 0 1 1
( -144 -208 0 ) ( -143 -208 0 ) ( -144 -208 1 ) ProtoWallsGrey -16 0 0 1 1 ( -144 -208 0 ) ( -143 -208 0 ) ( -144 -208 1 ) ProtoWallsGrey -16 0 0 1 1
( -32 -256 0 ) ( -32 -256 1 ) ( -32 -255 0 ) ProtoWallsGrey 32 0 0 1 1 ( -32 -256 0 ) ( -32 -256 1 ) ( -32 -255 0 ) ProtoWallsGrey 32 0 0 1 1
} }
// brush 12 // brush 12
{ {
( -544 -384 96 ) ( -544 -383 96 ) ( -544 -384 97 ) ProtoWallsGrey 0 0 0 1 1 ( -544 -384 96 ) ( -544 -383 96 ) ( -544 -384 97 ) ProtoWallsGrey 0 0 0 1 1
( -544 -384 96 ) ( -544 -384 97 ) ( -543 -384 96 ) ProtoWallsGrey 0 0 0 1 1 ( -544 -384 96 ) ( -544 -384 97 ) ( -543 -384 96 ) ProtoWallsGrey 0 0 0 1 1
( -544 -384 96 ) ( -543 -384 96 ) ( -544 -383 96 ) ProtoWallsGrey 0 0 0 1 1 ( -544 -384 96 ) ( -543 -384 96 ) ( -544 -383 96 ) ProtoWallsGrey 0 0 0 1 1
( -304 -256 112 ) ( -304 -255 112 ) ( -303 -256 112 ) ProtoWallsGrey 0 0 0 1 1 ( -304 -256 112 ) ( -304 -255 112 ) ( -303 -256 112 ) ProtoWallsGrey 0 0 0 1 1
( -304 -256 112 ) ( -303 -256 112 ) ( -304 -256 113 ) ProtoWallsGrey 0 0 0 1 1 ( -304 -256 112 ) ( -303 -256 112 ) ( -304 -256 113 ) ProtoWallsGrey 0 0 0 1 1
( -304 -256 112 ) ( -304 -256 113 ) ( -304 -255 112 ) ProtoWallsGrey 0 0 0 1 1 ( -304 -256 112 ) ( -304 -256 113 ) ( -304 -255 112 ) ProtoWallsGrey 0 0 0 1 1
} }
} }
// entity 1 // entity 1
{ {
"classname" "enemy_spawn" "classname" "enemy_spawn"
"origin" "-480 64 8" "origin" "-480 64 8"
} }
// entity 2 // entity 2
{ {
"classname" "info_player_start" "classname" "info_player_start"
"origin" "176 -224 8" "origin" "176 -224 8"
} }
// entity 3 // entity 3
{ {
"classname" "enemy_spawn" "classname" "enemy_spawn"
"origin" "-480 -16 8" "origin" "-480 -16 8"
} }
// entity 4 // entity 4
{ {
"classname" "enemy_spawn" "classname" "enemy_spawn"
"origin" "-352 -288 8" "origin" "-352 -288 8"
} }

View File

@ -1,46 +1,46 @@
const std = @import("std"); const std = @import("std");
const graphics = @import("graphics"); const graphics = @import("graphics");
const core = @import("core"); const core = @import("core");
const platform = @import("platform"); const platform = @import("platform");
const QuakeMap = graphics.QuakeMap; const QuakeMap = graphics.QuakeMap;
test "simple_integration" { test "simple_integration" {
// this doesn't really do anything other than just a simple compile check // this doesn't really do anything other than just a simple compile check
std.debug.print("sizeof NeonVkContext = {d}\n", .{@sizeOf(graphics.NeonVkContext)}); std.debug.print("sizeof NeonVkContext = {d}\n", .{@sizeOf(graphics.NeonVkContext)});
std.debug.print("sizeof triangle_mesh_vert.ObjectData = {d}\n", .{@sizeOf(graphics.vk_renderer.triangle_mesh_vert.ObjectData)}); std.debug.print("sizeof triangle_mesh_vert.ObjectData = {d}\n", .{@sizeOf(graphics.vk_renderer.triangle_mesh_vert.ObjectData)});
} }
test "renderthread queue" { test "renderthread queue" {
const allocator = std.testing.allocator; const allocator = std.testing.allocator;
try core.start_module(.{}, .{}, allocator); try core.start_module(.{}, .{}, allocator);
defer core.shutdown_module(allocator); defer core.shutdown_module(allocator);
} }
test "quake map loading" { test "quake map loading" {
// const TestMap = @embedFile("testmap.map"); // const TestMap = @embedFile("testmap.map");
const testmapFile = const testmapFile =
\\{ \\{
\\"spawnflags" "0" \\"spawnflags" "0"
\\"classname" "worldspawn" \\"classname" "worldspawn"
\\"wad" "E:\q1maps\Q.wad" \\"wad" "E:\q1maps\Q.wad"
\\{ \\{
\\( 256 64 16 ) ( 256 64 0 ) ( 256 0 16 ) mmetal1_2 0 0 0 1 1 \\( 256 64 16 ) ( 256 64 0 ) ( 256 0 16 ) mmetal1_2 0 0 0 1 1
\\( 0 0 0 ) ( 0 64 0 ) ( 0 0 16 ) mmetal1_2 0 0 0 1 1 \\( 0 0 0 ) ( 0 64 0 ) ( 0 0 16 ) mmetal1_2 0 0 0 1 1
\\( 64 256 16 ) ( 0 256 16 ) ( 64 256 0 ) mmetal1_2 0 0 0 1 1 \\( 64 256 16 ) ( 0 256 16 ) ( 64 256 0 ) mmetal1_2 0 0 0 1 1
\\( 0 0 0 ) ( 0 0 16 ) ( 64 0 0 ) mmetal1_2 0 0 0 1 1 \\( 0 0 0 ) ( 0 0 16 ) ( 64 0 0 ) mmetal1_2 0 0 0 1 1
\\( 64 64 0 ) ( 64 0 0 ) ( 0 64 0 ) mmetal1_2 0 0 0 1 1 \\( 64 64 0 ) ( 64 0 0 ) ( 0 64 0 ) mmetal1_2 0 0 0 1 1
\\( 0 0 -64 ) ( 64 0 -64 ) ( 0 64 -64 ) mmetal1_2 0 0 0 1 1 \\( 0 0 -64 ) ( 64 0 -64 ) ( 0 64 -64 ) mmetal1_2 0 0 0 1 1
\\} \\}
\\} \\}
\\{ \\{
\\"spawnflags" "0" \\"spawnflags" "0"
\\"classname" "info_player_start" \\"classname" "info_player_start"
\\"origin" "32 32 24" \\"origin" "32 32 24"
\\} \\}
; ;
var err: QuakeMap.ErrorInfo = undefined; var err: QuakeMap.ErrorInfo = undefined;
var map = try QuakeMap.read(std.testing.allocator, testmapFile, &err); var map = try QuakeMap.read(std.testing.allocator, testmapFile, &err);
defer map.deinit(); defer map.deinit();
} }

View File

@ -0,0 +1,2 @@
plunder these ones for features to
implement in rend

View File

@ -1,17 +1,17 @@
.{ .{
.name = "ui", .name = "ui",
.version = "0.0.0", .version = "0.0.0",
.dependencies = .{ .dependencies = .{
.vulkan = .{ .path = "../../lib/vulkan" }, .vulkan = .{ .path = "../../lib/vulkan" },
.SpirvReflect = .{ .path = "../../lib/spirv-reflect-zig" }, .SpirvReflect = .{ .path = "../../lib/spirv-reflect-zig" },
.papyrus = .{ .path = "../papyrus" }, .papyrus = .{ .path = "../papyrus" },
.assets = .{ .path = "../assets" }, .assets = .{ .path = "../assets" },
.platform = .{ .path = "../platform" }, .platform = .{ .path = "../platform" },
.core = .{ .path = "../core" }, .core = .{ .path = "../core" },
.graphics = .{ .path = "../graphics" }, .graphics = .{ .path = "../graphics" },
}, },
.paths = .{ .paths = .{
"", "",
}, },
} }

View File

@ -1,69 +1,69 @@
#version 460 #version 460
layout (location = 0) in vec4 color; layout (location = 0) in vec4 color;
layout (location = 1) in vec2 texCoord; layout (location = 1) in vec2 texCoord;
layout (location = 2) flat in int instanceId; layout (location = 2) flat in int instanceId;
layout (location = 3) in vec2 pixelPosition; layout (location = 3) in vec2 pixelPosition;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
layout (set = 1, binding = 0) uniform sampler2D tex; layout (set = 1, binding = 0) uniform sampler2D tex;
#include "FontSDFShared.glsl" #include "FontSDFShared.glsl"
#include "FragmentHelpers.glsl" #include "FragmentHelpers.glsl"
void main() { void main() {
vec4 tex = texture(tex, texCoord); vec4 tex = texture(tex, texCoord);
uint isSdf = fontBuffer.fontInfo[instanceId].isSdf; uint isSdf = fontBuffer.fontInfo[instanceId].isSdf;
vec2 position = fontBuffer.fontInfo[instanceId].position; vec2 position = fontBuffer.fontInfo[instanceId].position;
vec2 size = fontBuffer.fontInfo[instanceId].size; vec2 size = fontBuffer.fontInfo[instanceId].size;
if(!scissor(pixelPosition, position, size)) if(!scissor(pixelPosition, position, size))
{ {
discard; discard;
} }
if(isSdf == 1) if(isSdf == 1)
{ {
float dist = tex.r; float dist = tex.r;
float width = fwidth(dist); float width = fwidth(dist);
vec4 textColor = clamp(color, 0.0, 1.0); vec4 textColor = clamp(color, 0.0, 1.0);
float outerEdge = 1.0f - (120.0f / 255.0f); float outerEdge = 1.0f - (120.0f / 255.0f);
float alpha = contour(dist, outerEdge, width); float alpha = contour(dist, outerEdge, width);
float dscale = 0.354; // half of 1/sqrt2; you can play with this float dscale = 0.354; // half of 1/sqrt2; you can play with this
vec2 uv = texCoord.xy; vec2 uv = texCoord.xy;
vec2 duv = dscale * (dFdx(uv) + dFdy(uv)); vec2 duv = dscale * (dFdx(uv) + dFdy(uv));
vec4 box = vec4(uv - duv, uv + duv); vec4 box = vec4(uv - duv, uv + duv);
float asum = getSample(box.xy, outerEdge, width) float asum = getSample(box.xy, outerEdge, width)
+ getSample(box.zw, outerEdge, width) + getSample(box.zw, outerEdge, width)
+ getSample(box.xw, outerEdge, width) + getSample(box.xw, outerEdge, width)
+ getSample(box.zy, outerEdge, width); + getSample(box.zy, outerEdge, width);
// weighted average, with 4 extra points having 0.5 weight each, // weighted average, with 4 extra points having 0.5 weight each,
// so 1 + 0.5*4 = 3 is the divisor // so 1 + 0.5*4 = 3 is the divisor
alpha = (alpha + 0.5 * asum) / 3.0; alpha = (alpha + 0.5 * asum) / 3.0;
textColor = vec4(color.xyz, alpha);//textColor.* alpha); textColor = vec4(color.xyz, alpha);//textColor.* alpha);
textColor.xyz = pow(textColor.xyz, vec3(2.2)); // gamma correction textColor.xyz = pow(textColor.xyz, vec3(2.2)); // gamma correction
// Premultiplied alpha output. // Premultiplied alpha output.
outFragColor = textColor; outFragColor = textColor;
} }
else { else {
float alpha = 1.0; float alpha = 1.0;
float gray = dot(color.xyz, vec3(0.2126, 0.7152, 0.0722)); float gray = dot(color.xyz, vec3(0.2126, 0.7152, 0.0722));
outFragColor = vec4(color.xyz , pow(tex.x / gray, 1/(2.2)) );//textColor.* alpha); outFragColor = vec4(color.xyz , pow(tex.x / gray, 1/(2.2)) );//textColor.* alpha);
//outFragColor = vec4(1.0, 0.0, 0.0, 1.0); //outFragColor = vec4(1.0, 0.0, 0.0, 1.0);
} }
/* debug test. /* debug test.
if(!rect(pixelPosition, position, size)) if(!rect(pixelPosition, position, size))
{ {
outFragColor = vec4(1.0, 0.0, 0.0, 1.0); outFragColor = vec4(1.0, 0.0, 0.0, 1.0);
} }
*/ */
} }

View File

@ -1,28 +1,28 @@
#version 460 #version 460
layout(location = 0) in vec3 texPosition; layout(location = 0) in vec3 texPosition;
layout(location = 1) in vec3 texNormal; layout(location = 1) in vec3 texNormal;
layout(location = 2) in vec4 texColor; layout(location = 2) in vec4 texColor;
layout(location = 3) in vec2 texCoord; layout(location = 3) in vec2 texCoord;
layout (location = 0) out vec4 fragColor; layout (location = 0) out vec4 fragColor;
layout (location = 1) out vec2 texCoords; layout (location = 1) out vec2 texCoords;
layout (location = 2) out int instanceId; layout (location = 2) out int instanceId;
layout (location = 3) out vec2 pixelPosition; layout (location = 3) out vec2 pixelPosition;
#include "FontSDFShared.glsl" #include "FontSDFShared.glsl"
void main() void main()
{ {
vec2 pos = fontBuffer.fontInfo[gl_BaseInstance].position; vec2 pos = fontBuffer.fontInfo[gl_BaseInstance].position;
vec2 size = fontBuffer.fontInfo[gl_BaseInstance].size; vec2 size = fontBuffer.fontInfo[gl_BaseInstance].size;
vec2 t = texPosition.xy + pos; vec2 t = texPosition.xy + pos;
pixelPosition = t; pixelPosition = t;
//gl_Position = vec4(( (texPosition.xy + pos) / PushConstants.extent) * 2 + vec2(-1.0f, -1.0f), texPosition.z, 1.0); //gl_Position = vec4(( (texPosition.xy + pos) / PushConstants.extent) * 2 + vec2(-1.0f, -1.0f), texPosition.z, 1.0);
gl_Position = vec4((t / PushConstants.extent) * 2 + vec2(-1.0f, -1.0f), texPosition.z, 1.0); gl_Position = vec4((t / PushConstants.extent) * 2 + vec2(-1.0f, -1.0f), texPosition.z, 1.0);
texCoords = texCoord; texCoords = texCoord;
fragColor = texColor; fragColor = texColor;
instanceId = gl_BaseInstance; instanceId = gl_BaseInstance;
} }

View File

@ -1,111 +1,111 @@
#version 460 #version 460
//shader input //shader input
layout (location = 0) in vec4 fragColor; layout (location = 0) in vec4 fragColor;
layout (location = 1) in vec2 texCoord; layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec2 panelPixelPosition; // relative to the topleft layout (location = 2) in vec2 panelPixelPosition; // relative to the topleft
layout (location = 3) flat in int instanceId; layout (location = 3) flat in int instanceId;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
layout (set = 1, binding = 0) uniform sampler2D tex; layout (set = 1, binding = 0) uniform sampler2D tex;
#include "PapyrusRectShared.glsl" #include "PapyrusRectShared.glsl"
#include "FragmentHelpers.glsl" #include "FragmentHelpers.glsl"
void main() void main()
{ {
vec2 imageSize = objectBuffer.objects[instanceId].imageSize; vec2 imageSize = objectBuffer.objects[instanceId].imageSize;
vec4 rounding = objectBuffer.objects[instanceId].rounding; vec4 rounding = objectBuffer.objects[instanceId].rounding;
vec4 borderColor = objectBuffer.objects[instanceId].borderColor; vec4 borderColor = objectBuffer.objects[instanceId].borderColor;
float borderWidth = objectBuffer.objects[instanceId].borderWidth; float borderWidth = objectBuffer.objects[instanceId].borderWidth;
float alpha = fragColor.w; float alpha = fragColor.w;
uint usesImage = objectBuffer.objects[instanceId].flags & 1; uint usesImage = objectBuffer.objects[instanceId].flags & 1;
// check to discard topleft // check to discard topleft
vec3 color = fragColor.xyz; vec3 color = fragColor.xyz;
if(panelPixelPosition.x < rounding.x && panelPixelPosition.y < rounding.y) if(panelPixelPosition.x < rounding.x && panelPixelPosition.y < rounding.y)
{ {
float dist = distance(panelPixelPosition, vec2(rounding.x, rounding.x)); float dist = distance(panelPixelPosition, vec2(rounding.x, rounding.x));
if(dist > (rounding.x )) if(dist > (rounding.x ))
{ {
discard; discard;
} }
else if(somewhatEqual(dist, rounding.x)) else if(somewhatEqual(dist, rounding.x))
{ {
color = borderColor.xyz; color = borderColor.xyz;
alpha = borderColor.w; alpha = borderColor.w;
} }
} }
// top right // top right
if(panelPixelPosition.x > imageSize.x - rounding.y && panelPixelPosition.y < rounding.y ) if(panelPixelPosition.x > imageSize.x - rounding.y && panelPixelPosition.y < rounding.y )
{ {
float dist = distance(panelPixelPosition, vec2(imageSize.x - rounding.y, rounding.y)); float dist = distance(panelPixelPosition, vec2(imageSize.x - rounding.y, rounding.y));
if(dist > rounding.y) if(dist > rounding.y)
{ {
discard; discard;
} }
else if(somewhatEqual(dist, rounding.y)) else if(somewhatEqual(dist, rounding.y))
{ {
color = borderColor.xyz; color = borderColor.xyz;
alpha = borderColor.w; alpha = borderColor.w;
} }
} }
// bottom Left // bottom Left
if(panelPixelPosition.x < rounding.x && panelPixelPosition.y > imageSize.y - rounding.y) if(panelPixelPosition.x < rounding.x && panelPixelPosition.y > imageSize.y - rounding.y)
{ {
float dist = distance(panelPixelPosition, vec2(rounding.x, imageSize.y - rounding.y)); float dist = distance(panelPixelPosition, vec2(rounding.x, imageSize.y - rounding.y));
if(dist > rounding.y) if(dist > rounding.y)
{ {
discard; discard;
} }
else if(somewhatEqual(dist, rounding.y)) else if(somewhatEqual(dist, rounding.y))
{ {
color = borderColor.xyz; color = borderColor.xyz;
alpha = borderColor.w; alpha = borderColor.w;
} }
} }
// bottom right // bottom right
if(panelPixelPosition.x > imageSize.x - rounding.a && imageSize.y - panelPixelPosition.y < rounding.a ) if(panelPixelPosition.x > imageSize.x - rounding.a && imageSize.y - panelPixelPosition.y < rounding.a )
{ {
float dist = distance(panelPixelPosition, vec2(imageSize.x - rounding.x, imageSize.y - rounding.y)); float dist = distance(panelPixelPosition, vec2(imageSize.x - rounding.x, imageSize.y - rounding.y));
if(dist > rounding.y) if(dist > rounding.y)
{ {
discard; discard;
} }
else if(somewhatEqual(dist, rounding.y)) else if(somewhatEqual(dist, rounding.y))
{ {
color = borderColor.xyz; color = borderColor.xyz;
alpha = borderColor.w; alpha = borderColor.w;
} }
} }
// check to discard topright // check to discard topright
// determine border colors // determine border colors
if( panelPixelPosition.x < borderWidth if( panelPixelPosition.x < borderWidth
|| panelPixelPosition.x > imageSize.x - borderWidth || panelPixelPosition.x > imageSize.x - borderWidth
|| panelPixelPosition.y < borderWidth || panelPixelPosition.y < borderWidth
|| panelPixelPosition.y > imageSize.y - borderWidth || panelPixelPosition.y > imageSize.y - borderWidth
) )
{ {
color = borderColor.xyz; color = borderColor.xyz;
alpha = borderColor.w; alpha = borderColor.w;
} }
// scale the color // scale the color
if(usesImage > 0) if(usesImage > 0)
{ {
vec4 sampledColor = texture(tex, vec2(texCoord.x, 1 - texCoord.y)); vec4 sampledColor = texture(tex, vec2(texCoord.x, 1 - texCoord.y));
outFragColor = vec4(sampledColor.rgb, sampledColor.a * alpha); outFragColor = vec4(sampledColor.rgb, sampledColor.a * alpha);
} }
else else
{ {
outFragColor = vec4(pow(color, vec3(2.2)), alpha); outFragColor = vec4(pow(color, vec3(2.2)), alpha);
} }
} }

View File

@ -1,46 +1,46 @@
//we will be using glsl version 4.5 syntax //we will be using glsl version 4.5 syntax
#version 460 #version 460
layout (location = 0) in vec3 vPosition; layout (location = 0) in vec3 vPosition;
layout (location = 1) in vec3 vNormal; layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec4 vColor; layout (location = 2) in vec4 vColor;
layout (location = 3) in vec2 vTexCoord; layout (location = 3) in vec2 vTexCoord;
layout (location = 0) out vec4 outColor; layout (location = 0) out vec4 outColor;
layout (location = 1) out vec2 texCoord; layout (location = 1) out vec2 texCoord;
layout (location = 2) out vec2 panelPixelPosition; layout (location = 2) out vec2 panelPixelPosition;
layout (location = 3) out int instanceId; layout (location = 3) out int instanceId;
#include "PapyrusRectShared.glsl" #include "PapyrusRectShared.glsl"
void main() void main()
{ {
vec2 imagePosition = objectBuffer.objects[gl_BaseInstance].imagePosition; vec2 imagePosition = objectBuffer.objects[gl_BaseInstance].imagePosition;
vec2 imageSize = objectBuffer.objects[gl_BaseInstance].imageSize; vec2 imageSize = objectBuffer.objects[gl_BaseInstance].imageSize;
vec2 anchor = objectBuffer.objects[gl_BaseInstance].anchorPoint; vec2 anchor = objectBuffer.objects[gl_BaseInstance].anchorPoint;
vec2 scale = objectBuffer.objects[gl_BaseInstance].scale; vec2 scale = objectBuffer.objects[gl_BaseInstance].scale;
float alpha = objectBuffer.objects[gl_BaseInstance].alpha; float alpha = objectBuffer.objects[gl_BaseInstance].alpha;
vec4 baseColor = objectBuffer.objects[gl_BaseInstance].baseColor; vec4 baseColor = objectBuffer.objects[gl_BaseInstance].baseColor;
vec2 finalSize = (imageSize / PushConstants.extent); vec2 finalSize = (imageSize / PushConstants.extent);
//float zLevel = objectBuffer.objects[gl_BaseInstance].zLevel; //float zLevel = objectBuffer.objects[gl_BaseInstance].zLevel;
vec2 finalPos = ((imagePosition / PushConstants.extent) * 2 - 1) - anchor * finalSize * scale; vec2 finalPos = ((imagePosition / PushConstants.extent) * 2 - 1) - anchor * finalSize * scale;
outColor = baseColor; outColor = baseColor;
//outColor = vec3(vColor.x, vColor.y, vColor.z); //outColor = vec3(vColor.x, vColor.y, vColor.z);
vec4 fp = vec4( vec4 fp = vec4(
finalPos.x + ( vPosition.x * finalSize.x * scale.x), finalPos.x + ( vPosition.x * finalSize.x * scale.x),
finalPos.y + (-vPosition.y * finalSize.y * scale.y), finalPos.y + (-vPosition.y * finalSize.y * scale.y),
vPosition.z, 1.0 vPosition.z, 1.0
); );
//1.0); //1.0);
gl_Position = fp; gl_Position = fp;
//gl_Position = vec4( ((position.x) - 1.3) * 0.3 * 1.3, (-position.y + 0.05) * 1.3, position.z, 1.0); // + vec4(imagePosition, 0.0f, 1.0f); //gl_Position = vec4( ((position.x) - 1.3) * 0.3 * 1.3, (-position.y + 0.05) * 1.3, position.z, 1.0); // + vec4(imagePosition, 0.0f, 1.0f);
texCoord = vec2(1 - vTexCoord.x, vTexCoord.y); texCoord = vec2(1 - vTexCoord.x, vTexCoord.y);
panelPixelPosition = (vPosition.xy - anchor) / 2 * imageSize; panelPixelPosition = (vPosition.xy - anchor) / 2 * imageSize;
panelPixelPosition.y = imageSize.y - panelPixelPosition.y; panelPixelPosition.y = imageSize.y - panelPixelPosition.y;
instanceId = gl_BaseInstance; instanceId = gl_BaseInstance;
} }

View File

@ -1,14 +1,14 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
pub const VkCommand = union(enum(u8)) { pub const VkCommand = union(enum(u8)) {
image: struct { image: struct {
index: u32, index: u32,
imageSet: ?vk.DescriptorSet, imageSet: ?vk.DescriptorSet,
}, },
text: struct { text: struct {
index: u32, index: u32,
small: bool, small: bool,
ssbo: u32, ssbo: u32,
}, },
}; };

View File

@ -1,46 +1,46 @@
const std = @import("std"); const std = @import("std");
const core = @import("core"); const core = @import("core");
const graphics = @import("graphics"); const graphics = @import("graphics");
const memory = core.MemoryTracker; const memory = core.MemoryTracker;
pub const papyrus = @import("papyrus"); pub const papyrus = @import("papyrus");
pub const HandlerError = papyrus.HandlerError; pub const HandlerError = papyrus.HandlerError;
pub const NodeHandle = papyrus.NodeHandle; pub const NodeHandle = papyrus.NodeHandle;
pub const LocText = papyrus.LocText; pub const LocText = papyrus.LocText;
pub const PressedType = papyrus.PressedType; pub const PressedType = papyrus.PressedType;
pub const PapyrusSystem = @import("PapyrusIntegration.zig"); pub const PapyrusSystem = @import("PapyrusIntegration.zig");
var gPapyrus: *PapyrusSystem = undefined; var gPapyrus: *PapyrusSystem = undefined;
pub const Module: core.ModuleDescription = .{ pub const Module: core.ModuleDescription = .{
.name = "ui", .name = "ui",
.enabledByDefault = true, .enabledByDefault = true,
}; };
pub fn getSystem() *PapyrusSystem { pub fn getSystem() *PapyrusSystem {
return gPapyrus; return gPapyrus;
} }
pub fn getContext() *papyrus.Context { pub fn getContext() *papyrus.Context {
return gPapyrus.papyrusCtx; return gPapyrus.papyrusCtx;
} }
pub fn start_module(comptime spec: anytype, args: anytype, allocator: std.mem.Allocator) !void { pub fn start_module(comptime spec: anytype, args: anytype, allocator: std.mem.Allocator) !void {
_ = args; _ = args;
_ = spec; _ = spec;
_ = allocator; _ = allocator;
// no initialization // no initialization
if (core.isUtility()) { if (core.isUtility()) {
return; return;
} }
gPapyrus = try core.gEngine.createObject(PapyrusSystem, .{ .can_tick = true }); gPapyrus = try core.gEngine.createObject(PapyrusSystem, .{ .can_tick = true });
try gPapyrus.setup(graphics.getContext()); try gPapyrus.setup(graphics.getContext());
core.engine_logs("ui start_module"); core.engine_logs("ui start_module");
memory.MTPrintStatsDelta(); memory.MTPrintStatsDelta();
} }
pub fn shutdown_module(allocator: std.mem.Allocator) void { pub fn shutdown_module(allocator: std.mem.Allocator) void {
_ = allocator; _ = allocator;
} }

View File

@ -1,86 +1,86 @@
const std = @import("std"); const std = @import("std");
// very tiny, not intended to build anything just to run tests linked with libc // very tiny, not intended to build anything just to run tests linked with libc
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 mod = b.addModule("vkImgui", .{ const mod = b.addModule("vkImgui", .{
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
.link_libc = true, .link_libc = true,
.root_source_file = b.path("src/vkImgui.zig"), .root_source_file = b.path("src/vkImgui.zig"),
}); });
mod.addIncludePath(b.path("cimgui")); mod.addIncludePath(b.path("cimgui"));
mod.addIncludePath(b.path("cimplot")); mod.addIncludePath(b.path("cimplot"));
mod.addIncludePath(b.path("cimgui/imgui")); mod.addIncludePath(b.path("cimgui/imgui"));
mod.addIncludePath(b.path("cimgui/imgui/backends")); mod.addIncludePath(b.path("cimgui/imgui/backends"));
const cimgui = b.addStaticLibrary(.{ const cimgui = b.addStaticLibrary(.{
.name = "cimgui", .name = "cimgui",
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
}); });
cimgui.linkLibC(); cimgui.linkLibC();
if (target.result.abi != .msvc) if (target.result.abi != .msvc)
cimgui.linkLibCpp(); cimgui.linkLibCpp();
cimgui.addIncludePath(b.path("cimgui")); cimgui.addIncludePath(b.path("cimgui"));
cimgui.addIncludePath(b.path("cimplot")); cimgui.addIncludePath(b.path("cimplot"));
cimgui.addIncludePath(b.path("cimgui/imgui")); cimgui.addIncludePath(b.path("cimgui/imgui"));
cimgui.addIncludePath(b.path("cimgui/imgui/backends")); cimgui.addIncludePath(b.path("cimgui/imgui/backends"));
cimgui.addCSourceFiles(.{ cimgui.addCSourceFiles(.{
.root = b.path("cimgui/imgui"), .root = b.path("cimgui/imgui"),
.files = &[_][]const u8{ .files = &[_][]const u8{
"cimgui.cpp", "cimgui.cpp",
"cimgui_compat.cpp", "cimgui_compat.cpp",
"imgui.cpp", "imgui.cpp",
"imgui_demo.cpp", "imgui_demo.cpp",
"imgui_draw.cpp", "imgui_draw.cpp",
"imgui_tables.cpp", "imgui_tables.cpp",
"imgui_widgets.cpp", "imgui_widgets.cpp",
"backends/imgui_impl_vulkan.cpp", "backends/imgui_impl_vulkan.cpp",
"backends/imgui_impl_glfw.cpp", "backends/imgui_impl_glfw.cpp",
}, },
}); });
cimgui.addCSourceFiles(.{ cimgui.addCSourceFiles(.{
.root = b.path("cimplot"), .root = b.path("cimplot"),
.files = &[_][]const u8{ .files = &[_][]const u8{
"cimplot.cpp", "cimplot.cpp",
"implot/implot.cpp", "implot/implot.cpp",
"implot/implot_demo.cpp", "implot/implot_demo.cpp",
"implot/implot_items.cpp", "implot/implot_items.cpp",
}, },
}); });
const depList = [_][]const u8{ const depList = [_][]const u8{
"core", "core",
"graphics", "graphics",
"platform", "platform",
"vulkan", "vulkan",
}; };
for (depList) |depName| { for (depList) |depName| {
const dep = b.dependency(depName, .{ .target = target, .optimize = optimize }); const dep = b.dependency(depName, .{ .target = target, .optimize = optimize });
const depMod = dep.module(depName); const depMod = dep.module(depName);
mod.addImport(depName, depMod); mod.addImport(depName, depMod);
} }
mod.linkLibrary(cimgui); mod.linkLibrary(cimgui);
// I could've made cimgui a seperate lib, // I could've made cimgui a seperate lib,
// I can seperate it out later if needed. // I can seperate it out later if needed.
const test_step = b.step("test", "run unit tests for ui"); const test_step = b.step("test", "run unit tests for ui");
const tests = b.addTest(.{ const tests = b.addTest(.{
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
.root_source_file = b.path("tests/tests.zig"), .root_source_file = b.path("tests/tests.zig"),
}); });
tests.root_module.addImport("vkImgui", mod); tests.root_module.addImport("vkImgui", mod);
const runArtifact = b.addRunArtifact(tests); const runArtifact = b.addRunArtifact(tests);
test_step.dependOn(&runArtifact.step); test_step.dependOn(&runArtifact.step);
b.installArtifact(tests); b.installArtifact(tests);
} }

View File

@ -1,13 +1,13 @@
.{ .{
.name = "imgui", .name = "imgui",
.version = "0.0.0", .version = "0.0.0",
.dependencies = .{ .dependencies = .{
.core = .{ .path = "../core" }, .core = .{ .path = "../core" },
.graphics = .{ .path = "../graphics" }, .graphics = .{ .path = "../graphics" },
.platform = .{ .path = "../platform" }, .platform = .{ .path = "../platform" },
.vulkan = .{ .path = "../../lib/vulkan" }, .vulkan = .{ .path = "../../lib/vulkan" },
}, },
.paths = .{ .paths = .{
"", "",
}, },
} }

Some files were not shown because too many files have changed in this diff Show More