Add shader preprocessor with #include support and refactor shaders to remove a bunch of duplicates
This commit is contained in:
parent
8e9cb3fa5b
commit
9226b61988
9
assets/shaders/camera.glsl
Normal file
9
assets/shaders/camera.glsl
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef CAMERA_GLSL
|
||||||
|
#define CAMERA_GLSL
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform Matrices {
|
||||||
|
mat4 projection;
|
||||||
|
mat4 view;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CAMERA_GLSL
|
@ -1,8 +1,4 @@
|
|||||||
// UBOs
|
#include "camera.glsl"
|
||||||
layout(std140, binding = 0) uniform Matrices {
|
|
||||||
mat4 projection;
|
|
||||||
mat4 view;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Uniforms
|
// Uniforms
|
||||||
layout(location = 1) uniform mat4 model;
|
layout(location = 1) uniform mat4 model;
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
// UBOs
|
#include "camera.glsl"
|
||||||
layout(std140, binding = 0) uniform Matrices {
|
|
||||||
mat4 projection;
|
|
||||||
mat4 view;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 2) uniform vec3 color;
|
layout(location = 2) uniform vec3 color;
|
||||||
|
|
||||||
|
14
assets/shaders/draw_cmds_data.glsl
Normal file
14
assets/shaders/draw_cmds_data.glsl
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef DRAW_CMDS_DATA_GLSL
|
||||||
|
#define DRAW_CMDS_DATA_GLSL
|
||||||
|
|
||||||
|
struct DrawCmdData {
|
||||||
|
mat4 transform;
|
||||||
|
int materialIdx;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 3) readonly buffer DrawCmdDatas {
|
||||||
|
// Access by gl_BaseInstance + gl_InstanceID
|
||||||
|
DrawCmdData draw_data[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DRAW_CMDS_DATA_GLSL
|
44
assets/shaders/material.glsl
Normal file
44
assets/shaders/material.glsl
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef MATERIAL_GLSL
|
||||||
|
#define MATERIAL_GLSL
|
||||||
|
|
||||||
|
// You have to enable GL_ARB_bindless_texture extension if you're importing this
|
||||||
|
|
||||||
|
struct Material {
|
||||||
|
vec4 albedo;
|
||||||
|
sampler2D albedo_map;
|
||||||
|
vec2 albedo_map_uv_scale;
|
||||||
|
sampler2D normal_map;
|
||||||
|
vec2 normal_map_uv_scale;
|
||||||
|
float metallic;
|
||||||
|
sampler2D metallic_map;
|
||||||
|
vec2 metallic_map_uv_scale;
|
||||||
|
float roughness;
|
||||||
|
sampler2D roughness_map;
|
||||||
|
vec2 roughness_map_uv_scale;
|
||||||
|
vec3 emission;
|
||||||
|
sampler2D emission_map;
|
||||||
|
vec2 emission_map_uv_scale;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std430, binding = 2) readonly buffer Materials {
|
||||||
|
uint materials_count;
|
||||||
|
Material materials[];
|
||||||
|
};
|
||||||
|
|
||||||
|
vec4 getAlbedo(int materialIdx) {
|
||||||
|
return textureSize(materials[materialIdx].albedo_map, 0) == ivec2(0) ? vec4(pow(materials[materialIdx].albedo.rgb, vec3(2.2)), materials[materialIdx].albedo.a) : texture(materials[materialIdx].albedo_map, VertexOut.uv * materials[materialIdx].albedo_map_uv_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getRoughness(int materialIdx) {
|
||||||
|
return max(0.01, textureSize(materials[materialIdx].roughness_map, 0) == ivec2(0) ? materials[materialIdx].roughness : texture(materials[materialIdx].roughness_map, VertexOut.uv * materials[materialIdx].roughness_map_uv_scale).g);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getMetallic(int materialIdx) {
|
||||||
|
return textureSize(materials[materialIdx].metallic_map, 0) == ivec2(0) ? materials[materialIdx].metallic : texture(materials[materialIdx].metallic_map, VertexOut.uv * materials[materialIdx].metallic_map_uv_scale).b;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getEmission(int materialIdx) {
|
||||||
|
return textureSize(materials[materialIdx].emission_map, 0) == ivec2(0) ? materials[materialIdx].emission : texture(materials[materialIdx].emission_map, VertexOut.uv * materials[materialIdx].emission_map_uv_scale).rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MATERIAL_GLSL
|
@ -1,28 +1,15 @@
|
|||||||
#extension GL_ARB_bindless_texture : enable
|
#extension GL_ARB_bindless_texture : require
|
||||||
#extension GL_KHR_shader_subgroup_ballot : enable
|
#extension GL_KHR_shader_subgroup_ballot : enable
|
||||||
#extension GL_KHR_shader_subgroup_vote : enable
|
#extension GL_KHR_shader_subgroup_vote : enable
|
||||||
|
|
||||||
|
#include "camera.glsl"
|
||||||
|
#include "draw_cmds_data.glsl"
|
||||||
|
|
||||||
// Keep in sync with cpu
|
// Keep in sync with cpu
|
||||||
#define MAX_POINT_LIGHTS 8
|
#define MAX_POINT_LIGHTS 8
|
||||||
#define PI 3.1415926535897932384626433832795
|
#define PI 3.1415926535897932384626433832795
|
||||||
#define CSM_SPLITS 4
|
#define CSM_SPLITS 4
|
||||||
|
|
||||||
struct DrawCmdData {
|
|
||||||
mat4 transform;
|
|
||||||
int materialIdx;
|
|
||||||
};
|
|
||||||
|
|
||||||
// UBOs
|
|
||||||
layout(std140, binding = 0) uniform Matrices {
|
|
||||||
mat4 projection;
|
|
||||||
mat4 view;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 3) readonly buffer DrawCmdDatas {
|
|
||||||
// Access by gl_DrawID
|
|
||||||
DrawCmdData draw_data[];
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(location = 16, bindless_sampler) uniform sampler2DArrayShadow shadow_maps;
|
layout(location = 16, bindless_sampler) uniform sampler2DArrayShadow shadow_maps;
|
||||||
layout(location = 17, bindless_sampler) uniform samplerCubeArrayShadow cube_shadow_maps;
|
layout(location = 17, bindless_sampler) uniform samplerCubeArrayShadow cube_shadow_maps;
|
||||||
layout(location = 22, bindless_sampler) uniform sampler2D brdfLut;
|
layout(location = 22, bindless_sampler) uniform sampler2D brdfLut;
|
||||||
@ -78,6 +65,8 @@ void main() {
|
|||||||
|
|
||||||
#if FRAGMENT_SHADER
|
#if FRAGMENT_SHADER
|
||||||
|
|
||||||
|
#include "material.glsl"
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
struct Light {
|
struct Light {
|
||||||
vec4 vPos;
|
vec4 vPos;
|
||||||
@ -96,34 +85,11 @@ struct Light {
|
|||||||
vec4 csm_split_points; // TODO: Maybe increase to 8, though it's probably too many
|
vec4 csm_split_points; // TODO: Maybe increase to 8, though it's probably too many
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Material {
|
|
||||||
vec4 albedo;
|
|
||||||
sampler2D albedo_map;
|
|
||||||
vec2 albedo_map_uv_scale;
|
|
||||||
sampler2D normal_map;
|
|
||||||
vec2 normal_map_uv_scale;
|
|
||||||
float metallic;
|
|
||||||
sampler2D metallic_map;
|
|
||||||
vec2 metallic_map_uv_scale;
|
|
||||||
float roughness;
|
|
||||||
sampler2D roughness_map;
|
|
||||||
vec2 roughness_map_uv_scale;
|
|
||||||
vec3 emission;
|
|
||||||
sampler2D emission_map;
|
|
||||||
vec2 emission_map_uv_scale;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
layout(std430, binding = 1) readonly buffer Lights {
|
layout(std430, binding = 1) readonly buffer Lights {
|
||||||
uint lights_count;
|
uint lights_count;
|
||||||
Light lights[];
|
Light lights[];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(std430, binding = 2) readonly buffer Materials {
|
|
||||||
uint materials_count;
|
|
||||||
Material materials[];
|
|
||||||
};
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
out vec4 FragColor;
|
||||||
|
|
||||||
int getShadowMapIndex(int lightIdx) {
|
int getShadowMapIndex(int lightIdx) {
|
||||||
@ -146,22 +112,6 @@ int getCSMSplit(int lightIdx, float depth) {
|
|||||||
return CSM_SPLITS - 1;
|
return CSM_SPLITS - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 getAlbedo(int materialIdx) {
|
|
||||||
return textureSize(materials[materialIdx].albedo_map, 0) == ivec2(0) ? vec4(pow(materials[materialIdx].albedo.rgb, vec3(2.2)), materials[materialIdx].albedo.a) : texture(materials[materialIdx].albedo_map, VertexOut.uv * materials[materialIdx].albedo_map_uv_scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
float getRoughness(int materialIdx) {
|
|
||||||
return max(0.01, textureSize(materials[materialIdx].roughness_map, 0) == ivec2(0) ? materials[materialIdx].roughness : texture(materials[materialIdx].roughness_map, VertexOut.uv * materials[materialIdx].roughness_map_uv_scale).g);
|
|
||||||
}
|
|
||||||
|
|
||||||
float getMetallic(int materialIdx) {
|
|
||||||
return textureSize(materials[materialIdx].metallic_map, 0) == ivec2(0) ? materials[materialIdx].metallic : texture(materials[materialIdx].metallic_map, VertexOut.uv * materials[materialIdx].metallic_map_uv_scale).b;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 getEmission(int materialIdx) {
|
|
||||||
return textureSize(materials[materialIdx].emission_map, 0) == ivec2(0) ? materials[materialIdx].emission : texture(materials[materialIdx].emission_map, VertexOut.uv * materials[materialIdx].emission_map_uv_scale).rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 schlickFresnel(int matIdx, float NDotV) {
|
vec3 schlickFresnel(int matIdx, float NDotV) {
|
||||||
vec3 f0 = mix(vec3(0.04), getAlbedo(matIdx).rgb, getMetallic(matIdx));
|
vec3 f0 = mix(vec3(0.04), getAlbedo(matIdx).rgb, getMetallic(matIdx));
|
||||||
|
|
||||||
@ -330,10 +280,11 @@ vec3 ibl(int matIdx, vec3 N, vec3 V) {
|
|||||||
float ambient_diff = dot(N, VertexOut.vUp) * 0.5 + 0.5;
|
float ambient_diff = dot(N, VertexOut.vUp) * 0.5 + 0.5;
|
||||||
float ambient_spec = dot(R, VertexOut.vUp) * 0.5 + 0.5;
|
float ambient_spec = dot(R, VertexOut.vUp) * 0.5 + 0.5;
|
||||||
|
|
||||||
vec3 irradiance = vec3(1.0, 0.9764705882352941, 0.9921568627450981) * 79 * ambient_diff;
|
// TODO: don't hardcode this
|
||||||
|
vec3 irradiance = vec3(1.0, 0.9764705882352941, 0.9921568627450981) * 79 * ambient_diff * 0.02;
|
||||||
vec3 diffuse = irradiance * getAlbedo(matIdx).rgb;
|
vec3 diffuse = irradiance * getAlbedo(matIdx).rgb;
|
||||||
|
|
||||||
vec3 reflectedColor = vec3(0.9, 0.9064705882352941, 0.9921568627450981) * 79 * ambient_spec;
|
vec3 reflectedColor = vec3(0.9, 0.9064705882352941, 0.9921568627450981) * 79 * ambient_spec * 0.02;
|
||||||
vec2 envBRDF = textureLod(brdfLut, vec2(NDotV, getRoughness(matIdx)), 0).rg;
|
vec2 envBRDF = textureLod(brdfLut, vec2(NDotV, getRoughness(matIdx)), 0).rg;
|
||||||
vec3 specular = reflectedColor * (F * envBRDF.x + envBRDF.y);
|
vec3 specular = reflectedColor * (F * envBRDF.x + envBRDF.y);
|
||||||
return kD * diffuse + specular;
|
return kD * diffuse + specular;
|
||||||
|
@ -69,7 +69,7 @@ vec3 linearToSRGB(vec3 color) {
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec3 hdr_color = texture(screen_sampler, VertexOut.uv).rgb;
|
vec3 hdr_color = texture(screen_sampler, VertexOut.uv).rgb;
|
||||||
hdr_color = ACESFitted(hdr_color * 0.02);
|
hdr_color = ACESFitted(hdr_color);
|
||||||
|
|
||||||
FragColor.rgb = hdr_color;
|
FragColor.rgb = hdr_color;
|
||||||
FragColor.a = 1;
|
FragColor.a = 1;
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
// UBOs
|
#include "camera.glsl"
|
||||||
layout(std140, binding = 0) uniform Matrices {
|
|
||||||
mat4 projection;
|
|
||||||
mat4 view;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 3) readonly buffer DrawCmdDatas {
|
// Shadows use a different format, so don't use draw_cmds_data.glsl
|
||||||
|
layout(std430, binding = 3) readonly buffer DrawCmdDatasShadow {
|
||||||
// Access by gl_DrawID
|
// Access by gl_DrawID
|
||||||
mat4 transforms[];
|
mat4 transforms[];
|
||||||
};
|
};
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
#extension GL_ARB_bindless_texture : enable
|
#extension GL_ARB_bindless_texture : require
|
||||||
|
|
||||||
// UBOs
|
#include "camera.glsl"
|
||||||
layout(std140, binding = 0) uniform Matrices {
|
|
||||||
mat4 projection;
|
|
||||||
mat4 view;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Uniforms
|
// Uniforms
|
||||||
layout(location = 1) uniform mat4 model;
|
layout(location = 1) uniform mat4 model;
|
||||||
|
@ -1,20 +1,8 @@
|
|||||||
#extension GL_ARB_bindless_texture : enable
|
#extension GL_ARB_bindless_texture : require
|
||||||
|
|
||||||
struct DrawCmdData {
|
#include "camera.glsl"
|
||||||
mat4 transform;
|
#include "draw_cmds_data.glsl"
|
||||||
int materialIdx;
|
|
||||||
};
|
|
||||||
|
|
||||||
// UBOs
|
|
||||||
layout(std140, binding = 0) uniform Matrices {
|
|
||||||
mat4 projection;
|
|
||||||
mat4 view;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 3) readonly buffer DrawCmdDatas {
|
|
||||||
// Access by gl_DrawID
|
|
||||||
DrawCmdData draw_data[];
|
|
||||||
};
|
|
||||||
|
|
||||||
VERTEX_EXPORT flat uint DrawID;
|
VERTEX_EXPORT flat uint DrawID;
|
||||||
|
|
||||||
@ -40,31 +28,7 @@ void main() {
|
|||||||
|
|
||||||
#if FRAGMENT_SHADER
|
#if FRAGMENT_SHADER
|
||||||
|
|
||||||
struct Material {
|
#include "material.glsl"
|
||||||
vec4 albedo;
|
|
||||||
sampler2D albedo_map;
|
|
||||||
vec2 albedo_map_uv_scale;
|
|
||||||
sampler2D normal_map;
|
|
||||||
vec2 normal_map_uv_scale;
|
|
||||||
float metallic;
|
|
||||||
sampler2D metallic_map;
|
|
||||||
vec2 metallic_map_uv_scale;
|
|
||||||
float roughness;
|
|
||||||
sampler2D roughness_map;
|
|
||||||
vec2 roughness_map_uv_scale;
|
|
||||||
vec3 emission;
|
|
||||||
sampler2D emission_map;
|
|
||||||
vec2 emission_map_uv_scale;
|
|
||||||
};
|
|
||||||
|
|
||||||
layout(std430, binding = 2) readonly buffer Materials {
|
|
||||||
uint materials_count;
|
|
||||||
Material materials[];
|
|
||||||
};
|
|
||||||
|
|
||||||
vec4 getAlbedo(int materialIdx) {
|
|
||||||
return textureSize(materials[materialIdx].albedo_map, 0) == ivec2(0) ? vec4(pow(materials[materialIdx].albedo.rgb, vec3(2.2)), materials[materialIdx].albedo.a) : texture(materials[materialIdx].albedo_map, VertexOut.uv * materials[materialIdx].albedo_map_uv_scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
out vec4 FragColor;
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
19
build.zig
19
build.zig
@ -29,8 +29,8 @@ pub fn build(b: *Build) void {
|
|||||||
});
|
});
|
||||||
const zalgebra_dep = b.dependency("zalgebra", .{});
|
const zalgebra_dep = b.dependency("zalgebra", .{});
|
||||||
|
|
||||||
const assets_mod = b.addModule("assets", .{ .root_source_file = .{ .src_path = .{ .owner = b, .sub_path = "src/assets/root.zig" } } });
|
const assets_mod = b.addModule("assets", .{ .root_source_file = b.path("src/assets/root.zig") });
|
||||||
const asset_manifest_mod = b.addModule("asset_manifest", .{ .root_source_file = .{ .src_path = .{ .owner = b, .sub_path = "src/gen/asset_manifest.zig" } } });
|
const asset_manifest_mod = b.addModule("asset_manifest", .{ .root_source_file = b.path("src/gen/asset_manifest.zig") });
|
||||||
asset_manifest_mod.addImport("assets", assets_mod);
|
asset_manifest_mod.addImport("assets", assets_mod);
|
||||||
|
|
||||||
const assets_step = b.step("assets", "Build and install assets");
|
const assets_step = b.step("assets", "Build and install assets");
|
||||||
@ -194,16 +194,19 @@ fn buildAssets(b: *std.Build, install_assetc_step: *Step, step: *Step, assetc: *
|
|||||||
if (!is_known_ext) continue;
|
if (!is_known_ext) continue;
|
||||||
|
|
||||||
const run_assetc = b.addRunArtifact(assetc);
|
const run_assetc = b.addRunArtifact(assetc);
|
||||||
|
run_assetc.rename_step_with_output_arg = false;
|
||||||
|
|
||||||
gen_asset_manifest.addAssetListFile(run_assetc.captureStdOut());
|
gen_asset_manifest.addAssetListFile(run_assetc.captureStdOut());
|
||||||
run_assetc.step.dependOn(install_assetc_step);
|
run_assetc.step.dependOn(install_assetc_step);
|
||||||
|
|
||||||
run_assetc.addPathDir(b.pathFromRoot("libs/ispc_texcomp/lib"));
|
run_assetc.addPathDir(b.pathFromRoot("libs/ispc_texcomp/lib"));
|
||||||
|
|
||||||
// Absolute input file arg, this will add it to step deps, cache and all that good stuff
|
// Absolute input file arg, this will add it to step deps, cache and all that good stuff
|
||||||
run_assetc.addFileArg(.{ .src_path = .{ .owner = b, .sub_path = b.pathJoin(&.{ path, entry.path }) } });
|
run_assetc.addFileArg(b.path(b.pathJoin(&.{ path, entry.path })));
|
||||||
|
|
||||||
// Generated output dir. Output asset(s) will be placed there at the same relative path as input
|
// Generated output dir. Output asset(s) will be placed there at the same relative path as input
|
||||||
const result_dir = run_assetc.addOutputFileArg("assets");
|
const result_dir = run_assetc.addOutputFileArg("assets");
|
||||||
|
run_assetc.setName(b.fmt("assetc ({s})", .{entry.basename}));
|
||||||
|
|
||||||
const install_assets = b.addInstallDirectory(.{
|
const install_assets = b.addInstallDirectory(.{
|
||||||
.source_dir = result_dir,
|
.source_dir = result_dir,
|
||||||
@ -230,7 +233,7 @@ fn buildAssetCompiler(b: *Build, optimize: std.builtin.OptimizeMode, assets_mod:
|
|||||||
const assetc = b.addExecutable(.{
|
const assetc = b.addExecutable(.{
|
||||||
.name = "assetc",
|
.name = "assetc",
|
||||||
.target = b.host,
|
.target = b.host,
|
||||||
.root_source_file = .{ .src_path = .{ .owner = b, .sub_path = "tools/asset_compiler.zig" } },
|
.root_source_file = b.path("tools/asset_compiler.zig"),
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
assetc.linkLibC();
|
assetc.linkLibC();
|
||||||
@ -239,12 +242,12 @@ fn buildAssetCompiler(b: *Build, optimize: std.builtin.OptimizeMode, assets_mod:
|
|||||||
b.installFile("libs/ispc_texcomp/lib/ispc_texcomp.dll", "ispc_texcomp.dll");
|
b.installFile("libs/ispc_texcomp/lib/ispc_texcomp.dll", "ispc_texcomp.dll");
|
||||||
b.installFile("libs/ispc_texcomp/lib/ispc_texcomp.pdb", "ispc_texcomp.pdb");
|
b.installFile("libs/ispc_texcomp/lib/ispc_texcomp.pdb", "ispc_texcomp.pdb");
|
||||||
}
|
}
|
||||||
assetc.addLibraryPath(.{ .src_path = .{ .owner = b, .sub_path = "libs/ispc_texcomp/lib" } });
|
assetc.addLibraryPath(b.path("libs/ispc_texcomp/lib"));
|
||||||
assetc.addIncludePath(.{ .src_path = .{ .owner = b, .sub_path = "libs/ispc_texcomp/include" } });
|
assetc.addIncludePath(b.path("libs/ispc_texcomp/include"));
|
||||||
assetc.linkSystemLibrary("ispc_texcomp");
|
assetc.linkSystemLibrary("ispc_texcomp");
|
||||||
|
|
||||||
const zalgebra_mod = zalgebra_dep.module("zalgebra");
|
const zalgebra_mod = zalgebra_dep.module("zalgebra");
|
||||||
const formats_mod = b.addModule("formats", .{ .root_source_file = .{ .src_path = .{ .owner = b, .sub_path = "src/formats.zig" } } });
|
const formats_mod = b.addModule("formats", .{ .root_source_file = b.path("src/formats.zig") });
|
||||||
formats_mod.addImport("zalgebra", zalgebra_mod);
|
formats_mod.addImport("zalgebra", zalgebra_mod);
|
||||||
formats_mod.addImport("assets", assets_mod);
|
formats_mod.addImport("assets", assets_mod);
|
||||||
assetc.root_module.addImport("formats", formats_mod);
|
assetc.root_module.addImport("formats", formats_mod);
|
||||||
@ -256,7 +259,7 @@ fn buildAssetCompiler(b: *Build, optimize: std.builtin.OptimizeMode, assets_mod:
|
|||||||
assetc.linkLibCpp();
|
assetc.linkLibCpp();
|
||||||
|
|
||||||
assetc.addCSourceFile(.{ .file = b.path("libs/stb/stb_image.c"), .flags = &.{"-std=c99"} });
|
assetc.addCSourceFile(.{ .file = b.path("libs/stb/stb_image.c"), .flags = &.{"-std=c99"} });
|
||||||
assetc.addIncludePath(.{ .src_path = .{ .owner = b, .sub_path = "libs/stb" } });
|
assetc.addIncludePath(b.path("libs/stb"));
|
||||||
|
|
||||||
return assetc;
|
return assetc;
|
||||||
}
|
}
|
||||||
|
@ -785,18 +785,621 @@ fn loadShader(self: *AssetManager, id: AssetId) LoadedShader {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ShaderTokenizer = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub const TokenType = enum {
|
||||||
|
Unknown,
|
||||||
|
|
||||||
|
OpenParen,
|
||||||
|
OpenBrace,
|
||||||
|
OpenBracket,
|
||||||
|
|
||||||
|
ClosedParen,
|
||||||
|
ClosedBrace,
|
||||||
|
ClosedBracket,
|
||||||
|
|
||||||
|
Comma,
|
||||||
|
Colon,
|
||||||
|
Semicolon,
|
||||||
|
Question,
|
||||||
|
Tilde,
|
||||||
|
|
||||||
|
Dot,
|
||||||
|
|
||||||
|
Star,
|
||||||
|
Plus,
|
||||||
|
Dash,
|
||||||
|
Slash,
|
||||||
|
Percent,
|
||||||
|
Caret,
|
||||||
|
Bar,
|
||||||
|
Ampersand,
|
||||||
|
|
||||||
|
StarEquals,
|
||||||
|
PlusEquals,
|
||||||
|
DashEquals,
|
||||||
|
SlashEquals,
|
||||||
|
PercentEquals,
|
||||||
|
CaretEquals,
|
||||||
|
BarEquals,
|
||||||
|
AmpersandEquals,
|
||||||
|
|
||||||
|
DoubleBar,
|
||||||
|
DoubleAmpersand,
|
||||||
|
|
||||||
|
Equals,
|
||||||
|
EqualsEquals,
|
||||||
|
|
||||||
|
Bang,
|
||||||
|
BangEquals,
|
||||||
|
|
||||||
|
Greater,
|
||||||
|
GreaterGreater, // >>
|
||||||
|
Less,
|
||||||
|
LessLess, // <<
|
||||||
|
|
||||||
|
GreaterEquals,
|
||||||
|
LessEquals,
|
||||||
|
|
||||||
|
String,
|
||||||
|
Directive,
|
||||||
|
|
||||||
|
Number,
|
||||||
|
Identifier,
|
||||||
|
|
||||||
|
End,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Token = struct {
|
||||||
|
type: TokenType = .Unknown,
|
||||||
|
text: []const u8 = "",
|
||||||
|
|
||||||
|
// Start and end of the token including things like quotes
|
||||||
|
start: usize = 0,
|
||||||
|
end: usize = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
at: usize = 0,
|
||||||
|
data: []const u8,
|
||||||
|
|
||||||
|
pub fn init(data: []const u8) Self {
|
||||||
|
return Self{ .data = data };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peek(self: *const Self) ?u8 {
|
||||||
|
if (self.at + 1 < self.data.len) {
|
||||||
|
return self.data[self.at + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matchDoubleSymbol(self: *Self, token: *Token, next_sym: u8, no_match: TokenType, match: TokenType) bool {
|
||||||
|
if (self.peek()) |next_char| {
|
||||||
|
if (next_char == next_sym) {
|
||||||
|
token.type = match;
|
||||||
|
token.end += 1;
|
||||||
|
token.text = self.data[token.start..token.end];
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
token.type = no_match;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
token.type = no_match;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isHex(c: u8) bool {
|
||||||
|
return switch (c) {
|
||||||
|
'0'...'9' => true,
|
||||||
|
'a'...'f', 'A'...'F' => true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matchInteger(self: *Self) ?Token {
|
||||||
|
var token = Token{ .type = .Number, .start = self.at };
|
||||||
|
var has_sign = false;
|
||||||
|
if (self.data[self.at] == '-') {
|
||||||
|
self.at += 1;
|
||||||
|
has_sign = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (self.data[self.at]) {
|
||||||
|
'0' => {
|
||||||
|
if (self.peek()) |next_sym| {
|
||||||
|
switch (next_sym) {
|
||||||
|
'x', 'X' => {
|
||||||
|
// HEX
|
||||||
|
self.at += 2;
|
||||||
|
|
||||||
|
while (isHex(self.data[self.at])) {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'0'...'9' => {
|
||||||
|
self.at += 1;
|
||||||
|
// Octal, maybe invalid (8, 9 are invalid)
|
||||||
|
while (isNum(self.data[self.at])) {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
self.at += 1;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'1'...'9' => {
|
||||||
|
while (self.at < self.data.len and isNum(self.data[self.at])) {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (self.data[self.at]) {
|
||||||
|
'u', 'U' => {
|
||||||
|
self.at += 1;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
token.end = self.at;
|
||||||
|
token.text = self.data[token.start..token.end];
|
||||||
|
|
||||||
|
const len_without_sign = if (has_sign) token.text.len - 1 else token.text.len;
|
||||||
|
if (len_without_sign == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eatDigitSequence(self: *Self) void {
|
||||||
|
while (self.at < self.data.len and isNum(self.data[self.at])) {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matchFloat(self: *Self) ?Token {
|
||||||
|
var token = Token{ .type = .Number, .start = self.at };
|
||||||
|
|
||||||
|
var has_sign = false;
|
||||||
|
switch (self.data[self.at]) {
|
||||||
|
'-', '+' => {
|
||||||
|
self.at += 1;
|
||||||
|
has_sign = true;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
self.eatDigitSequence();
|
||||||
|
if (self.data[self.at] == '.') {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
self.eatDigitSequence();
|
||||||
|
// Exponent
|
||||||
|
if (self.data[self.at] == 'e' or self.data[self.at] == 'E') {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
//Suffix
|
||||||
|
switch (self.data[self.at]) {
|
||||||
|
'f', 'F' => {
|
||||||
|
self.at += 1;
|
||||||
|
},
|
||||||
|
'l' => {
|
||||||
|
if (self.peek() == 'f') {
|
||||||
|
self.at += 2;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'L' => {
|
||||||
|
if (self.peek() == 'F') {
|
||||||
|
self.at += 2;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
token.end = self.at;
|
||||||
|
token.text = self.data[token.start..token.end];
|
||||||
|
|
||||||
|
const len_without_sign = if (has_sign) token.text.len - 1 else token.text.len;
|
||||||
|
if (len_without_sign == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matchNumber(self: *Self, token: *Token) bool {
|
||||||
|
const start = self.at;
|
||||||
|
const maybe_int_token = self.matchInteger();
|
||||||
|
self.at = start;
|
||||||
|
const maybe_float_token = self.matchFloat();
|
||||||
|
|
||||||
|
if (maybe_int_token != null and maybe_float_token != null) {
|
||||||
|
const int_token = maybe_int_token.?;
|
||||||
|
const float_token = maybe_float_token.?;
|
||||||
|
if (int_token.end > float_token.end) {
|
||||||
|
self.at = int_token.end;
|
||||||
|
token.* = int_token;
|
||||||
|
} else {
|
||||||
|
self.at = float_token.end;
|
||||||
|
token.* = float_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maybe_float_token) |result| {
|
||||||
|
self.at = result.end;
|
||||||
|
token.* = result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maybe_int_token) |result| {
|
||||||
|
self.at = result.end;
|
||||||
|
token.* = result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(self: *Self) Token {
|
||||||
|
self.eatWhitespace();
|
||||||
|
|
||||||
|
if (self.at == self.data.len) {
|
||||||
|
return Token{ .type = .End };
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = Token{ .type = .Unknown, .start = self.at, .end = self.at + 1, .text = self.data[self.at .. self.at + 1] };
|
||||||
|
|
||||||
|
if (self.at < self.data.len) {
|
||||||
|
switch (self.data[self.at]) {
|
||||||
|
'(' => {
|
||||||
|
result.type = .OpenParen;
|
||||||
|
},
|
||||||
|
'{' => {
|
||||||
|
result.type = .OpenBrace;
|
||||||
|
},
|
||||||
|
'[' => {
|
||||||
|
result.type = .OpenBracket;
|
||||||
|
},
|
||||||
|
')' => {
|
||||||
|
result.type = .ClosedParen;
|
||||||
|
},
|
||||||
|
'}' => {
|
||||||
|
result.type = .ClosedBrace;
|
||||||
|
},
|
||||||
|
']' => {
|
||||||
|
result.type = .ClosedBracket;
|
||||||
|
},
|
||||||
|
',' => {
|
||||||
|
result.type = .Comma;
|
||||||
|
},
|
||||||
|
':' => {
|
||||||
|
result.type = .Colon;
|
||||||
|
},
|
||||||
|
';' => {
|
||||||
|
result.type = .Semicolon;
|
||||||
|
},
|
||||||
|
'?' => {
|
||||||
|
result.type = .Question;
|
||||||
|
},
|
||||||
|
'~' => {
|
||||||
|
result.type = .Tilde;
|
||||||
|
},
|
||||||
|
'.' => {
|
||||||
|
if (!self.matchNumber(&result)) {
|
||||||
|
result.type = .Dot;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'*' => {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '=', .Star, .StarEquals);
|
||||||
|
},
|
||||||
|
'+' => {
|
||||||
|
if (!self.matchNumber(&result)) {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '=', .Plus, .PlusEquals);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'-' => {
|
||||||
|
if (!self.matchNumber(&result)) {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '=', .Dash, .DashEquals);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'/' => {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '=', .Slash, .SlashEquals);
|
||||||
|
},
|
||||||
|
'%' => {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '=', .Percent, .PercentEquals);
|
||||||
|
},
|
||||||
|
'^' => {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '=', .Caret, .StarEquals);
|
||||||
|
},
|
||||||
|
'|' => {
|
||||||
|
if (!self.matchDoubleSymbol(&result, '=', .Bar, .BarEquals)) {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '|', .Bar, .DoubleBar);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'&' => {
|
||||||
|
if (!self.matchDoubleSymbol(&result, '=', .Ampersand, .AmpersandEquals)) {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '&', .Ampersand, .DoubleAmpersand);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'=' => {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '=', .Equals, .EqualsEquals);
|
||||||
|
},
|
||||||
|
'!' => {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '=', .Bang, .BangEquals);
|
||||||
|
},
|
||||||
|
'<' => {
|
||||||
|
if (!self.matchDoubleSymbol(&result, '=', .Less, .LessEquals)) {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '<', .Less, .LessLess);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'>' => {
|
||||||
|
if (!self.matchDoubleSymbol(&result, '=', .Greater, .GreaterEquals)) {
|
||||||
|
_ = self.matchDoubleSymbol(&result, '>', .Greater, .GreaterGreater);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'"' => {
|
||||||
|
const start = self.at;
|
||||||
|
self.at += 1;
|
||||||
|
|
||||||
|
const text_start = self.at;
|
||||||
|
|
||||||
|
while (self.at < self.data.len and self.data[self.at] != '"') {
|
||||||
|
if (self.data[self.at] == '\\') {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
const text_end = self.at;
|
||||||
|
|
||||||
|
if (self.data[self.at] == '"') {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
const end = self.at;
|
||||||
|
|
||||||
|
result.type = .String;
|
||||||
|
result.start = start;
|
||||||
|
result.text = self.data[text_start..text_end];
|
||||||
|
result.start = start;
|
||||||
|
result.end = end;
|
||||||
|
},
|
||||||
|
'#' => {
|
||||||
|
const start = self.at;
|
||||||
|
|
||||||
|
self.at += 1;
|
||||||
|
const text_start = self.at;
|
||||||
|
|
||||||
|
while (isAlphaNum(self.data[self.at])) {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const end = self.at;
|
||||||
|
|
||||||
|
result.type = .Directive;
|
||||||
|
result.text = self.data[text_start..end];
|
||||||
|
result.start = start;
|
||||||
|
result.end = end;
|
||||||
|
},
|
||||||
|
'a'...'z', 'A'...'Z', '_' => {
|
||||||
|
const start = self.at;
|
||||||
|
|
||||||
|
while (self.at < self.data.len and (isAlphaNum(self.data[self.at]))) {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const end = self.at;
|
||||||
|
|
||||||
|
result.type = .Identifier;
|
||||||
|
result.text = self.data[start..end];
|
||||||
|
result.start = start;
|
||||||
|
result.end = end;
|
||||||
|
},
|
||||||
|
'0'...'9' => {
|
||||||
|
const matched = self.matchNumber(&result);
|
||||||
|
std.debug.assert(matched);
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.type = .End;
|
||||||
|
}
|
||||||
|
self.at = result.end;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isWhitespace(c: u8) bool {
|
||||||
|
return c == ' ' or c == '\t' or c == '\n' or c == '\r';
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isAlpha(c: u8) bool {
|
||||||
|
return (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z');
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isNum(c: u8) bool {
|
||||||
|
return (c >= '0' and c <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isAlphaNum(c: u8) bool {
|
||||||
|
return isAlpha(c) or isNum(c) or c == '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eatWhitespace(self: *Self) void {
|
||||||
|
var consuming = true;
|
||||||
|
while (consuming) {
|
||||||
|
if (self.at >= self.data.len) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWhitespace(self.data[self.at])) {
|
||||||
|
self.at += 1;
|
||||||
|
} else if (self.data[self.at] == '/' and self.peek() == '/') {
|
||||||
|
self.at += 2;
|
||||||
|
while (self.at < self.data.len and self.data[self.at] != '\n') {
|
||||||
|
if (self.data[self.at] == '\\' and self.peek() == '\n') {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
} else if (self.data[self.at] == '/' and self.peek() == '*') {
|
||||||
|
self.at += 2;
|
||||||
|
|
||||||
|
while (self.at < self.data.len and self.at < self.data.len and !(self.data[self.at] == '*' and self.peek() == '/')) {
|
||||||
|
self.at += 1;
|
||||||
|
}
|
||||||
|
if (self.at < self.data.len and self.data[self.at] == '*' and self.peek() == '/') {
|
||||||
|
self.at += 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
consuming = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "ShaderTokenizer" {
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var tokenizer = ShaderTokenizer.init(
|
||||||
|
\\// UBOs asdkfljlka ajksfk\
|
||||||
|
\\
|
||||||
|
\\#include "../my_file\".glsl"
|
||||||
|
\\
|
||||||
|
\\layout(std140, binding = 0) uniform Matrices {
|
||||||
|
\\ mat4 projection;
|
||||||
|
\\ mat4 view;
|
||||||
|
\\};
|
||||||
|
\\
|
||||||
|
\\layout(location = 2) uniform vec3 color;
|
||||||
|
\\
|
||||||
|
\\// Input, output blocks
|
||||||
|
\\
|
||||||
|
\\#if VERTEX_SHADER
|
||||||
|
\\
|
||||||
|
\\layout(location = 0) in vec3 aPos;
|
||||||
|
\\
|
||||||
|
\\void main() {
|
||||||
|
\\ gl_Position = projection * view * vec4(aPos.xyz, 1.0);
|
||||||
|
\\}
|
||||||
|
\\#endif // VERTEX_SHADER
|
||||||
|
\\
|
||||||
|
\\#if FRAGMENT_SHADER
|
||||||
|
\\
|
||||||
|
\\out vec4 FragColor;
|
||||||
|
\\
|
||||||
|
\\void main() {
|
||||||
|
\\ FragColor += vec4(vec3(1.0), 1.0f);
|
||||||
|
\\ bool logic = (true && false || _asdfjkh) | (1u << -123U);
|
||||||
|
\\ 0xAf123FF
|
||||||
|
\\ -0x123
|
||||||
|
\\ -09872
|
||||||
|
\\ .1
|
||||||
|
\\ .12f
|
||||||
|
\\ 0.2LF
|
||||||
|
\\ +0
|
||||||
|
\\ -0f
|
||||||
|
\\}
|
||||||
|
\\
|
||||||
|
\\
|
||||||
|
\\#endif // FRAGMNET_SHADER
|
||||||
|
);
|
||||||
|
|
||||||
|
var token = tokenizer.next();
|
||||||
|
while (token.type != .End) : (token = tokenizer.next()) {
|
||||||
|
try std.io.getStdErr().writer().print("{} \"{s}\"\n", .{ token.type, token.text });
|
||||||
|
try testing.expect(token.type != .Unknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn loadShaderErr(self: *AssetManager, id: AssetId) !LoadedShader {
|
fn loadShaderErr(self: *AssetManager, id: AssetId) !LoadedShader {
|
||||||
const path = asset_manifest.getPath(id);
|
const path = asset_manifest.getPath(id);
|
||||||
|
const dir = std.fs.path.dirname(path) orelse @panic("No dir");
|
||||||
|
|
||||||
const data = try self.loadFile(self.allocator, path, SHADER_MAX_BYTES);
|
const data = try self.loadFile(self.frame_arena, path, SHADER_MAX_BYTES);
|
||||||
|
|
||||||
const loaded_shader = LoadedShader{ .source = data.bytes };
|
var included_asset_ids = std.ArrayList(AssetId).init(self.frame_arena);
|
||||||
|
var preprocessed_segments = std.SegmentedList([]const u8, 64){};
|
||||||
|
var final_len: usize = 0;
|
||||||
|
|
||||||
|
// Preprocess
|
||||||
|
{
|
||||||
|
var tokenizer = ShaderTokenizer.init(data.bytes);
|
||||||
|
|
||||||
|
var last_offset: usize = 0;
|
||||||
|
|
||||||
|
var token = tokenizer.next();
|
||||||
|
while (token.type != .End) : (token = tokenizer.next()) {
|
||||||
|
switch (token.type) {
|
||||||
|
.Directive => {
|
||||||
|
if (std.mem.eql(u8, token.text, "include")) {
|
||||||
|
|
||||||
|
// Append section of text up to this directive
|
||||||
|
try preprocessed_segments.append(self.frame_arena, data.bytes[last_offset..token.start]);
|
||||||
|
final_len += token.start - last_offset;
|
||||||
|
|
||||||
|
const include_path = tokenizer.next();
|
||||||
|
// Next section will start after this directive, this allows replacing #include with its content
|
||||||
|
last_offset = include_path.end;
|
||||||
|
|
||||||
|
if (include_path.type != .String) {
|
||||||
|
return error.InvalidInclude;
|
||||||
|
}
|
||||||
|
|
||||||
|
const included_file_path = try std.fs.path.resolve(self.frame_arena, &.{ dir, include_path.text });
|
||||||
|
|
||||||
|
const included_asset_id = assets.AssetPath.fromString(included_file_path).hash();
|
||||||
|
if (included_asset_id != 0) {
|
||||||
|
try included_asset_ids.append(included_asset_id);
|
||||||
|
const included_shader = try self.loadShaderErr(included_asset_id);
|
||||||
|
try preprocessed_segments.append(self.frame_arena, included_shader.source);
|
||||||
|
final_len += included_shader.source.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const remaining = data.bytes.len - last_offset;
|
||||||
|
if (remaining > 0) {
|
||||||
|
try preprocessed_segments.append(self.frame_arena, data.bytes[last_offset..data.bytes.len]);
|
||||||
|
final_len += remaining;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result_source = try self.allocator.alloc(u8, final_len);
|
||||||
|
|
||||||
|
// Join source sections
|
||||||
|
{
|
||||||
|
var cursor: usize = 0;
|
||||||
|
var iter = preprocessed_segments.constIterator(0);
|
||||||
|
|
||||||
|
while (iter.next()) |slice| {
|
||||||
|
@memcpy(result_source[cursor .. cursor + slice.len], slice.*);
|
||||||
|
cursor += slice.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loaded_shader = LoadedShader{ .source = result_source };
|
||||||
{
|
{
|
||||||
self.rw_lock.lock();
|
self.rw_lock.lock();
|
||||||
defer self.rw_lock.unlock();
|
defer self.rw_lock.unlock();
|
||||||
|
|
||||||
try self.loaded_assets.put(self.allocator, id, .{ .shader = loaded_shader });
|
try self.loaded_assets.put(self.allocator, id, .{ .shader = loaded_shader });
|
||||||
try self.modified_times.put(self.allocator, id, data.modified);
|
try self.modified_times.put(self.allocator, id, data.modified);
|
||||||
|
|
||||||
|
try self.addDependencies(id, included_asset_ids.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
return loaded_shader;
|
return loaded_shader;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
pub const AssetId = u64;
|
pub const AssetId = u64;
|
||||||
|
|
||||||
pub const Handle = struct {
|
pub const Handle = struct {
|
||||||
@ -8,3 +10,149 @@ pub const Handle = struct {
|
|||||||
pub const Texture = extern struct { id: AssetId = 0 };
|
pub const Texture = extern struct { id: AssetId = 0 };
|
||||||
pub const Material = extern struct { id: AssetId = 0 };
|
pub const Material = extern struct { id: AssetId = 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const AssetType = enum {
|
||||||
|
Scene,
|
||||||
|
Mesh,
|
||||||
|
Shader,
|
||||||
|
ShaderProgram,
|
||||||
|
Texture,
|
||||||
|
Material,
|
||||||
|
|
||||||
|
pub fn pluralName(self: AssetType) []const u8 {
|
||||||
|
return switch (self) {
|
||||||
|
.Scene => "Scenes",
|
||||||
|
.Mesh => "Meshes",
|
||||||
|
.Shader => "Shaders",
|
||||||
|
.ShaderProgram => "ShaderPrograms",
|
||||||
|
.Texture => "Textures",
|
||||||
|
.Material => "Materials",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ext(self: AssetType) []const u8 {
|
||||||
|
return switch (self) {
|
||||||
|
.Scene => "scn",
|
||||||
|
.Mesh => "mesh",
|
||||||
|
.Shader => "glsl",
|
||||||
|
.ShaderProgram => "prog",
|
||||||
|
.Texture => "tex",
|
||||||
|
.Material => "mat",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const AssetPath = union(enum) {
|
||||||
|
invalid: void, // translates to handle with id: 0
|
||||||
|
simple: []const u8,
|
||||||
|
nested: struct {
|
||||||
|
path: []const u8,
|
||||||
|
sub_path: []const u8,
|
||||||
|
},
|
||||||
|
|
||||||
|
pub fn hash(self: AssetPath) u64 {
|
||||||
|
switch (self) {
|
||||||
|
.invalid => return 0,
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
var hasher = std.hash.Wyhash.init(0);
|
||||||
|
std.hash.autoHashStrat(&hasher, self.getPath(), .Deep);
|
||||||
|
std.hash.autoHashStrat(&hasher, self.getSubPath(), .Deep);
|
||||||
|
return hasher.final();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subPath(self: AssetPath, sub_path: []const u8) AssetPath {
|
||||||
|
return switch (self) {
|
||||||
|
.invalid => self,
|
||||||
|
.simple => |path| AssetPath{ .nested = .{ .path = path, .sub_path = sub_path } },
|
||||||
|
.nested => |nested| AssetPath{ .nested = .{ .path = nested.path, .sub_path = sub_path } },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getPath(self: AssetPath) []const u8 {
|
||||||
|
return switch (self) {
|
||||||
|
.invalid => "",
|
||||||
|
.simple => |path| path,
|
||||||
|
.nested => |nested| nested.path,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getSubPath(self: AssetPath) ?[]const u8 {
|
||||||
|
return switch (self) {
|
||||||
|
.invalid => null,
|
||||||
|
.nested => |nested| nested.sub_path,
|
||||||
|
else => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn strLen(self: AssetPath) usize {
|
||||||
|
return switch (self) {
|
||||||
|
.invalid => 0,
|
||||||
|
.simple => |path| path.len,
|
||||||
|
.nested => |nested| return nested.path.len + nested.sub_path.len + 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn writeString(self: AssetPath, writer: anytype) !void {
|
||||||
|
switch (self) {
|
||||||
|
.invalid => {},
|
||||||
|
.simple => |path| {
|
||||||
|
try writer.writeAll(path);
|
||||||
|
},
|
||||||
|
.nested => |nested| {
|
||||||
|
try writer.writeAll(nested.path);
|
||||||
|
try writer.writeByte('#');
|
||||||
|
try writer.writeAll(nested.sub_path);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toString(self: AssetPath, out_buf: []u8) ![]u8 {
|
||||||
|
return self.toStringSep(out_buf, '#');
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toStringSep(self: AssetPath, out_buf: []u8, sep: u8) ![]u8 {
|
||||||
|
if (out_buf.len < self.strLen()) {
|
||||||
|
return error.BufferTooSmall;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (self) {
|
||||||
|
.invalid => {
|
||||||
|
return out_buf[0..0];
|
||||||
|
},
|
||||||
|
.simple => |path| {
|
||||||
|
@memcpy(out_buf[0..path.len], path);
|
||||||
|
return out_buf[0..path.len];
|
||||||
|
},
|
||||||
|
.nested => |nested| {
|
||||||
|
@memcpy(out_buf[0..nested.path.len], nested.path);
|
||||||
|
out_buf[nested.path.len] = sep;
|
||||||
|
@memcpy(out_buf[nested.path.len + 1 .. nested.path.len + 1 + nested.sub_path.len], nested.sub_path);
|
||||||
|
|
||||||
|
return out_buf[0..self.strLen()];
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toStringAlloc(self: AssetPath, allocator: std.mem.Allocator) ![]u8 {
|
||||||
|
const buf = try allocator.alloc(u8, self.strLen());
|
||||||
|
errdefer allocator.free(buf);
|
||||||
|
return try self.toString(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fromString(str: []const u8) AssetPath {
|
||||||
|
if (str.len == 0) {
|
||||||
|
return .invalid;
|
||||||
|
}
|
||||||
|
if (std.mem.indexOf(u8, str, "#")) |sep_idx| {
|
||||||
|
return .{
|
||||||
|
.nested = .{
|
||||||
|
.path = str[0..sep_idx],
|
||||||
|
.sub_path = str[sep_idx + 1 ..],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .simple = str };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -192,7 +192,7 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
|||||||
_ = globals.g_mem.world.addEntity(.{
|
_ = globals.g_mem.world.addEntity(.{
|
||||||
.flags = .{ .dir_light = true, .rotate = true },
|
.flags = .{ .dir_light = true, .rotate = true },
|
||||||
.transform = .{ .rot = Quat.fromEulerAngles(Vec3.new(70, 0, 0)) },
|
.transform = .{ .rot = Quat.fromEulerAngles(Vec3.new(70, 0, 0)) },
|
||||||
.light = .{ .color_intensity = Vec4.new(1.00, 0.805, 0.570, 790) },
|
.light = .{ .color_intensity = Vec4.new(1.00, 0.805, 0.8, 790 * 0.02) },
|
||||||
.rotate = .{ .axis = Vec3.up(), .rate = -10 },
|
.rotate = .{ .axis = Vec3.up(), .rate = -10 },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user