First scene loaded, discovered an issue with ubo's, weird stuff in fullscreen
This commit is contained in:
parent
96449b65d7
commit
5f426c61de
2
assets/test_scene.mtl
Normal file
2
assets/test_scene.mtl
Normal file
@ -0,0 +1,2 @@
|
||||
# Blender 4.0.2 MTL File: 'None'
|
||||
# www.blender.org
|
303
assets/test_scene.obj
Normal file
303
assets/test_scene.obj
Normal file
@ -0,0 +1,303 @@
|
||||
# Blender 4.0.2
|
||||
# www.blender.org
|
||||
mtllib test_scene.mtl
|
||||
o Cube
|
||||
v -1.000000 -1.000000 1.000000
|
||||
v -1.000000 1.000000 1.000000
|
||||
v -1.000000 -1.000000 -1.000000
|
||||
v -1.000000 1.000000 -1.000000
|
||||
v 1.000000 -1.000000 1.000000
|
||||
v 1.000000 1.000000 1.000000
|
||||
v 1.000000 -1.000000 -1.000000
|
||||
v 1.000000 1.000000 -1.000000
|
||||
vn -1.0000 -0.0000 -0.0000
|
||||
vn -0.0000 -0.0000 -1.0000
|
||||
vn 1.0000 -0.0000 -0.0000
|
||||
vn -0.0000 -0.0000 1.0000
|
||||
vn -0.0000 -1.0000 -0.0000
|
||||
vn -0.0000 1.0000 -0.0000
|
||||
vt 0.375000 0.000000
|
||||
vt 0.625000 0.000000
|
||||
vt 0.625000 0.250000
|
||||
vt 0.375000 0.250000
|
||||
vt 0.625000 0.500000
|
||||
vt 0.375000 0.500000
|
||||
vt 0.625000 0.750000
|
||||
vt 0.375000 0.750000
|
||||
vt 0.625000 1.000000
|
||||
vt 0.375000 1.000000
|
||||
vt 0.125000 0.500000
|
||||
vt 0.125000 0.750000
|
||||
vt 0.875000 0.500000
|
||||
vt 0.875000 0.750000
|
||||
s 0
|
||||
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||
f 3/4/2 4/3/2 8/5/2 7/6/2
|
||||
f 7/6/3 8/5/3 6/7/3 5/8/3
|
||||
f 5/8/4 6/7/4 2/9/4 1/10/4
|
||||
f 3/11/5 7/6/5 5/8/5 1/12/5
|
||||
f 8/5/6 4/13/6 2/14/6 6/7/6
|
||||
o Cylinder
|
||||
v -4.365820 -1.000000 -1.000000
|
||||
v -4.365820 1.000000 -1.000000
|
||||
v -4.170730 -1.000000 -0.980785
|
||||
v -4.170730 1.000000 -0.980785
|
||||
v -3.983137 -1.000000 -0.923880
|
||||
v -3.983137 1.000000 -0.923880
|
||||
v -3.810250 -1.000000 -0.831470
|
||||
v -3.810250 1.000000 -0.831470
|
||||
v -3.658714 -1.000000 -0.707107
|
||||
v -3.658714 1.000000 -0.707107
|
||||
v -3.534351 -1.000000 -0.555570
|
||||
v -3.534351 1.000000 -0.555570
|
||||
v -3.441941 -1.000000 -0.382683
|
||||
v -3.441941 1.000000 -0.382683
|
||||
v -3.385035 -1.000000 -0.195090
|
||||
v -3.385035 1.000000 -0.195090
|
||||
v -3.365820 -1.000000 0.000000
|
||||
v -3.365820 1.000000 0.000000
|
||||
v -3.385035 -1.000000 0.195090
|
||||
v -3.385035 1.000000 0.195090
|
||||
v -3.441941 -1.000000 0.382683
|
||||
v -3.441941 1.000000 0.382683
|
||||
v -3.534351 -1.000000 0.555570
|
||||
v -3.534351 1.000000 0.555570
|
||||
v -3.658714 -1.000000 0.707107
|
||||
v -3.658714 1.000000 0.707107
|
||||
v -3.810250 -1.000000 0.831470
|
||||
v -3.810250 1.000000 0.831470
|
||||
v -3.983137 -1.000000 0.923880
|
||||
v -3.983137 1.000000 0.923880
|
||||
v -4.170730 -1.000000 0.980785
|
||||
v -4.170730 1.000000 0.980785
|
||||
v -4.365820 -1.000000 1.000000
|
||||
v -4.365820 1.000000 1.000000
|
||||
v -4.560911 -1.000000 0.980785
|
||||
v -4.560911 1.000000 0.980785
|
||||
v -4.748504 -1.000000 0.923880
|
||||
v -4.748504 1.000000 0.923880
|
||||
v -4.921391 -1.000000 0.831470
|
||||
v -4.921391 1.000000 0.831470
|
||||
v -5.072927 -1.000000 0.707107
|
||||
v -5.072927 1.000000 0.707107
|
||||
v -5.197290 -1.000000 0.555570
|
||||
v -5.197290 1.000000 0.555570
|
||||
v -5.289700 -1.000000 0.382683
|
||||
v -5.289700 1.000000 0.382683
|
||||
v -5.346606 -1.000000 0.195090
|
||||
v -5.346606 1.000000 0.195090
|
||||
v -5.365820 -1.000000 0.000000
|
||||
v -5.365820 1.000000 0.000000
|
||||
v -5.346606 -1.000000 -0.195090
|
||||
v -5.346606 1.000000 -0.195090
|
||||
v -5.289700 -1.000000 -0.382683
|
||||
v -5.289700 1.000000 -0.382683
|
||||
v -5.197290 -1.000000 -0.555570
|
||||
v -5.197290 1.000000 -0.555570
|
||||
v -5.072927 -1.000000 -0.707107
|
||||
v -5.072927 1.000000 -0.707107
|
||||
v -4.921391 -1.000000 -0.831470
|
||||
v -4.921391 1.000000 -0.831470
|
||||
v -4.748504 -1.000000 -0.923880
|
||||
v -4.748504 1.000000 -0.923880
|
||||
v -4.560911 -1.000000 -0.980785
|
||||
v -4.560911 1.000000 -0.980785
|
||||
vn 0.0980 -0.0000 -0.9952
|
||||
vn 0.2903 -0.0000 -0.9569
|
||||
vn 0.4714 -0.0000 -0.8819
|
||||
vn 0.6344 -0.0000 -0.7730
|
||||
vn 0.7730 -0.0000 -0.6344
|
||||
vn 0.8819 -0.0000 -0.4714
|
||||
vn 0.9569 -0.0000 -0.2903
|
||||
vn 0.9952 -0.0000 -0.0980
|
||||
vn 0.9952 -0.0000 0.0980
|
||||
vn 0.9569 -0.0000 0.2903
|
||||
vn 0.8819 -0.0000 0.4714
|
||||
vn 0.7730 -0.0000 0.6344
|
||||
vn 0.6344 -0.0000 0.7730
|
||||
vn 0.4714 -0.0000 0.8819
|
||||
vn 0.2903 -0.0000 0.9569
|
||||
vn 0.0980 -0.0000 0.9952
|
||||
vn -0.0980 -0.0000 0.9952
|
||||
vn -0.2903 -0.0000 0.9569
|
||||
vn -0.4714 -0.0000 0.8819
|
||||
vn -0.6344 -0.0000 0.7730
|
||||
vn -0.7730 -0.0000 0.6344
|
||||
vn -0.8819 -0.0000 0.4714
|
||||
vn -0.9569 -0.0000 0.2903
|
||||
vn -0.9952 -0.0000 0.0980
|
||||
vn -0.9952 -0.0000 -0.0980
|
||||
vn -0.9569 -0.0000 -0.2903
|
||||
vn -0.8819 -0.0000 -0.4714
|
||||
vn -0.7730 -0.0000 -0.6344
|
||||
vn -0.6344 -0.0000 -0.7730
|
||||
vn -0.4714 -0.0000 -0.8819
|
||||
vn -0.0000 1.0000 -0.0000
|
||||
vn -0.2903 -0.0000 -0.9569
|
||||
vn -0.0980 -0.0000 -0.9952
|
||||
vn -0.0000 -1.0000 -0.0000
|
||||
vt 1.000000 0.500000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.968750 1.000000
|
||||
vt 0.968750 0.500000
|
||||
vt 0.937500 1.000000
|
||||
vt 0.937500 0.500000
|
||||
vt 0.906250 1.000000
|
||||
vt 0.906250 0.500000
|
||||
vt 0.875000 1.000000
|
||||
vt 0.875000 0.500000
|
||||
vt 0.843750 1.000000
|
||||
vt 0.843750 0.500000
|
||||
vt 0.812500 1.000000
|
||||
vt 0.812500 0.500000
|
||||
vt 0.781250 1.000000
|
||||
vt 0.781250 0.500000
|
||||
vt 0.750000 1.000000
|
||||
vt 0.750000 0.500000
|
||||
vt 0.718750 1.000000
|
||||
vt 0.718750 0.500000
|
||||
vt 0.687500 1.000000
|
||||
vt 0.687500 0.500000
|
||||
vt 0.656250 1.000000
|
||||
vt 0.656250 0.500000
|
||||
vt 0.625000 1.000000
|
||||
vt 0.625000 0.500000
|
||||
vt 0.593750 1.000000
|
||||
vt 0.593750 0.500000
|
||||
vt 0.562500 1.000000
|
||||
vt 0.562500 0.500000
|
||||
vt 0.531250 1.000000
|
||||
vt 0.531250 0.500000
|
||||
vt 0.500000 1.000000
|
||||
vt 0.500000 0.500000
|
||||
vt 0.468750 1.000000
|
||||
vt 0.468750 0.500000
|
||||
vt 0.437500 1.000000
|
||||
vt 0.437500 0.500000
|
||||
vt 0.406250 1.000000
|
||||
vt 0.406250 0.500000
|
||||
vt 0.375000 1.000000
|
||||
vt 0.375000 0.500000
|
||||
vt 0.343750 1.000000
|
||||
vt 0.343750 0.500000
|
||||
vt 0.312500 1.000000
|
||||
vt 0.312500 0.500000
|
||||
vt 0.281250 1.000000
|
||||
vt 0.281250 0.500000
|
||||
vt 0.250000 1.000000
|
||||
vt 0.250000 0.500000
|
||||
vt 0.218750 1.000000
|
||||
vt 0.218750 0.500000
|
||||
vt 0.187500 1.000000
|
||||
vt 0.187500 0.500000
|
||||
vt 0.156250 1.000000
|
||||
vt 0.156250 0.500000
|
||||
vt 0.125000 1.000000
|
||||
vt 0.125000 0.500000
|
||||
vt 0.093750 1.000000
|
||||
vt 0.093750 0.500000
|
||||
vt 0.062500 1.000000
|
||||
vt 0.062500 0.500000
|
||||
vt 0.296822 0.485388
|
||||
vt 0.250000 0.490000
|
||||
vt 0.203178 0.485388
|
||||
vt 0.158156 0.471731
|
||||
vt 0.116663 0.449553
|
||||
vt 0.080294 0.419706
|
||||
vt 0.050447 0.383337
|
||||
vt 0.028269 0.341844
|
||||
vt 0.014612 0.296822
|
||||
vt 0.010000 0.250000
|
||||
vt 0.014612 0.203178
|
||||
vt 0.028269 0.158156
|
||||
vt 0.050447 0.116663
|
||||
vt 0.080294 0.080294
|
||||
vt 0.116663 0.050447
|
||||
vt 0.158156 0.028269
|
||||
vt 0.203178 0.014612
|
||||
vt 0.250000 0.010000
|
||||
vt 0.296822 0.014612
|
||||
vt 0.341844 0.028269
|
||||
vt 0.383337 0.050447
|
||||
vt 0.419706 0.080294
|
||||
vt 0.449553 0.116663
|
||||
vt 0.471731 0.158156
|
||||
vt 0.485388 0.203178
|
||||
vt 0.490000 0.250000
|
||||
vt 0.485388 0.296822
|
||||
vt 0.471731 0.341844
|
||||
vt 0.449553 0.383337
|
||||
vt 0.419706 0.419706
|
||||
vt 0.383337 0.449553
|
||||
vt 0.341844 0.471731
|
||||
vt 0.031250 1.000000
|
||||
vt 0.031250 0.500000
|
||||
vt 0.000000 1.000000
|
||||
vt 0.000000 0.500000
|
||||
vt 0.750000 0.490000
|
||||
vt 0.796822 0.485388
|
||||
vt 0.841844 0.471731
|
||||
vt 0.883337 0.449553
|
||||
vt 0.919706 0.419706
|
||||
vt 0.949553 0.383337
|
||||
vt 0.971731 0.341844
|
||||
vt 0.985388 0.296822
|
||||
vt 0.990000 0.250000
|
||||
vt 0.985388 0.203178
|
||||
vt 0.971731 0.158156
|
||||
vt 0.949553 0.116663
|
||||
vt 0.919706 0.080294
|
||||
vt 0.883337 0.050447
|
||||
vt 0.841844 0.028269
|
||||
vt 0.796822 0.014612
|
||||
vt 0.750000 0.010000
|
||||
vt 0.703178 0.014612
|
||||
vt 0.658156 0.028269
|
||||
vt 0.616663 0.050447
|
||||
vt 0.580294 0.080294
|
||||
vt 0.550447 0.116663
|
||||
vt 0.528269 0.158156
|
||||
vt 0.514612 0.203178
|
||||
vt 0.510000 0.250000
|
||||
vt 0.514612 0.296822
|
||||
vt 0.528269 0.341844
|
||||
vt 0.550447 0.383337
|
||||
vt 0.580294 0.419706
|
||||
vt 0.616663 0.449553
|
||||
vt 0.658156 0.471731
|
||||
vt 0.703178 0.485388
|
||||
s 0
|
||||
f 9/15/7 10/16/7 12/17/7 11/18/7
|
||||
f 11/18/8 12/17/8 14/19/8 13/20/8
|
||||
f 13/20/9 14/19/9 16/21/9 15/22/9
|
||||
f 15/22/10 16/21/10 18/23/10 17/24/10
|
||||
f 17/24/11 18/23/11 20/25/11 19/26/11
|
||||
f 19/26/12 20/25/12 22/27/12 21/28/12
|
||||
f 21/28/13 22/27/13 24/29/13 23/30/13
|
||||
f 23/30/14 24/29/14 26/31/14 25/32/14
|
||||
f 25/32/15 26/31/15 28/33/15 27/34/15
|
||||
f 27/34/16 28/33/16 30/35/16 29/36/16
|
||||
f 29/36/17 30/35/17 32/37/17 31/38/17
|
||||
f 31/38/18 32/37/18 34/39/18 33/40/18
|
||||
f 33/40/19 34/39/19 36/41/19 35/42/19
|
||||
f 35/42/20 36/41/20 38/43/20 37/44/20
|
||||
f 37/44/21 38/43/21 40/45/21 39/46/21
|
||||
f 39/46/22 40/45/22 42/47/22 41/48/22
|
||||
f 41/48/23 42/47/23 44/49/23 43/50/23
|
||||
f 43/50/24 44/49/24 46/51/24 45/52/24
|
||||
f 45/52/25 46/51/25 48/53/25 47/54/25
|
||||
f 47/54/26 48/53/26 50/55/26 49/56/26
|
||||
f 49/56/27 50/55/27 52/57/27 51/58/27
|
||||
f 51/58/28 52/57/28 54/59/28 53/60/28
|
||||
f 53/60/29 54/59/29 56/61/29 55/62/29
|
||||
f 55/62/30 56/61/30 58/63/30 57/64/30
|
||||
f 57/64/31 58/63/31 60/65/31 59/66/31
|
||||
f 59/66/32 60/65/32 62/67/32 61/68/32
|
||||
f 61/68/33 62/67/33 64/69/33 63/70/33
|
||||
f 63/70/34 64/69/34 66/71/34 65/72/34
|
||||
f 65/72/35 66/71/35 68/73/35 67/74/35
|
||||
f 67/74/36 68/73/36 70/75/36 69/76/36
|
||||
f 12/77/37 10/78/37 72/79/37 70/80/37 68/81/37 66/82/37 64/83/37 62/84/37 60/85/37 58/86/37 56/87/37 54/88/37 52/89/37 50/90/37 48/91/37 46/92/37 44/93/37 42/94/37 40/95/37 38/96/37 36/97/37 34/98/37 32/99/37 30/100/37 28/101/37 26/102/37 24/103/37 22/104/37 20/105/37 18/106/37 16/107/37 14/108/37
|
||||
f 69/76/38 70/75/38 72/109/38 71/110/38
|
||||
f 71/110/39 72/109/39 10/111/39 9/112/39
|
||||
f 9/113/40 11/114/40 13/115/40 15/116/40 17/117/40 19/118/40 21/119/40 23/120/40 25/121/40 27/122/40 29/123/40 31/124/40 33/125/40 35/126/40 37/127/40 39/128/40 41/129/40 43/130/40 45/131/40 47/132/40 49/133/40 51/134/40 53/135/40 55/136/40 57/137/40 59/138/40 61/139/40 63/140/40 65/141/40 67/142/40 69/143/40 71/144/40
|
23
build.zig
23
build.zig
@ -32,13 +32,11 @@ pub fn build(b: *Build) void {
|
||||
const assets_step = b.step("assets", "Build and install assets");
|
||||
b.getInstallStep().dependOn(assets_step);
|
||||
|
||||
const assetc = buildAssetCompiler(b, buildOptimize);
|
||||
const assetc = buildAssetCompiler(b, buildOptimize, assets_mod);
|
||||
|
||||
const install_assetc_step = b.addInstallArtifact(assetc, .{ .dest_dir = .{ .override = .prefix } });
|
||||
assets_step.dependOn(&install_assetc_step.step);
|
||||
|
||||
assetc.root_module.addImport("assets", assets_mod);
|
||||
|
||||
const gen_asset_manifest = buildAssets(b, &install_assetc_step.step, assets_step, assetc, "assets") catch |err| {
|
||||
std.log.err("Failed to build assets {}\n", .{err});
|
||||
@panic("buildAssets");
|
||||
@ -205,15 +203,18 @@ fn buildAssets(b: *std.Build, install_assetc_step: *Step, step: *Step, assetc: *
|
||||
return asset_manifest_file;
|
||||
}
|
||||
|
||||
fn buildAssetCompiler(b: *Build, optimize: std.builtin.OptimizeMode) *Step.Compile {
|
||||
fn buildAssetCompiler(b: *Build, optimize: std.builtin.OptimizeMode, assets_mod: *Build.Module) *Step.Compile {
|
||||
const assimp_dep = b.dependency("zig-assimp", .{
|
||||
.target = b.host,
|
||||
.optimize = optimize,
|
||||
//.formats = @as([]const u8, "3DS,3MF,AC,AMF,ASE,Assbin,Assjson,Assxml,B3D,Blender,BVH,C4D,COB,Collada,CSM,DXF,FBX,glTF,glTF2,HMP,IFC,Irr,LWO,LWS,M3D,MD2,MD3,MD5,MDC,MDL,MMD,MS3D,NDO,NFF,Obj,OFF,Ogre,OpenGEX,Ply,Q3BSP,Q3D,Raw,SIB,SMD,Step,STEPParser,STL,Terragen,Unreal,X,X3D,XGL"),
|
||||
.formats = @as([]const u8, "Obj"),
|
||||
});
|
||||
const zalgebra_dep = b.dependency("zalgebra", .{});
|
||||
|
||||
const assimp_lib = assimp_dep.artifact("assimp");
|
||||
// HACK: fix in assimp
|
||||
assimp_lib.defineCMacro("AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER", "\"AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER\"");
|
||||
|
||||
const assetc = b.addExecutable(.{
|
||||
.name = "assetc",
|
||||
@ -223,13 +224,21 @@ fn buildAssetCompiler(b: *Build, optimize: std.builtin.OptimizeMode) *Step.Compi
|
||||
});
|
||||
assetc.linkLibC();
|
||||
|
||||
b.installFile("libs/ispc_texcomp/lib/ispc_texcomp.dll", "ispc_texcomp.dll");
|
||||
b.installFile("libs/ispc_texcomp/lib/ispc_texcomp.pdb", "ispc_texcomp.pdb");
|
||||
if (b.host.result.os.tag == .windows) {
|
||||
b.installFile("libs/ispc_texcomp/lib/ispc_texcomp.dll", "ispc_texcomp.dll");
|
||||
b.installFile("libs/ispc_texcomp/lib/ispc_texcomp.pdb", "ispc_texcomp.pdb");
|
||||
}
|
||||
assetc.addLibraryPath(.{ .path = "libs/ispc_texcomp/lib" });
|
||||
assetc.addIncludePath(.{ .path = "libs/ispc_texcomp/include" });
|
||||
assetc.linkSystemLibrary("ispc_texcomp");
|
||||
|
||||
assetc.root_module.addAnonymousImport("formats", .{ .root_source_file = .{ .path = "src/formats.zig" } });
|
||||
const zalgebra_mod = zalgebra_dep.module("zalgebra");
|
||||
const formats_mod = b.addModule("formats", .{ .root_source_file = .{ .path = "src/formats.zig" } });
|
||||
formats_mod.addImport("zalgebra", zalgebra_mod);
|
||||
formats_mod.addImport("assets", assets_mod);
|
||||
assetc.root_module.addImport("formats", formats_mod);
|
||||
assetc.root_module.addImport("zalgebra", zalgebra_mod);
|
||||
assetc.root_module.addImport("assets", assets_mod);
|
||||
|
||||
assetc.linkLibrary(assimp_lib);
|
||||
assetc.linkLibC();
|
||||
|
@ -122,6 +122,21 @@ pub fn resolveTexture(self: *AssetManager, handle: Handle.Texture) *const Loaded
|
||||
return self.loadTexture(handle.id);
|
||||
}
|
||||
|
||||
pub fn resolveScene(self: *AssetManager, handle: Handle.Scene) *const formats.Scene {
|
||||
if (handle.id == 0) return &NullScene.scene;
|
||||
|
||||
if (self.loaded_assets.getPtr(handle.id)) |asset| {
|
||||
switch (asset.*) {
|
||||
.scene => |*scene| {
|
||||
return &scene.scene;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
return &self.loadScene(handle.id).scene;
|
||||
}
|
||||
|
||||
// TODO: proper watching
|
||||
pub fn watchChanges(self: *AssetManager) void {
|
||||
var iter = self.loaded_assets.iterator();
|
||||
@ -258,6 +273,11 @@ const NullTexture = LoadedTexture{
|
||||
.handle = 0,
|
||||
};
|
||||
|
||||
const NullScene = LoadedScene{
|
||||
.buf = "",
|
||||
.scene = .{},
|
||||
};
|
||||
|
||||
pub fn loadMesh(self: *AssetManager, id: AssetId) *const LoadedMesh {
|
||||
return self.loadMeshErr(id) catch |err| {
|
||||
std.log.err("Error: {} loading mesh at path: {s}", .{ err, asset_manifest.getPath(id) });
|
||||
@ -425,11 +445,41 @@ fn loadTextureErr(self: *AssetManager, id: AssetId) !*const LoadedTexture {
|
||||
return &self.loaded_assets.getPtr(id).?.texture;
|
||||
}
|
||||
|
||||
fn loadScene(self: *AssetManager, id: AssetId) *const LoadedScene {
|
||||
return self.loadSceneErr(id) catch |err| {
|
||||
std.log.err("Error: {} loading scene at path {s}\n", .{ err, asset_manifest.getPath(id) });
|
||||
|
||||
return &NullScene;
|
||||
};
|
||||
}
|
||||
|
||||
fn loadSceneErr(self: *AssetManager, id: AssetId) !*const LoadedScene {
|
||||
const path = asset_manifest.getPath(id);
|
||||
const data = try self.loadFile(self.allocator, path, TEXTURE_MAX_BYTES);
|
||||
|
||||
const scene = try formats.Scene.fromBuffer(data.bytes);
|
||||
|
||||
try self.loaded_assets.put(
|
||||
self.allocator,
|
||||
id,
|
||||
.{
|
||||
.scene = LoadedScene{
|
||||
.buf = data.bytes,
|
||||
.scene = scene,
|
||||
},
|
||||
},
|
||||
);
|
||||
try self.modified_times.put(self.allocator, id, data.modified);
|
||||
|
||||
return &self.loaded_assets.getPtr(id).?.scene;
|
||||
}
|
||||
|
||||
const LoadedAsset = union(enum) {
|
||||
shader: LoadedShader,
|
||||
shaderProgram: LoadedShaderProgram,
|
||||
mesh: LoadedMesh,
|
||||
texture: LoadedTexture,
|
||||
scene: LoadedScene,
|
||||
};
|
||||
|
||||
const LoadedShader = struct {
|
||||
@ -454,6 +504,12 @@ const LoadedTexture = struct {
|
||||
handle: gl.GLuint64,
|
||||
};
|
||||
|
||||
const LoadedScene = struct {
|
||||
// Buffer that holds scene data
|
||||
buf: []const u8,
|
||||
scene: formats.Scene,
|
||||
};
|
||||
|
||||
pub const AABB = struct {
|
||||
min: Vec3 = Vec3.zero(),
|
||||
max: Vec3 = Vec3.zero(),
|
||||
@ -607,6 +663,9 @@ fn unloadAssetWithDependees(self: *AssetManager, id: AssetId) void {
|
||||
gl.GL_ARB_bindless_texture.makeTextureHandleNonResidentARB(texture.handle);
|
||||
gl.deleteTextures(1, &texture.name);
|
||||
},
|
||||
.scene => |*scene| {
|
||||
self.allocator.free(scene.buf);
|
||||
},
|
||||
}
|
||||
}
|
||||
_ = self.loaded_assets.remove(id);
|
||||
|
@ -4,6 +4,7 @@ const c = @import("sdl.zig");
|
||||
const AssetManager = @import("AssetManager.zig");
|
||||
const a = @import("asset_manifest");
|
||||
const globals = @import("globals.zig");
|
||||
pub const Material = @import("formats.zig").Material;
|
||||
|
||||
const za = @import("zalgebra");
|
||||
const Vec2 = za.Vec2;
|
||||
@ -27,9 +28,10 @@ mesh_vao: gl.GLuint = 0,
|
||||
tripple_buffer_index: usize = MAX_FRAMES_QUEUED - 1,
|
||||
gl_fences: [MAX_FRAMES_QUEUED]?gl.GLsync = [_]?gl.GLsync{null} ** MAX_FRAMES_QUEUED,
|
||||
camera_ubo: gl.GLuint = 0,
|
||||
camera_matrices: []CameraMatrices = &.{},
|
||||
camera_matrices: []u8 = &.{},
|
||||
point_lights_ubo: gl.GLuint = 0,
|
||||
point_lights: []PointLightArray = &.{},
|
||||
point_lights: []u8 = &.{},
|
||||
ubo_align: usize = 0,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetman: *AssetManager) Render {
|
||||
var render = Render{
|
||||
@ -38,6 +40,13 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
|
||||
.assetman = assetman,
|
||||
};
|
||||
|
||||
var buffer_align_int: gl.GLint = 0;
|
||||
gl.getIntegerv(gl.UNIFORM_BUFFER_OFFSET_ALIGNMENT, &buffer_align_int);
|
||||
|
||||
if (buffer_align_int == 0) @panic("Failed to query GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT");
|
||||
|
||||
render.ubo_align = @intCast(buffer_align_int);
|
||||
|
||||
// MESH VAO
|
||||
var vao: gl.GLuint = 0;
|
||||
gl.createVertexArrays(1, &vao);
|
||||
@ -72,17 +81,23 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
|
||||
gl.createBuffers(1, &render.camera_ubo);
|
||||
std.debug.assert(render.camera_ubo != 0);
|
||||
|
||||
const buf_size = render.uboAlignedSizeOf(CameraMatrices) * MAX_FRAMES_QUEUED;
|
||||
gl.namedBufferStorage(
|
||||
render.camera_ubo,
|
||||
@sizeOf(CameraMatrices) * MAX_FRAMES_QUEUED,
|
||||
@intCast(buf_size),
|
||||
null,
|
||||
PERSISTENT_BUFFER_FLAGS,
|
||||
);
|
||||
const camera_matrices_c: [*c]CameraMatrices = @alignCast(@ptrCast(gl.mapNamedBufferRange(render.camera_ubo, 0, @sizeOf(CameraMatrices) * MAX_FRAMES_QUEUED, PERSISTENT_BUFFER_FLAGS) orelse {
|
||||
const camera_matrices_c: [*]u8 = @ptrCast(gl.mapNamedBufferRange(
|
||||
render.camera_ubo,
|
||||
0,
|
||||
@intCast(buf_size),
|
||||
PERSISTENT_BUFFER_FLAGS,
|
||||
) orelse {
|
||||
checkGLError();
|
||||
@panic("bind camera_ubo");
|
||||
}));
|
||||
render.camera_matrices = camera_matrices_c[0..MAX_FRAMES_QUEUED];
|
||||
});
|
||||
render.camera_matrices = camera_matrices_c[0..buf_size];
|
||||
}
|
||||
|
||||
// Point lights ubo
|
||||
@ -90,22 +105,23 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, assetm
|
||||
gl.createBuffers(1, &render.point_lights_ubo);
|
||||
std.debug.assert(render.camera_ubo != 0);
|
||||
|
||||
const buf_size = render.uboAlignedSizeOf(PointLightArray) * MAX_FRAMES_QUEUED;
|
||||
gl.namedBufferStorage(
|
||||
render.point_lights_ubo,
|
||||
@sizeOf(PointLightArray) * MAX_FRAMES_QUEUED,
|
||||
@intCast(buf_size),
|
||||
null,
|
||||
PERSISTENT_BUFFER_FLAGS,
|
||||
);
|
||||
const point_lights_c: [*c]PointLightArray = @alignCast(@ptrCast(gl.mapNamedBufferRange(
|
||||
const point_lights_c: [*]u8 = @ptrCast(gl.mapNamedBufferRange(
|
||||
render.point_lights_ubo,
|
||||
0,
|
||||
@sizeOf(PointLightArray) * MAX_FRAMES_QUEUED,
|
||||
@intCast(buf_size),
|
||||
PERSISTENT_BUFFER_FLAGS,
|
||||
) orelse {
|
||||
checkGLError();
|
||||
@panic("bind point_lights_ubo");
|
||||
}));
|
||||
render.point_lights = point_lights_c[0..MAX_FRAMES_QUEUED];
|
||||
});
|
||||
render.point_lights = point_lights_c[0..buf_size];
|
||||
}
|
||||
|
||||
return render;
|
||||
@ -123,7 +139,7 @@ pub fn begin(self: *Render) void {
|
||||
gl.bindVertexArray(self.mesh_vao);
|
||||
|
||||
if (self.gl_fences[self.tripple_buffer_index]) |fence| {
|
||||
const syncResult = gl.clientWaitSync(fence, gl.SYNC_FLUSH_COMMANDS_BIT, 9999999);
|
||||
const syncResult = gl.clientWaitSync(fence, gl.SYNC_FLUSH_COMMANDS_BIT, 9999999999);
|
||||
|
||||
switch (syncResult) {
|
||||
gl.ALREADY_SIGNALED => {
|
||||
@ -132,6 +148,7 @@ pub fn begin(self: *Render) void {
|
||||
gl.TIMEOUT_EXPIRED => {
|
||||
// oh no, driver will crash soon :(
|
||||
std.log.err("OpenGL clientWaitSync timeout expired D:\n", .{});
|
||||
checkGLError();
|
||||
},
|
||||
gl.CONDITION_SATISFIED => {
|
||||
// awesome
|
||||
@ -146,35 +163,43 @@ pub fn begin(self: *Render) void {
|
||||
}
|
||||
|
||||
self.gl_fences[self.tripple_buffer_index] = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
}
|
||||
|
||||
pub fn getPointLights(self: *Render) *PointLightArray {
|
||||
return @alignCast(@ptrCast(self.point_lights[self.tripple_buffer_index * self.uboAlignedSizeOf(PointLightArray) ..].ptr));
|
||||
}
|
||||
|
||||
pub fn flushUBOs(self: *Render) void {
|
||||
const idx = self.tripple_buffer_index;
|
||||
|
||||
{
|
||||
const camera_matrix = &self.camera_matrices[self.tripple_buffer_index];
|
||||
const camera_matrix: *CameraMatrices = @alignCast(@ptrCast(self.camera_matrices[idx * self.uboAlignedSizeOf(CameraMatrices) ..].ptr));
|
||||
|
||||
camera_matrix.* = .{
|
||||
.projection = self.camera.projection(),
|
||||
.view = self.camera.view_mat,
|
||||
};
|
||||
|
||||
//gl.flushMappedNamedBufferRange(self.camera_ubo, idx * @sizeOf(CameraMatrices), @sizeOf(CameraMatrices));
|
||||
gl.bindBufferRange(
|
||||
gl.UNIFORM_BUFFER,
|
||||
UBO.CameraMatrices.value(),
|
||||
self.camera_ubo,
|
||||
self.tripple_buffer_index * @sizeOf(CameraMatrices),
|
||||
@sizeOf(CameraMatrices),
|
||||
idx * self.uboAlignedSizeOf(CameraMatrices),
|
||||
@intCast(self.uboAlignedSizeOf(CameraMatrices)),
|
||||
);
|
||||
checkGLError();
|
||||
}
|
||||
|
||||
// gl.flushMappedNamedBufferRange(self.point_lights_ubo, idx * @sizeOf(PointLightArray), @sizeOf(PointLightArray));
|
||||
gl.bindBufferRange(
|
||||
gl.UNIFORM_BUFFER,
|
||||
UBO.PointLights.value(),
|
||||
self.point_lights_ubo,
|
||||
self.tripple_buffer_index * @sizeOf(PointLightArray),
|
||||
@sizeOf(PointLightArray),
|
||||
idx * self.uboAlignedSizeOf(PointLightArray),
|
||||
@intCast(self.uboAlignedSizeOf(PointLightArray)),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn getPointLights(self: *Render) *PointLightArray {
|
||||
return &self.point_lights[self.tripple_buffer_index];
|
||||
checkGLError();
|
||||
}
|
||||
|
||||
pub fn draw(self: *Render, cmd: DrawCommand) void {
|
||||
@ -321,14 +346,6 @@ pub const PointLightArray = extern struct {
|
||||
count: c_uint,
|
||||
};
|
||||
|
||||
pub const Material = struct {
|
||||
albedo: Vec3 = Vec3.one(),
|
||||
albedo_map: AssetManager.Handle.Texture = .{},
|
||||
normal_map: AssetManager.Handle.Texture = .{},
|
||||
metallic: f32 = 0,
|
||||
metallic_map: AssetManager.Handle.Texture = .{},
|
||||
roughness: f32 = 1,
|
||||
roughness_map: AssetManager.Handle.Texture = .{},
|
||||
emission: f32 = 0,
|
||||
emission_map: AssetManager.Handle.Texture = .{},
|
||||
};
|
||||
fn uboAlignedSizeOf(self: *const Render, comptime T: type) usize {
|
||||
return std.mem.alignForward(usize, @sizeOf(T), self.ubo_align);
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
pub const AssetId = u64;
|
||||
|
||||
pub const Handle = struct {
|
||||
pub const Scene = extern struct { id: AssetId = 0 };
|
||||
pub const Shader = extern struct { id: AssetId = 0 };
|
||||
pub const ShaderProgram = extern struct { id: AssetId = 0 };
|
||||
pub const Mesh = struct { id: AssetId = 0 };
|
||||
pub const Texture = struct { id: AssetId = 0 };
|
||||
pub const Mesh = extern struct { id: AssetId = 0 };
|
||||
pub const Texture = extern struct { id: AssetId = 0 };
|
||||
};
|
||||
|
113
src/formats.zig
113
src/formats.zig
@ -1,6 +1,9 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Handle = @import("assets").Handle;
|
||||
const za = @import("zalgebra");
|
||||
const Vec3 = za.Vec3;
|
||||
pub const Entity = @import("globals.zig").Entity;
|
||||
|
||||
pub const native_endian = builtin.cpu.arch.endian();
|
||||
|
||||
@ -229,6 +232,10 @@ pub const Texture = struct {
|
||||
.data = data,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn free(self: *Texture, allocator: std.mem.Allocator) void {
|
||||
allocator.free(self.data);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: this doesn't respect endiannes at all
|
||||
@ -245,19 +252,111 @@ test "texture write/parse" {
|
||||
var data = [_]u8{ 'h', 'e', 'l', 'l', 'o' };
|
||||
const source = Texture{
|
||||
.header = .{
|
||||
.format = .bc7_srgb,
|
||||
.format = .bc7,
|
||||
.width = 123,
|
||||
.height = 234,
|
||||
.mip_levels = 1,
|
||||
.size = data.len,
|
||||
.mip_count = 1,
|
||||
},
|
||||
.data = &data,
|
||||
.data = &.{&data},
|
||||
};
|
||||
|
||||
var buf: [@sizeOf(Texture.Header) + data.len]u8 = undefined;
|
||||
var buf: [@sizeOf(Texture.Header) + data.len + 4]u8 = undefined;
|
||||
var stream = std.io.fixedBufferStream(&buf);
|
||||
try writeTexture(stream.writer(), source);
|
||||
try writeTexture(stream.writer(), source, native_endian);
|
||||
|
||||
const decoded = try Texture.fromBuffer(&buf);
|
||||
var decoded = try Texture.fromBuffer(std.testing.allocator, &buf);
|
||||
defer decoded.free(std.testing.allocator);
|
||||
try std.testing.expectEqualDeep(source, decoded);
|
||||
}
|
||||
|
||||
pub const Scene = struct {
|
||||
pub const Header = extern struct {
|
||||
magic: [4]u8 = [_]u8{ 'S', 'C', 'N', 'F' }, // Scene Format
|
||||
entity_count: u32 = 0,
|
||||
};
|
||||
|
||||
header: Header = .{},
|
||||
|
||||
entities: []align(1) const Entity.Data = &.{},
|
||||
/// Store parenting info for each entity
|
||||
/// NOTE: Parent index should never be larger than entity index
|
||||
/// because entities will be created in order
|
||||
/// -1 means no parent
|
||||
parents: []align(1) const i64 = &.{},
|
||||
|
||||
pub fn fromBuffer(buf: []u8) !Scene {
|
||||
const header_ptr: *align(1) Header = @ptrCast(buf.ptr);
|
||||
const header = header_ptr.*;
|
||||
|
||||
if (!std.mem.eql(u8, &header.magic, "SCNF")) {
|
||||
return error.MagicMatch;
|
||||
}
|
||||
|
||||
var offset: usize = @sizeOf(Header);
|
||||
var size: usize = @sizeOf(Entity.Data) * header.entity_count;
|
||||
const entities: []align(1) Entity.Data = std.mem.bytesAsSlice(Entity.Data, buf[offset .. offset + size]);
|
||||
offset += size;
|
||||
size = @sizeOf(i64) * header.entity_count;
|
||||
const parents: []align(1) i64 = std.mem.bytesAsSlice(i64, buf[offset .. offset + size]);
|
||||
offset += size;
|
||||
|
||||
return Scene{
|
||||
.header = header,
|
||||
.entities = entities,
|
||||
.parents = parents,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: this doesn't respect endiannes at all
|
||||
pub fn writeScene(writer: anytype, value: Scene, endian: std.builtin.Endian) !void {
|
||||
try writer.writeStruct(value.header);
|
||||
|
||||
// TODO: make writeSlice?
|
||||
for (value.entities) |ent| {
|
||||
try writer.writeStruct(ent);
|
||||
}
|
||||
for (value.parents) |parentIdx| {
|
||||
try writer.writeInt(i64, parentIdx, endian);
|
||||
}
|
||||
}
|
||||
|
||||
test "write and read scene" {
|
||||
var entities = [_]Entity.Data{
|
||||
.{
|
||||
.flags = .{ .point_light = true },
|
||||
.transform = .{},
|
||||
},
|
||||
.{
|
||||
.flags = .{ .point_light = true },
|
||||
.transform = .{ .pos = Vec3.new(1, 2, 3) },
|
||||
},
|
||||
};
|
||||
var parents = [_]i64{-1} ** entities.len;
|
||||
const source = Scene{
|
||||
.header = .{
|
||||
.entity_count = entities.len,
|
||||
},
|
||||
.entities = &entities,
|
||||
.parents = &parents,
|
||||
};
|
||||
|
||||
var buf: [@sizeOf(Scene.Header) + entities.len * @sizeOf(Entity.Data) + entities.len * @sizeOf(i64)]u8 = undefined;
|
||||
var stream = std.io.fixedBufferStream(&buf);
|
||||
try writeScene(stream.writer(), source, native_endian);
|
||||
|
||||
const decoded = try Scene.fromBuffer(&buf);
|
||||
try std.testing.expectEqualDeep(source, decoded);
|
||||
}
|
||||
|
||||
pub const Material = extern struct {
|
||||
albedo: Vec3 = Vec3.one(),
|
||||
albedo_map: Handle.Texture = .{},
|
||||
normal_map: Handle.Texture = .{},
|
||||
metallic: f32 = 0,
|
||||
metallic_map: Handle.Texture = .{},
|
||||
roughness: f32 = 1,
|
||||
roughness_map: Handle.Texture = .{},
|
||||
emission: f32 = 0,
|
||||
emission_map: Handle.Texture = .{},
|
||||
};
|
||||
|
95
src/game.zig
95
src/game.zig
@ -127,6 +127,7 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
||||
.frame_fba = std.heap.FixedBufferAllocator.init(frame_arena_buffer),
|
||||
.assetman = AssetManager.init(global_allocator.*, globals.g_mem.frame_fba.allocator()),
|
||||
.render = Render.init(global_allocator.*, globals.g_mem.frame_fba.allocator(), &globals.g_mem.assetman),
|
||||
.world = .{ .frame_arena = globals.g_mem.frame_fba.allocator() },
|
||||
};
|
||||
globals.g_mem.render.camera = &globals.g_mem.free_cam.camera;
|
||||
std.log.debug("actual ptr: {}, correct ptr {}", .{ globals.g_mem.assetman.frame_arena.ptr, globals.g_mem.frame_fba.allocator().ptr });
|
||||
@ -142,23 +143,29 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
||||
|
||||
gl.viewport(0, 0, globals.g_init.width, globals.g_init.height);
|
||||
|
||||
const light_root = globals.g_mem.world.addEntity(.{
|
||||
.flags = .{ .rotate = true },
|
||||
.transform = .{ .pos = Vec3.new(0, 0.1, 0) },
|
||||
.rotate = .{ .axis = Vec3.up(), .rate = 60 },
|
||||
});
|
||||
|
||||
const light1 = globals.g_mem.world.addEntity(.{
|
||||
.transform = .{ .pos = Vec3.new(1.8, 1, 0) },
|
||||
.flags = .{ .point_light = true, .rotate = true },
|
||||
.point_light = .{ .color_intensity = Vec4.new(1.0, 0.3, 0.1, 100.0), .radius = 0.1 },
|
||||
.rotate = .{ .axis = Vec3.up(), .rate = 60 },
|
||||
.rotate = .{ .axis = Vec3.up(), .rate = -40 },
|
||||
});
|
||||
light1.ptr.setParent(light_root.handle);
|
||||
|
||||
_ = globals.g_mem.world.addEntity(.{
|
||||
const light2 = globals.g_mem.world.addEntity(.{
|
||||
.transform = .{ .pos = Vec3.new(-2, 0, 0) },
|
||||
.parent = light1,
|
||||
.flags = .{ .point_light = true, .rotate = true },
|
||||
.point_light = .{
|
||||
.color_intensity = Vec4.new(0.2, 0.5, 1.0, 100.0),
|
||||
.radius = 0.1,
|
||||
},
|
||||
.rotate = .{ .axis = Vec3.up(), .rate = -20 },
|
||||
});
|
||||
light2.ptr.setParent(light1.handle);
|
||||
|
||||
_ = globals.g_mem.world.addEntity(.{
|
||||
.transform = .{ .pos = Vec3.new(1, 0.5, 4) },
|
||||
@ -219,6 +226,10 @@ export fn game_init(global_allocator: *std.mem.Allocator) void {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const test_scene_root = globals.g_mem.world.createScene(globals.g_assetman.resolveScene(a.Scenes.test_scene.scene));
|
||||
|
||||
std.log.debug("test scene root idx {}\n", .{test_scene_root.idx});
|
||||
}
|
||||
|
||||
export fn game_update() bool {
|
||||
@ -257,10 +268,11 @@ export fn game_update() bool {
|
||||
},
|
||||
c.SDL_KEYUP, c.SDL_KEYDOWN => {
|
||||
const pressed = event.key.state == c.SDL_PRESSED;
|
||||
|
||||
switch (event.key.keysym.scancode) {
|
||||
// Toggle fullscreen
|
||||
c.SDL_SCANCODE_F11 => {
|
||||
if (event.type == c.SDL_KEYDOWN) {
|
||||
c.SDL_SCANCODE_RETURN => {
|
||||
if (event.type == c.SDL_KEYDOWN and event.key.keysym.mod & c.KMOD_ALT > 0) {
|
||||
toggleFullScreen() catch continue;
|
||||
}
|
||||
},
|
||||
@ -344,15 +356,27 @@ export fn game_update() bool {
|
||||
move.zMut().* -= 1;
|
||||
}
|
||||
|
||||
// TODO: make this an entity
|
||||
gmem.free_cam.update(gmem.delta_time, move, look.scale(0.008));
|
||||
|
||||
const f_width: f32 = @floatFromInt(ginit.width);
|
||||
const f_height: f32 = @floatFromInt(ginit.height);
|
||||
|
||||
gmem.free_cam.camera.aspect = f_width / f_height;
|
||||
gmem.rotation += 60 * gmem.delta_time;
|
||||
|
||||
// TODO: make this an entity
|
||||
gmem.free_cam.update(gmem.delta_time, move, look.scale(0.008));
|
||||
|
||||
// Update
|
||||
{
|
||||
for (gmem.world.entities[0..gmem.world.entity_count]) |*ent| {
|
||||
if (!ent.data.flags.active) continue;
|
||||
|
||||
if (ent.data.flags.rotate) {
|
||||
ent.data.transform.rotate(ent.data.rotate.axis, ent.data.rotate.rate * gmem.delta_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render
|
||||
{
|
||||
gmem.render.begin();
|
||||
defer gmem.render.finish();
|
||||
@ -364,25 +388,16 @@ export fn game_update() bool {
|
||||
|
||||
for (0..gmem.world.entity_count) |i| {
|
||||
const ent = &gmem.world.entities[i];
|
||||
if (!ent.flags.active) continue;
|
||||
if (!ent.data.flags.active) continue;
|
||||
|
||||
if (ent.flags.rotate) {
|
||||
const old_pos = ent.transform.pos;
|
||||
const new_pos = Mat4.fromRotation(
|
||||
ent.rotate.rate * gmem.delta_time,
|
||||
ent.rotate.axis,
|
||||
).mulByVec4(Vec4.new(old_pos.x(), old_pos.y(), old_pos.z(), 1));
|
||||
ent.transform.setPos(Vec3.new(new_pos.x(), new_pos.y(), new_pos.z()));
|
||||
}
|
||||
|
||||
if (ent.flags.point_light) {
|
||||
if (ent.data.flags.point_light) {
|
||||
const pos = ent.globalMatrix(&gmem.world).extractTranslation();
|
||||
var pos4 = Vec4.new(pos.x(), pos.y(), pos.z(), 1.0);
|
||||
pos4 = gmem.render.camera.view_mat.mulByVec4(pos4);
|
||||
|
||||
point_lights.lights[point_lights.count] = .{
|
||||
.pos_radius = Vec4.new(pos4.x(), pos4.y(), pos4.z(), ent.point_light.radius),
|
||||
.color_intensity = ent.point_light.color_intensity,
|
||||
.pos_radius = Vec4.new(pos4.x(), pos4.y(), pos4.z(), ent.data.point_light.radius),
|
||||
.color_intensity = ent.data.point_light.color_intensity,
|
||||
};
|
||||
point_lights.count += 1;
|
||||
if (point_lights.count == Render.MAX_POINT_LIGHTS) {
|
||||
@ -390,25 +405,27 @@ export fn game_update() bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render meshes and lights
|
||||
for (0..gmem.world.entity_count) |i| {
|
||||
const ent = &gmem.world.entities[i];
|
||||
if (!ent.flags.active) continue;
|
||||
gmem.render.flushUBOs();
|
||||
|
||||
if (ent.flags.mesh) {
|
||||
gmem.render.draw(.{
|
||||
.mesh = ent.mesh.handle,
|
||||
.material = ent.mesh.material,
|
||||
.transform = ent.globalMatrix(&gmem.world).*,
|
||||
});
|
||||
} else if (ent.flags.point_light) {
|
||||
gmem.render.draw(.{
|
||||
.mesh = a.Meshes.sphere,
|
||||
.material = .{ .albedo = ent.point_light.color() },
|
||||
.transform = ent.globalMatrix(&gmem.world).*,
|
||||
});
|
||||
// Render meshes and lights
|
||||
for (0..gmem.world.entity_count) |i| {
|
||||
const ent = &gmem.world.entities[i];
|
||||
if (!ent.data.flags.active) continue;
|
||||
|
||||
if (ent.data.flags.mesh) {
|
||||
gmem.render.draw(.{
|
||||
.mesh = ent.data.mesh.handle,
|
||||
.material = ent.data.mesh.material,
|
||||
.transform = ent.globalMatrix(&gmem.world).*,
|
||||
});
|
||||
} else if (ent.data.flags.point_light) {
|
||||
gmem.render.draw(.{
|
||||
.mesh = a.Meshes.sphere,
|
||||
.material = .{ .albedo = ent.data.point_light.color() },
|
||||
.transform = ent.globalMatrix(&gmem.world).*,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
pub const manifest = @import("asset_manifest_gen");
|
||||
|
||||
pub const Scenes = manifest.Scenes;
|
||||
pub const Meshes = manifest.Meshes;
|
||||
pub const Shaders = manifest.Shaders;
|
||||
pub const ShaderPrograms = manifest.ShaderPrograms;
|
||||
|
110
src/globals.zig
110
src/globals.zig
@ -2,6 +2,9 @@ const std = @import("std");
|
||||
const c = @import("sdl.zig");
|
||||
const AssetManager = @import("AssetManager.zig");
|
||||
const Render = @import("Render.zig");
|
||||
const formats = @import("formats.zig");
|
||||
const Material = formats.Material;
|
||||
const Scene = formats.Scene;
|
||||
|
||||
const za = @import("zalgebra");
|
||||
const Vec2 = za.Vec2;
|
||||
@ -37,9 +40,10 @@ pub const Entity = struct {
|
||||
mesh: bool = false,
|
||||
point_light: bool = false,
|
||||
rotate: bool = false,
|
||||
_pad: u4 = 0, // make it abi sized
|
||||
};
|
||||
|
||||
pub const Transform = struct {
|
||||
pub const Transform = extern struct {
|
||||
pos: Vec3 = Vec3.zero(),
|
||||
rot: Quat = Quat.identity(),
|
||||
scale: Vec3 = Vec3.one(),
|
||||
@ -64,13 +68,18 @@ pub const Entity = struct {
|
||||
self.pos = self.pos.add(by);
|
||||
self.dirty();
|
||||
}
|
||||
|
||||
pub fn rotate(self: *Transform, axis: Vec3, angle: f32) void {
|
||||
self.rot = self.rot.mul(Quat.fromAxis(angle, axis));
|
||||
self.dirty();
|
||||
}
|
||||
};
|
||||
|
||||
pub const Mesh = struct {
|
||||
pub const Mesh = extern struct {
|
||||
handle: AssetManager.Handle.Mesh = .{},
|
||||
material: Render.Material = .{},
|
||||
material: Material = .{},
|
||||
};
|
||||
pub const PointLight = struct {
|
||||
pub const PointLight = extern struct {
|
||||
radius: f32 = std.math.floatEps(f32), // should never be 0 or bad things happen
|
||||
color_intensity: Vec4 = Vec4.one(), // x, y, z - color, w - intensity
|
||||
|
||||
@ -79,42 +88,53 @@ pub const Entity = struct {
|
||||
return Vec3.new(col.x(), col.y(), col.z());
|
||||
}
|
||||
};
|
||||
pub const Rotate = struct {
|
||||
pub const Rotate = extern struct {
|
||||
axis: Vec3 = Vec3.up(),
|
||||
rate: f32 = 0, // deg/s
|
||||
};
|
||||
|
||||
/// Serializable entity data
|
||||
pub const Data = extern struct {
|
||||
flags: Flags = .{},
|
||||
transform: Transform = .{},
|
||||
mesh: Mesh = .{},
|
||||
point_light: PointLight = .{},
|
||||
rotate: Rotate = .{},
|
||||
};
|
||||
|
||||
// Entity list and handle management
|
||||
idx: u32 = 0,
|
||||
gen: u32 = 0,
|
||||
// Free list
|
||||
next: ?*Entity = null,
|
||||
|
||||
flags: Flags = .{},
|
||||
parent: ?EntityHandle = null,
|
||||
transform: Transform = .{},
|
||||
mesh: Mesh = .{},
|
||||
point_light: PointLight = .{},
|
||||
rotate: Rotate = .{},
|
||||
|
||||
data: Data = .{},
|
||||
|
||||
pub fn setParent(self: *Entity, parent: ?EntityHandle) void {
|
||||
self.parent = parent;
|
||||
self.data.transform.dirty();
|
||||
}
|
||||
|
||||
pub fn localMatrix(self: *Entity) *const Mat4 {
|
||||
if (self.transform._local_dirty) {
|
||||
self.transform._local = Mat4.recompose(self.transform.pos, self.transform.rot, self.transform.scale);
|
||||
self.transform._local_dirty = false;
|
||||
if (self.data.transform._local_dirty) {
|
||||
self.data.transform._local = Mat4.recompose(self.data.transform.pos, self.data.transform.rot, self.data.transform.scale);
|
||||
self.data.transform._local_dirty = false;
|
||||
}
|
||||
return &self.transform._local;
|
||||
return &self.data.transform._local;
|
||||
}
|
||||
|
||||
pub fn globalMatrix(self: *Entity, world: *World) *const Mat4 {
|
||||
// TODO: think how to reduce pointer chasing
|
||||
if (self.parent) |parent_ent| {
|
||||
if (world.getEntity(parent_ent)) |parent| {
|
||||
if (parent.transform._global_dirty or self.transform._global_dirty) {
|
||||
self.transform._global = parent.globalMatrix(world).mul(self.localMatrix().*);
|
||||
self.transform._global_dirty = false;
|
||||
if (parent.data.transform._global_dirty or self.data.transform._global_dirty) {
|
||||
self.data.transform._global = parent.globalMatrix(world).mul(self.localMatrix().*);
|
||||
self.data.transform._global_dirty = false;
|
||||
}
|
||||
|
||||
return &self.transform._global;
|
||||
return &self.data.transform._global;
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,16 +143,28 @@ pub const Entity = struct {
|
||||
};
|
||||
|
||||
pub const EntityHandle = packed struct {
|
||||
idx: u32,
|
||||
gen: u32,
|
||||
idx: u32 = 0,
|
||||
gen: u32 = 0,
|
||||
|
||||
/// Returns handle with 0 idx and gen.
|
||||
/// 0 gen is invalid, valid generations start from 0
|
||||
pub fn invalid() EntityHandle {
|
||||
return EntityHandle{};
|
||||
}
|
||||
};
|
||||
|
||||
pub const EntityCreateResult = struct {
|
||||
handle: EntityHandle,
|
||||
ptr: *Entity,
|
||||
};
|
||||
|
||||
pub const World = struct {
|
||||
frame_arena: std.mem.Allocator,
|
||||
entities: [MAX_ENTITIES]Entity = [_]Entity{.{}} ** MAX_ENTITIES,
|
||||
entity_count: usize = 0,
|
||||
free_entity: ?*Entity = null,
|
||||
|
||||
pub fn addEntity(self: *World, entity: Entity) EntityHandle {
|
||||
pub fn addEntity(self: *World, data: Entity.Data) EntityCreateResult {
|
||||
const ent = result: {
|
||||
if (self.free_entity) |ent| {
|
||||
break :result ent;
|
||||
@ -146,16 +178,44 @@ pub const World = struct {
|
||||
const next = ent.next;
|
||||
const gen = ent.gen;
|
||||
const idx = ent.idx;
|
||||
ent.* = entity;
|
||||
ent.data = data;
|
||||
// TODO: handle wrapping
|
||||
ent.gen = gen + 1;
|
||||
ent.idx = idx;
|
||||
ent.flags.active = true;
|
||||
ent.data.flags.active = true;
|
||||
self.free_entity = next;
|
||||
|
||||
return EntityHandle{ .idx = idx, .gen = ent.gen };
|
||||
return EntityCreateResult{
|
||||
.handle = EntityHandle{ .idx = idx, .gen = ent.gen },
|
||||
.ptr = ent,
|
||||
};
|
||||
}
|
||||
|
||||
/// Spawns a scene and returns a hand to the root entity
|
||||
pub fn createScene(self: *World, scene: *const Scene) EntityHandle {
|
||||
if (scene.entities.len == 0) {
|
||||
return EntityHandle.invalid();
|
||||
}
|
||||
|
||||
const handles = self.frame_arena.alloc(EntityHandle, scene.entities.len) catch @panic("OOM"); // not handling error, this is unrecoverable
|
||||
|
||||
for (0.., handles, scene.entities, scene.parents) |i, *out_handle, *ent, parent| {
|
||||
const res = self.addEntity(ent.*);
|
||||
out_handle.* = res.handle;
|
||||
|
||||
if (parent >= 0) {
|
||||
std.debug.assert(parent < i);
|
||||
res.ptr.parent = handles[@intCast(parent)];
|
||||
}
|
||||
}
|
||||
|
||||
return handles[0];
|
||||
}
|
||||
|
||||
pub fn getEntity(self: *World, handle: EntityHandle) ?*Entity {
|
||||
// Gen 0 is always invalid
|
||||
if (handle.gen == 0) return null;
|
||||
|
||||
const ent = &self.entities[handle.idx];
|
||||
if (ent.gen != handle.gen) {
|
||||
return null;
|
||||
@ -183,7 +243,7 @@ pub const GameMemory = struct {
|
||||
input_state: InputState = .{},
|
||||
free_cam: FreeLookCamera = .{},
|
||||
mouse_focus: bool = false,
|
||||
world: World = .{},
|
||||
world: World,
|
||||
};
|
||||
|
||||
pub const InputState = packed struct {
|
||||
|
@ -7,6 +7,8 @@ const asset_list = @import("asset_list.zig");
|
||||
const AssetListEntry = asset_list.AssetListEntry;
|
||||
const Vector2 = formats.Vector2;
|
||||
const Vector3 = formats.Vector3;
|
||||
const za = @import("zalgebra");
|
||||
const Vec3 = za.Vec3;
|
||||
const c = @cImport({
|
||||
@cInclude("assimp/cimport.h");
|
||||
@cInclude("assimp/scene.h");
|
||||
@ -22,8 +24,8 @@ const c = @cImport({
|
||||
const ASSET_MAX_BYTES = 1024 * 1024 * 1024;
|
||||
|
||||
pub fn resolveAssetTypeByExtension(path: []const u8) ?AssetType {
|
||||
if (std.mem.endsWith(u8, path, ".obj")) {
|
||||
return .Mesh;
|
||||
if (std.mem.endsWith(u8, path, ".obj") or std.mem.endsWith(u8, path, ".fbx")) {
|
||||
return .Scene;
|
||||
}
|
||||
if (std.mem.endsWith(u8, path, ".prog")) {
|
||||
return .ShaderProgram;
|
||||
@ -69,11 +71,11 @@ pub fn main() !void {
|
||||
std.log.debug("rel_input: {s}", .{rel_input});
|
||||
|
||||
switch (asset_type) {
|
||||
.Mesh => try processMesh(allocator, rel_input, output_dir, asset_list_writer),
|
||||
.Scene => try processScene(allocator, rel_input, output_dir, asset_list_writer),
|
||||
.Shader => try copyFile(asset_type, rel_input, output_dir, asset_list_writer),
|
||||
.ShaderProgram => try processShaderProgram(allocator, rel_input, output_dir, asset_list_writer),
|
||||
.Texture => try processTexture(allocator, rel_input, output_dir, asset_list_writer),
|
||||
.Scene => return error.NotImplemented,
|
||||
else => unreachable,
|
||||
}
|
||||
try buf_asset_list_writer.flush();
|
||||
}
|
||||
@ -95,7 +97,12 @@ fn copyFile(_type: AssetType, input: []const u8, output_dir: std.fs.Dir, asset_l
|
||||
try asset_list.writeAssetListEntryText(asset_list_writer, asset_list_entry);
|
||||
}
|
||||
|
||||
fn createOutput(_type: AssetType, asset_path: AssetPath, output_dir: std.fs.Dir, writer: anytype) !std.fs.File {
|
||||
const AssetOutput = struct {
|
||||
file: std.fs.File,
|
||||
list_entry: AssetListEntry,
|
||||
};
|
||||
|
||||
fn createOutput(_type: AssetType, asset_path: AssetPath, output_dir: std.fs.Dir, writer: anytype) !AssetOutput {
|
||||
const asset_list_entry = AssetListEntry{
|
||||
.type = _type,
|
||||
.src_path = asset_path,
|
||||
@ -109,10 +116,18 @@ fn createOutput(_type: AssetType, asset_path: AssetPath, output_dir: std.fs.Dir,
|
||||
|
||||
try asset_list.writeAssetListEntryText(writer, asset_list_entry);
|
||||
|
||||
return try output_subdir.createFile(std.fs.path.basename(out_path), .{});
|
||||
const file = try output_subdir.createFile(std.fs.path.basename(out_path), .{});
|
||||
|
||||
return AssetOutput{
|
||||
.file = file,
|
||||
.list_entry = asset_list_entry,
|
||||
};
|
||||
}
|
||||
|
||||
fn processMesh(allocator: std.mem.Allocator, input: []const u8, output_dir: std.fs.Dir, asset_list_writer: anytype) !void {
|
||||
/// This can output either a single mesh (for simple formats like obj)
|
||||
/// or a scene + a bunch of sub assets (meshes, materials, textures, animations, etc.)
|
||||
/// It all depends on the source asset.
|
||||
fn processScene(allocator: std.mem.Allocator, input: []const u8, output_dir: std.fs.Dir, asset_list_writer: anytype) !void {
|
||||
const input_z = try std.mem.concatWithSentinel(allocator, u8, &.{input}, 0);
|
||||
const maybe_scene: ?*const c.aiScene = @ptrCast(c.aiImportFile(
|
||||
input_z.ptr,
|
||||
@ -126,10 +141,103 @@ fn processMesh(allocator: std.mem.Allocator, input: []const u8, output_dir: std.
|
||||
defer c.aiReleaseImport(scene);
|
||||
|
||||
if (scene.mNumMeshes == 0) return error.NoMeshes;
|
||||
if (scene.mNumMeshes > 1) return error.TooManyMeshes;
|
||||
|
||||
const mesh: *c.aiMesh = @ptrCast(scene.mMeshes[0]);
|
||||
if (scene.mNumMeshes == 1) {
|
||||
const mesh: *c.aiMesh = @ptrCast(scene.mMeshes[0]);
|
||||
|
||||
var output = try createOutput(.Mesh, AssetPath{ .simple = input }, output_dir, asset_list_writer);
|
||||
defer output.file.close();
|
||||
|
||||
return try processMesh(allocator, scene, mesh, output.file);
|
||||
} else {
|
||||
const base_asset_path = AssetPath{ .simple = input };
|
||||
|
||||
const meshes: []*c.aiMesh = @ptrCast(scene.mMeshes[0..@intCast(scene.mNumMeshes)]);
|
||||
|
||||
var mesh_outputs = std.ArrayList(AssetListEntry).init(allocator);
|
||||
|
||||
for (meshes) |mesh| {
|
||||
const name = mesh.mName.data[0..mesh.mName.length];
|
||||
|
||||
var output = try createOutput(.Mesh, base_asset_path.subPath(name), output_dir, asset_list_writer);
|
||||
defer output.file.close();
|
||||
|
||||
try mesh_outputs.append(output.list_entry);
|
||||
|
||||
try processMesh(allocator, scene, mesh, output.file);
|
||||
}
|
||||
|
||||
if (scene.mRootNode == null) return;
|
||||
|
||||
var node_to_entity_idx = std.AutoHashMap(*c.aiNode, usize).init(allocator);
|
||||
var entities = std.ArrayList(formats.Entity.Data).init(allocator);
|
||||
var parents = std.ArrayList(i64).init(allocator);
|
||||
|
||||
// Breadth first traversal
|
||||
var nodeq = std.ArrayList(*c.aiNode).init(allocator);
|
||||
try nodeq.append(@ptrCast(scene.mRootNode));
|
||||
|
||||
while (nodeq.popOrNull()) |node| {
|
||||
if (node.mChildren != null) {
|
||||
const children: []*c.aiNode = @ptrCast(node.mChildren[0..@intCast(node.mNumChildren)]);
|
||||
for (0..children.len) |i| {
|
||||
// Reverse order, because pop taks from end of the list
|
||||
const child = children[children.len - i - 1];
|
||||
try nodeq.append(child);
|
||||
}
|
||||
}
|
||||
|
||||
try entities.append(.{});
|
||||
const idx = entities.items.len - 1;
|
||||
try node_to_entity_idx.put(node, idx);
|
||||
|
||||
const maybe_parent: ?*c.aiNode = @ptrCast(node.mParent);
|
||||
if (maybe_parent) |parent| {
|
||||
const parent_idx = node_to_entity_idx.get(parent) orelse return error.MissingParentIdx; // this is a bug in our code
|
||||
try parents.append(@intCast(parent_idx));
|
||||
} else {
|
||||
try parents.append(-1);
|
||||
}
|
||||
|
||||
const ent = &entities.items[idx];
|
||||
|
||||
// TODO: extract transform
|
||||
|
||||
if (node.mMeshes != null) {
|
||||
const mesh_indices = node.mMeshes[0..node.mNumMeshes];
|
||||
for (mesh_indices) |mesh_idx| {
|
||||
const mesh_entry = mesh_outputs.items[@intCast(mesh_idx)];
|
||||
ent.flags.mesh = true;
|
||||
ent.flags.rotate = true;
|
||||
|
||||
// TODO: turn multiple meshes into sub-entities
|
||||
ent.mesh = .{
|
||||
.handle = .{ .id = mesh_entry.src_path.hash() },
|
||||
// TODO: extract material
|
||||
};
|
||||
ent.rotate = .{ .axis = Vec3.up(), .rate = 80 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const out_scene = formats.Scene{
|
||||
.header = .{
|
||||
.entity_count = @intCast(entities.items.len),
|
||||
},
|
||||
.entities = entities.items,
|
||||
.parents = parents.items,
|
||||
};
|
||||
|
||||
const output = try createOutput(.Scene, base_asset_path.subPath("scene"), output_dir, asset_list_writer);
|
||||
defer output.file.close();
|
||||
var buf_writer = std.io.bufferedWriter(output.file.writer());
|
||||
try formats.writeScene(buf_writer.writer(), out_scene, formats.native_endian);
|
||||
try buf_writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
fn processMesh(allocator: std.mem.Allocator, scene: *const c.aiScene, mesh: *const c.aiMesh, out_file: std.fs.File) !void {
|
||||
_ = scene; // autofix
|
||||
if (mesh.mNormals == null) return error.MissingNormals;
|
||||
if (mesh.mTangents == null) return error.MissingTangents;
|
||||
if (mesh.mTextureCoords[0] == null) return error.MissingUVs;
|
||||
@ -196,10 +304,7 @@ fn processMesh(allocator: std.mem.Allocator, input: []const u8, output_dir: std.
|
||||
.indices = indices,
|
||||
};
|
||||
|
||||
var out_file = try createOutput(.Mesh, AssetPath{ .simple = input }, output_dir, asset_list_writer);
|
||||
defer out_file.close();
|
||||
var buf_writer = std.io.bufferedWriter(out_file.writer());
|
||||
|
||||
try formats.writeMesh(
|
||||
buf_writer.writer(),
|
||||
out_mesh,
|
||||
@ -236,9 +341,9 @@ fn processShaderProgram(allocator: std.mem.Allocator, input: []const u8, output_
|
||||
return error.InvalidShaderPath;
|
||||
}
|
||||
|
||||
var out_file = try createOutput(.ShaderProgram, AssetPath{ .simple = input }, output_dir, asset_list_writer);
|
||||
defer out_file.close();
|
||||
var buf_writer = std.io.bufferedWriter(out_file.writer());
|
||||
const output = try createOutput(.ShaderProgram, AssetPath{ .simple = input }, output_dir, asset_list_writer);
|
||||
defer output.file.close();
|
||||
var buf_writer = std.io.bufferedWriter(output.file.writer());
|
||||
|
||||
try formats.writeShaderProgram(buf_writer.writer(), shader_asset_id, program.value.vertex, program.value.fragment, formats.native_endian);
|
||||
try buf_writer.flush();
|
||||
@ -347,9 +452,9 @@ fn processTexture(allocator: std.mem.Allocator, input: []const u8, output_dir: s
|
||||
.data = out_data,
|
||||
};
|
||||
|
||||
const out_file = try createOutput(.Texture, AssetPath{ .simple = input }, output_dir, asset_list_writer);
|
||||
defer out_file.close();
|
||||
var buf_writer = std.io.bufferedWriter(out_file.writer());
|
||||
const output = try createOutput(.Texture, AssetPath{ .simple = input }, output_dir, asset_list_writer);
|
||||
defer output.file.close();
|
||||
var buf_writer = std.io.bufferedWriter(output.file.writer());
|
||||
|
||||
try formats.writeTexture(buf_writer.writer(), texture, formats.native_endian);
|
||||
try buf_writer.flush();
|
||||
|
Loading…
x
Reference in New Issue
Block a user