From 47a0c0317cc774c19b78582bec9b5b09d56f569a Mon Sep 17 00:00:00 2001 From: tcmal Date: Sun, 25 Aug 2024 17:44:23 +0100 Subject: feat(render): draw passes --- Cargo.toml | 2 +- examples/render-bsp/Cargo.toml | 20 - examples/render-bsp/data/newtest.bsp | Bin 66488 -> 0 bytes examples/render-bsp/data/newtest.map | 110 ---- examples/render-bsp/data/test.bsp | Bin 63640 -> 0 bytes examples/render-bsp/data/test.map | 116 ---- examples/render-bsp/src/main.rs | 183 ------ examples/render-quad/Cargo.toml | 20 + examples/render-quad/src/level.rs | 78 +++ examples/render-quad/src/main.rs | 229 +++++++ stockton-input-codegen/src/lib.rs | 12 +- stockton-levels/Cargo.toml | 3 +- stockton-levels/src/features.rs | 7 +- stockton-levels/src/parts/faces.rs | 2 +- stockton-levels/src/parts/vertices.rs | 2 +- stockton-levels/src/parts/visdata.rs | 6 +- stockton-render/Cargo.toml | 1 + stockton-render/src/draw/buffers/mod.rs | 15 +- stockton-render/src/draw/buffers/staged.rs | 76 +-- stockton-render/src/draw/builders/mod.rs | 3 + stockton-render/src/draw/builders/pipeline.rs | 276 ++++++++ stockton-render/src/draw/builders/renderpass.rs | 75 +++ stockton-render/src/draw/builders/shader.rs | 35 + stockton-render/src/draw/camera.rs | 76 +-- stockton-render/src/draw/context.rs | 41 +- stockton-render/src/draw/draw_passes/cons.rs | 45 +- stockton-render/src/draw/draw_passes/level.rs | 812 ++++++++++++------------ stockton-render/src/draw/draw_passes/mod.rs | 27 +- stockton-render/src/draw/mod.rs | 3 +- stockton-render/src/draw/queue_negotiator.rs | 19 +- stockton-render/src/draw/target.rs | 85 ++- stockton-render/src/draw/texture/resolver.rs | 6 +- stockton-render/src/lib.rs | 27 +- stockton-render/src/systems.rs | 1 + stockton-render/src/types.rs | 1 + stockton-render/src/window.rs | 6 +- stockton-types/Cargo.toml | 1 - stockton-types/src/components/mod.rs | 14 + stockton-types/src/session.rs | 2 +- 39 files changed, 1365 insertions(+), 1072 deletions(-) delete mode 100644 examples/render-bsp/Cargo.toml delete mode 100644 examples/render-bsp/data/newtest.bsp delete mode 100644 examples/render-bsp/data/newtest.map delete mode 100644 examples/render-bsp/data/test.bsp delete mode 100644 examples/render-bsp/data/test.map delete mode 100644 examples/render-bsp/src/main.rs create mode 100644 examples/render-quad/Cargo.toml create mode 100644 examples/render-quad/src/level.rs create mode 100644 examples/render-quad/src/main.rs create mode 100644 stockton-render/src/draw/builders/mod.rs create mode 100644 stockton-render/src/draw/builders/pipeline.rs create mode 100644 stockton-render/src/draw/builders/renderpass.rs create mode 100644 stockton-render/src/draw/builders/shader.rs diff --git a/Cargo.toml b/Cargo.toml index 4403a53..d365a31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,6 @@ members = [ "stockton-contrib", "rendy-memory", "rendy-descriptor", - "examples/render-bsp", + "examples/render-quad", "examples/input-codegen", ] diff --git a/examples/render-bsp/Cargo.toml b/examples/render-bsp/Cargo.toml deleted file mode 100644 index bdbab89..0000000 --- a/examples/render-bsp/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "render-bsp" -version = "0.1.0" -authors = ["Oscar "] -edition = "2018" - -[dependencies] -stockton-render = { path = "../../stockton-render", features = ["vulkan"] } -stockton-input = { path = "../../stockton-input" } -stockton-input-codegen = { path = "../../stockton-input-codegen" } -stockton-types = { path = "../../stockton-types" } -stockton-levels = { path = "../../stockton-levels" } -stockton-contrib = { path = "../../stockton-contrib", features = ["delta_time", "flycam"] } -winit = "^0.21" -log = "0.4.0" -simplelog = "^0.10" -image = "0.23.2" -egui = "^0.12" -legion = { version = "^0.3" } -anyhow = "1.0.40" diff --git a/examples/render-bsp/data/newtest.bsp b/examples/render-bsp/data/newtest.bsp deleted file mode 100644 index a89f408..0000000 Binary files a/examples/render-bsp/data/newtest.bsp and /dev/null differ diff --git a/examples/render-bsp/data/newtest.map b/examples/render-bsp/data/newtest.map deleted file mode 100644 index 8ad8889..0000000 --- a/examples/render-bsp/data/newtest.map +++ /dev/null @@ -1,110 +0,0 @@ -// entity 0 -{ -"classname" "worldspawn" -"_q3map2_cmdline" "-meta; -vis -saveprt; -light -fast -filter" -"_q3map2_version" "2.5.17n-git-7d2c6f1a" -// brush 0 -{ -( -192 0 0 ) ( -192 256 0 ) ( -192 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 192 0 0 ) ( 192 -256 0 ) ( 192 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 -208 0 ) ( 0 -208 -256 ) ( -256 -208 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 176 0 ) ( 0 176 256 ) ( -256 176 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( -192 176 256 ) ( -192 -208 256 ) ( 192 -208 256 ) skies/toxicskydim 0 0 0 0.5 0.5 0 0 0 -( 0 0 320 ) ( 256 0 320 ) ( 0 -256 320 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -} -// brush 1 -{ -( 192 -208 256 ) ( 192 -208 192 ) ( 192 176 192 ) base_floor/concrete 0 0 0 0.5 0.5 0 0 0 -( 256 0 0 ) ( 256 -256 0 ) ( 256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 -208 0 ) ( 0 -208 -256 ) ( -256 -208 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 176 0 ) ( 0 176 256 ) ( -256 176 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 192 176 192 ) ( 192 -208 192 ) ( 256 -208 192 ) base_floor/concrete 0 0 0 0.5 0.5 0 0 0 -( 0 0 256 ) ( 256 0 256 ) ( 0 -256 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -} -// brush 2 -{ -( -192 0 0 ) ( -192 256 0 ) ( -192 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 256 0 0 ) ( 256 -256 0 ) ( 256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 -272 0 ) ( 0 -272 -256 ) ( -256 -272 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( -192 -208 256 ) ( -192 -208 192 ) ( 256 -208 192 ) base_floor/concrete 0 0 0 0.5 0.5 0 0 0 -( -192 -208 192 ) ( -192 -272 192 ) ( 256 -272 192 ) base_floor/concrete 0 0 0 0.5 0.5 0 0 0 -( 0 0 256 ) ( 256 0 256 ) ( 0 -256 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -} -// brush 3 -{ -( -256 0 0 ) ( -256 256 0 ) ( -256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( -192 176 256 ) ( -192 176 192 ) ( -192 -272 192 ) base_floor/concrete 0 0 -0 0.5 0.5 0 0 0 -( 0 -272 0 ) ( 0 -272 -256 ) ( -256 -272 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 176 0 ) ( 0 176 256 ) ( -256 176 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( -256 176 192 ) ( -256 -272 192 ) ( -192 -272 192 ) base_floor/concrete 0 0 0 0.5 0.5 0 0 0 -( 0 0 256 ) ( 256 0 256 ) ( 0 -256 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -} -// brush 4 -{ -( -256 0 0 ) ( -256 256 0 ) ( -256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 256 0 0 ) ( 256 -256 0 ) ( 256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 256 176 256 ) ( 256 176 192 ) ( -256 176 192 ) base_floor/concrete 0 0 -0 0.5 0.5 0 0 0 -( 0 240 0 ) ( 0 240 256 ) ( -256 240 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( -256 240 192 ) ( -256 176 192 ) ( 256 176 192 ) base_floor/concrete 0 0 0 0.5 0.5 0 0 0 -( 0 0 256 ) ( 256 0 256 ) ( 0 -256 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -} -// brush 5 -{ -( -256 0 0 ) ( -256 256 0 ) ( -256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 256 0 0 ) ( 256 -256 0 ) ( 256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 -336 0 ) ( 0 -336 -256 ) ( -256 -336 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( -256 -272 192 ) ( -256 -272 -256 ) ( 256 -272 -256 ) base_wall/bluemetal2 0 0 0 0.5 0.5 0 0 0 -( 0 0 -256 ) ( -256 0 -256 ) ( 0 -256 -256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 0 192 ) ( 256 0 192 ) ( 0 -256 192 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -} -// brush 6 -{ -( -256 0 0 ) ( -256 256 0 ) ( -256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 256 0 0 ) ( 256 -256 0 ) ( 256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 256 240 192 ) ( 256 240 -256 ) ( -256 240 -256 ) base_wall/bluemetal2 0 0 -0 0.5 0.5 0 0 0 -( 0 304 0 ) ( 0 304 256 ) ( -256 304 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 0 -256 ) ( -256 0 -256 ) ( 0 -256 -256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 0 192 ) ( 256 0 192 ) ( 0 -256 192 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -} -// brush 7 -{ -( -320 0 0 ) ( -320 256 0 ) ( -320 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( -256 240 192 ) ( -256 240 -256 ) ( -256 -272 -256 ) base_wall/bluemetal2 0 0 -0 0.5 0.5 0 0 0 -( 0 -272 0 ) ( 0 -272 -256 ) ( -256 -272 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 240 0 ) ( 0 240 256 ) ( -256 240 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 0 -256 ) ( -256 0 -256 ) ( 0 -256 -256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 0 192 ) ( 256 0 192 ) ( 0 -256 192 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -} -// brush 8 -{ -( 256 -272 192 ) ( 256 -272 -256 ) ( 256 240 -256 ) base_wall/bluemetal2 0 0 0 0.5 0.5 0 0 0 -( 320 0 0 ) ( 320 -256 0 ) ( 320 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 -272 0 ) ( 0 -272 -256 ) ( -256 -272 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 240 0 ) ( 0 240 256 ) ( -256 240 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 0 -256 ) ( -256 0 -256 ) ( 0 -256 -256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 0 192 ) ( 256 0 192 ) ( 0 -256 192 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -} -// brush 9 -{ -( -256 0 0 ) ( -256 256 0 ) ( -256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 256 0 0 ) ( 256 -256 0 ) ( 256 0 256 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 -272 0 ) ( 0 -272 -256 ) ( -256 -272 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 240 0 ) ( 0 240 256 ) ( -256 240 0 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( 0 0 -320 ) ( -256 0 -320 ) ( 0 -256 -320 ) common/caulk 0 0 0 0.25 0.25 0 0 0 -( -256 -272 -256 ) ( -256 240 -256 ) ( 256 240 -256 ) base_floor/clang_floor2 0 0 -0 0.5 0.5 0 0 0 -} -// brush 10 -{ -( 192 64 64 ) ( 192 0 64 ) ( 128 64 64 ) gothic_trim/gothgrate2 0 0 0 0.5 0.5 0 0 0 -( 192 64 64 ) ( 128 64 64 ) ( 192 64 -576 ) gothic_trim/newskull 0 -0 0 0.5 0.5 0 0 0 -( 192 64 56 ) ( 192 64 -584 ) ( 192 0 56 ) gothic_trim/tower_top 0 496 0 0.5 0.5 0 0 0 -( 144 0 0 ) ( 208 0 0 ) ( 144 64 0 ) gothic_trim/pitted_rust3_dkred 480 0 0 0.5 0.5 0 0 0 -( 128 0 -576 ) ( 128 0 64 ) ( 192 0 -576 ) gothic_trim/metalsupport4b 0 -0 0 0.5 0.5 0 0 0 -( 128 0 -576 ) ( 128 64 -576 ) ( 128 0 64 ) gothic_trim/metalsupport4i_bit 0 -0 0 0.5 0.5 0 0 0 -} -} -// entity 1 -{ -"classname" "info_player_start" -"origin" "-8.000000 -6.000000 15.000000" -} diff --git a/examples/render-bsp/data/test.bsp b/examples/render-bsp/data/test.bsp deleted file mode 100644 index 2aa0334..0000000 Binary files a/examples/render-bsp/data/test.bsp and /dev/null differ diff --git a/examples/render-bsp/data/test.map b/examples/render-bsp/data/test.map deleted file mode 100644 index 9f4915f..0000000 --- a/examples/render-bsp/data/test.map +++ /dev/null @@ -1,116 +0,0 @@ -// Generated by Q3Map2 (ydnar) -convert -format map -// entity 0 -{ - "classname" "worldspawn" - "_q3map2_cmdline" "-meta; -vis -saveprt; -light -fast -filter" - "_q3map2_version" "2.5.17n-git-7d2c6f1a" - - // brush 0 - { - ( -192.000 0.000 0.000 ) ( -192.000 256.000 0.000 ) ( -192.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 192.000 0.000 0.000 ) ( 192.000 -256.000 0.000 ) ( 192.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 -208.000 0.000 ) ( 0.000 -208.000 -256.000 ) ( -256.000 -208.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 176.000 0.000 ) ( 0.000 176.000 256.000 ) ( -256.000 176.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( -192.000 176.000 256.000 ) ( -192.000 -208.000 256.000 ) ( 192.000 -208.000 256.000 ) skies/toxicskydim 0.00000000 0.00000000 0.00000000 0.50000000 0.50000000 0 0 0 - ( 0.000 0.000 320.000 ) ( 256.000 0.000 320.000 ) ( 0.000 -256.000 320.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - } - - // brush 1 - { - ( 192.000 -208.000 256.000 ) ( 192.000 -208.000 192.000 ) ( 192.000 176.000 192.000 ) base_floor/concrete 0.00000000 0.00000000 0.00000000 0.50000000 0.50000000 0 0 0 - ( 256.000 0.000 0.000 ) ( 256.000 -256.000 0.000 ) ( 256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 -208.000 0.000 ) ( 0.000 -208.000 -256.000 ) ( -256.000 -208.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 176.000 0.000 ) ( 0.000 176.000 256.000 ) ( -256.000 176.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 192.000 176.000 192.000 ) ( 192.000 -208.000 192.000 ) ( 256.000 -208.000 192.000 ) base_floor/concrete 0.00000000 0.00000000 0.00000000 0.50000000 0.50000000 0 0 0 - ( 0.000 0.000 256.000 ) ( 256.000 0.000 256.000 ) ( 0.000 -256.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - } - - // brush 2 - { - ( -192.000 0.000 0.000 ) ( -192.000 256.000 0.000 ) ( -192.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 256.000 0.000 0.000 ) ( 256.000 -256.000 0.000 ) ( 256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 -272.000 0.000 ) ( 0.000 -272.000 -256.000 ) ( -256.000 -272.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( -192.000 -208.000 256.000 ) ( -192.000 -208.000 192.000 ) ( 256.000 -208.000 192.000 ) base_floor/concrete 0.00000000 0.00000000 0.00000000 0.50000000 0.50000000 0 0 0 - ( -192.000 -208.000 192.000 ) ( -192.000 -272.000 192.000 ) ( 256.000 -272.000 192.000 ) base_floor/concrete 0.00000000 0.00000000 0.00000000 0.50000000 0.50000000 0 0 0 - ( 0.000 0.000 256.000 ) ( 256.000 0.000 256.000 ) ( 0.000 -256.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - } - - // brush 3 - { - ( -256.000 0.000 0.000 ) ( -256.000 256.000 0.000 ) ( -256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( -192.000 176.000 256.000 ) ( -192.000 176.000 192.000 ) ( -192.000 -272.000 192.000 ) base_floor/concrete 0.00000000 0.00000000 -0.00000000 0.50000000 0.50000000 0 0 0 - ( 0.000 -272.000 0.000 ) ( 0.000 -272.000 -256.000 ) ( -256.000 -272.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 176.000 0.000 ) ( 0.000 176.000 256.000 ) ( -256.000 176.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( -256.000 176.000 192.000 ) ( -256.000 -272.000 192.000 ) ( -192.000 -272.000 192.000 ) base_floor/concrete 0.00000000 0.00000000 0.00000000 0.50000000 0.50000000 0 0 0 - ( 0.000 0.000 256.000 ) ( 256.000 0.000 256.000 ) ( 0.000 -256.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - } - - // brush 4 - { - ( -256.000 0.000 0.000 ) ( -256.000 256.000 0.000 ) ( -256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 256.000 0.000 0.000 ) ( 256.000 -256.000 0.000 ) ( 256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 256.000 176.000 256.000 ) ( 256.000 176.000 192.000 ) ( -256.000 176.000 192.000 ) base_floor/concrete 0.00000000 0.00000000 -0.00000000 0.50000000 0.50000000 0 0 0 - ( 0.000 240.000 0.000 ) ( 0.000 240.000 256.000 ) ( -256.000 240.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( -256.000 240.000 192.000 ) ( -256.000 176.000 192.000 ) ( 256.000 176.000 192.000 ) base_floor/concrete 0.00000000 0.00000000 0.00000000 0.50000000 0.50000000 0 0 0 - ( 0.000 0.000 256.000 ) ( 256.000 0.000 256.000 ) ( 0.000 -256.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - } - - // brush 5 - { - ( -256.000 0.000 0.000 ) ( -256.000 256.000 0.000 ) ( -256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 256.000 0.000 0.000 ) ( 256.000 -256.000 0.000 ) ( 256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 -336.000 0.000 ) ( 0.000 -336.000 -256.000 ) ( -256.000 -336.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( -256.000 -272.000 192.000 ) ( -256.000 -272.000 -256.000 ) ( 256.000 -272.000 -256.000 ) base_wall/bluemetal2 0.00000000 0.00000000 0.00000000 0.50000000 0.50000000 0 0 0 - ( 0.000 0.000 -256.000 ) ( -256.000 0.000 -256.000 ) ( 0.000 -256.000 -256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 0.000 192.000 ) ( 256.000 0.000 192.000 ) ( 0.000 -256.000 192.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - } - - // brush 6 - { - ( -256.000 0.000 0.000 ) ( -256.000 256.000 0.000 ) ( -256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 256.000 0.000 0.000 ) ( 256.000 -256.000 0.000 ) ( 256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 256.000 240.000 192.000 ) ( 256.000 240.000 -256.000 ) ( -256.000 240.000 -256.000 ) base_wall/bluemetal2 0.00000000 0.00000000 -0.00000000 0.50000000 0.50000000 0 0 0 - ( 0.000 304.000 0.000 ) ( 0.000 304.000 256.000 ) ( -256.000 304.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 0.000 -256.000 ) ( -256.000 0.000 -256.000 ) ( 0.000 -256.000 -256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 0.000 192.000 ) ( 256.000 0.000 192.000 ) ( 0.000 -256.000 192.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - } - - // brush 7 - { - ( -320.000 0.000 0.000 ) ( -320.000 256.000 0.000 ) ( -320.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( -256.000 240.000 192.000 ) ( -256.000 240.000 -256.000 ) ( -256.000 -272.000 -256.000 ) base_wall/bluemetal2 0.00000000 0.00000000 -0.00000000 0.50000000 0.50000000 0 0 0 - ( 0.000 -272.000 0.000 ) ( 0.000 -272.000 -256.000 ) ( -256.000 -272.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 240.000 0.000 ) ( 0.000 240.000 256.000 ) ( -256.000 240.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 0.000 -256.000 ) ( -256.000 0.000 -256.000 ) ( 0.000 -256.000 -256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 0.000 192.000 ) ( 256.000 0.000 192.000 ) ( 0.000 -256.000 192.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - } - - // brush 8 - { - ( 256.000 -272.000 192.000 ) ( 256.000 -272.000 -256.000 ) ( 256.000 240.000 -256.000 ) base_wall/bluemetal2 0.00000000 0.00000000 0.00000000 0.50000000 0.50000000 0 0 0 - ( 320.000 0.000 0.000 ) ( 320.000 -256.000 0.000 ) ( 320.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 -272.000 0.000 ) ( 0.000 -272.000 -256.000 ) ( -256.000 -272.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 240.000 0.000 ) ( 0.000 240.000 256.000 ) ( -256.000 240.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 0.000 -256.000 ) ( -256.000 0.000 -256.000 ) ( 0.000 -256.000 -256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 0.000 192.000 ) ( 256.000 0.000 192.000 ) ( 0.000 -256.000 192.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - } - - // brush 9 - { - ( -256.000 0.000 0.000 ) ( -256.000 256.000 0.000 ) ( -256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 256.000 0.000 0.000 ) ( 256.000 -256.000 0.000 ) ( 256.000 0.000 256.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 -272.000 0.000 ) ( 0.000 -272.000 -256.000 ) ( -256.000 -272.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 240.000 0.000 ) ( 0.000 240.000 256.000 ) ( -256.000 240.000 0.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( 0.000 0.000 -320.000 ) ( -256.000 0.000 -320.000 ) ( 0.000 -256.000 -320.000 ) common/caulk 0.00000000 0.00000000 0.00000000 0.25000000 0.25000000 0 0 0 - ( -256.000 -272.000 -256.000 ) ( -256.000 240.000 -256.000 ) ( 256.000 240.000 -256.000 ) base_floor/clang_floor2 0.00000000 0.00000000 -0.00000000 0.50000000 0.50000000 0 0 0 - } - -} - -// entity 1 -{ - "classname" "info_player_start" - "origin" "-8.000000 -6.000000 15.000000" - -} - diff --git a/examples/render-bsp/src/main.rs b/examples/render-bsp/src/main.rs deleted file mode 100644 index 73475c0..0000000 --- a/examples/render-bsp/src/main.rs +++ /dev/null @@ -1,183 +0,0 @@ -//! Renders ./example.bsp - -#[macro_use] -extern crate stockton_input_codegen; - -#[macro_use] -extern crate legion; - -use anyhow::{Context, Result}; -use log::warn; -use std::collections::BTreeMap; -use std::fs::File; -use std::io::Read; -use std::path::Path; -use winit::{event::Event, event_loop::EventLoop, window::WindowBuilder}; - -use egui::{containers::CentralPanel, Frame}; -use stockton_contrib::delta_time::*; -use stockton_contrib::flycam::*; - -use stockton_input::{Axis, InputManager, Mouse}; -use stockton_levels::prelude::*; - -use stockton_render::error::full_error_display; -use stockton_render::systems::*; -use stockton_render::{Renderer, UiState, WindowEvent}; - -use stockton_types::components::{CameraSettings, Transform}; -use stockton_types::{Session, Vector3}; - -type MapFile = (); - -#[derive(InputManager, Default, Clone, Debug)] -struct MovementInputs { - #[axis] - x: Axis, - - #[axis] - y: Axis, - - #[axis] - z: Axis, -} - -impl FlycamInput for MovementInputs { - fn get_x_axis(&self) -> &Axis { - &self.x - } - fn get_y_axis(&self) -> &Axis { - &self.y - } - fn get_z_axis(&self) -> &Axis { - &self.z - } -} - -#[system] -fn hello_world(#[resource] ui: &mut UiState) { - CentralPanel::default() - .frame(Frame::none()) - .show(ui.ctx(), |ui| { - ui.heading("Hello, World!"); - }); -} - -fn main() { - if let Err(err) = try_main() { - eprintln!("{}", full_error_display(err)); - } -} - -fn try_main() -> Result<()> { - // Initialise logger - simplelog::TermLogger::init( - log::LevelFilter::Debug, - simplelog::ConfigBuilder::new() - .set_max_level(log::LevelFilter::Debug) - .set_thread_mode(simplelog::ThreadLogMode::Names) - .build(), - simplelog::TerminalMode::Stderr, - simplelog::ColorChoice::Auto, - ) - .context("Error initialising logger")?; - - // Make a window - let event_loop = EventLoop::new(); - let window = WindowBuilder::new() - .build(&event_loop) - .context("Error creating window")?; - - if window.set_cursor_grab(true).is_err() { - warn!("warning: cursor not grabbed"); - } - window.set_cursor_visible(false); - - // TODO: Parse the map file - let map = todo!(); - - // Create the UI State - let mut ui = UiState::new(); - - // Create the renderer - let (renderer, tx) = Renderer::new(&window)?; - let new_control_flow = renderer.update_control_flow.clone(); - - // Populate the initial UI state - ui.populate_initial_state(&renderer); - - // Create the input manager - let manager = { - use stockton_input::InputMutation::*; - use MovementInputsFields::*; - - let mut actions = BTreeMap::new(); - - actions.insert(17, (Z, PositiveAxis)); // W - actions.insert(30, (X, NegativeAxis)); // A - actions.insert(31, (Z, NegativeAxis)); // S - actions.insert(32, (X, PositiveAxis)); // D - actions.insert(29, (Y, NegativeAxis)); // Ctrl - actions.insert(57, (Y, PositiveAxis)); // Space - - MovementInputsManager::new(actions) - }; - - // Load everything into the session - let mut session = Session::new( - move |resources| { - resources.insert(ui); - resources.insert(map); - resources.insert(manager); - resources.insert(Timing::default()); - resources.insert(Mouse::default()); - }, - move |schedule| { - schedule - .add_system(update_deltatime_system()) - .add_system(process_window_events_system::()) - .flush() - .add_system(hello_world_system()) - .add_system(flycam_move_system::()) - .flush(); - }, - ); - - // Add our player entity - let _player = session.world.push(( - Transform { - position: Vector3::new(0.0, 0.0, 0.0), - rotation: Vector3::new(0.0, 0.0, 0.0), - }, - CameraSettings { - far: 1024.0, - fov: 90.0, - near: 0.1, - }, - FlycamControlled::new(512.0, 400.0), - )); - - // Done loading - This is our main loop. - // It just communicates events to the session and continuously ticks - event_loop.run(move |event, _, flow| { - match event { - Event::MainEventsCleared => { - window.request_redraw(); - } - Event::RedrawRequested(_) => session.do_update(), - _ => { - if let Some(we) = WindowEvent::from(&event) { - tx.send(we).unwrap() - } - } - } - - // Update the control flow if the session has requested it. - { - let new_control_flow = new_control_flow.read().unwrap(); - if *new_control_flow != *flow { - *flow = *new_control_flow; - } - }; - }); -} diff --git a/examples/render-quad/Cargo.toml b/examples/render-quad/Cargo.toml new file mode 100644 index 0000000..d32aa6e --- /dev/null +++ b/examples/render-quad/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "render-quad" +version = "0.1.0" +authors = ["Oscar "] +edition = "2018" + +[dependencies] +stockton-render = { path = "../../stockton-render", features = ["vulkan"] } +stockton-input = { path = "../../stockton-input" } +stockton-input-codegen = { path = "../../stockton-input-codegen" } +stockton-types = { path = "../../stockton-types" } +stockton-levels = { path = "../../stockton-levels" } +stockton-contrib = { path = "../../stockton-contrib", features = ["delta_time", "flycam"] } +winit = "^0.21" +log = "0.4.0" +simplelog = "^0.10" +image = "0.23.2" +egui = "^0.12" +legion = { version = "^0.3" } +anyhow = "1.0.40" diff --git a/examples/render-quad/src/level.rs b/examples/render-quad/src/level.rs new file mode 100644 index 0000000..d10c3b6 --- /dev/null +++ b/examples/render-quad/src/level.rs @@ -0,0 +1,78 @@ +use stockton_levels::parts::{ + data::{FaceRef, Geometry, TextureRef}, + HasFaces, HasTextures, HasVisData, IsFace, IsTexture, +}; + +pub struct DemoLevel { + pub faces: Box<[Face]>, + pub textures: Box<[Texture]>, +} + +impl DemoLevel { + fn face_idx(&self, search: &Face) -> FaceRef { + for (idx, face) in self.faces.iter().enumerate() { + if face == search { + return idx as u32; + } + } + panic!("face not in level") + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct Face { + pub geometry: Geometry, + pub texture_idx: TextureRef, +} + +impl HasFaces for DemoLevel { + type Face = Face; + + fn get_face(&self, index: FaceRef) -> Option<&Self::Face> { + self.faces.get(index as usize) + } +} + +impl IsFace for Face { + fn index(&self, container: &DemoLevel) -> stockton_levels::parts::data::FaceRef { + container.face_idx(self) + } + + fn geometry(&self, _container: &DemoLevel) -> Geometry { + self.geometry.clone() + } + + fn texture_idx(&self, _container: &DemoLevel) -> TextureRef { + self.texture_idx + } +} + +pub struct Texture { + pub name: String, +} + +impl HasTextures for DemoLevel { + type Texture = Texture; + + fn get_texture(&self, idx: TextureRef) -> Option<&Self::Texture> { + self.textures.get(idx as usize) + } +} + +impl IsTexture for Texture { + fn name(&self) -> &str { + &self.name + } +} + +impl<'a> HasVisData<'a> for DemoLevel { + type Faces = std::ops::Range; + + fn get_visible( + &'a self, + _transform: &stockton_types::components::Transform, + _settings: &stockton_types::components::CameraSettings, + ) -> Self::Faces { + 0..self.faces.len() as u32 + } +} diff --git a/examples/render-quad/src/main.rs b/examples/render-quad/src/main.rs new file mode 100644 index 0000000..b16c3d0 --- /dev/null +++ b/examples/render-quad/src/main.rs @@ -0,0 +1,229 @@ +//! Renders ./example.bsp geometry: (), texture_idx: () geometry: (), texture_idx: () + +#[macro_use] +extern crate stockton_input_codegen; + +#[macro_use] +extern crate legion; + +use anyhow::{Context, Result}; +use log::warn; +use std::collections::BTreeMap; + +use std::sync::{Arc, RwLock}; +use stockton_levels::parts::data::{Geometry, Vertex}; +use stockton_levels::types::Rgba; +use stockton_render::draw::LevelDrawPass; +use winit::{event::Event, event_loop::EventLoop, window::WindowBuilder}; + +use egui::{containers::CentralPanel, Frame}; +use stockton_contrib::delta_time::*; +use stockton_contrib::flycam::*; + +use stockton_input::{Axis, InputManager, Mouse}; + +use stockton_render::error::full_error_display; +use stockton_render::systems::*; +use stockton_render::{Renderer, UiState, WindowEvent}; + +use stockton_types::components::{CameraSettings, CameraVPMatrix, Transform}; +use stockton_types::{Session, Vector2, Vector3}; + +mod level; +use level::*; + +type Dp<'a> = LevelDrawPass<'a, DemoLevel>; + +#[derive(InputManager, Default, Clone, Debug)] +struct MovementInputs { + #[axis] + x: Axis, + + #[axis] + y: Axis, + + #[axis] + z: Axis, +} + +impl FlycamInput for MovementInputs { + fn get_x_axis(&self) -> &Axis { + &self.x + } + fn get_y_axis(&self) -> &Axis { + &self.y + } + fn get_z_axis(&self) -> &Axis { + &self.z + } +} + +#[system] +fn hello_world(#[resource] ui: &mut UiState) { + CentralPanel::default() + .frame(Frame::none()) + .show(ui.ctx(), |ui| { + ui.heading("Hello, World!"); + }); +} + +fn main() { + if let Err(err) = try_main() { + eprintln!("{}", full_error_display(err)); + } +} + +fn try_main<'a>() -> Result<()> { + // Initialise logger + simplelog::TermLogger::init( + log::LevelFilter::Debug, + simplelog::ConfigBuilder::new() + .set_max_level(log::LevelFilter::Debug) + .set_thread_mode(simplelog::ThreadLogMode::Names) + .build(), + simplelog::TerminalMode::Stderr, + simplelog::ColorChoice::Auto, + ) + .context("Error initialising logger")?; + + // Make a window + let event_loop = EventLoop::new(); + let window = WindowBuilder::new() + .build(&event_loop) + .context("Error creating window")?; + + if window.set_cursor_grab(true).is_err() { + warn!("warning: cursor not grabbed"); + } + window.set_cursor_visible(false); + + // TODO: Parse the map file + let map = Arc::new(RwLock::new(DemoLevel { + faces: vec![Face { + geometry: Geometry::Vertices( + Vertex { + position: Vector3::new(-128.0, 128.0, 128.0), + tex: Vector2::new(0.0, 0.0), + color: Rgba::from_slice(&[0, 0, 0, 1]), + }, + Vertex { + position: Vector3::new(-128.0, -128.0, 128.0), + tex: Vector2::new(0.0, 1.0), + color: Rgba::from_slice(&[0, 0, 0, 1]), + }, + Vertex { + position: Vector3::new(128.0, 128.0, 128.0), + tex: Vector2::new(1.0, 0.0), + color: Rgba::from_slice(&[0, 0, 0, 1]), + }, + ), + texture_idx: 0, + }] + .into_boxed_slice(), + textures: vec![Texture { + name: "example_texture".to_string(), + }] + .into_boxed_slice(), + })); + + // Create the UI State + let mut ui = UiState::new(); + + // Create the input manager + let manager = { + use stockton_input::InputMutation::*; + use MovementInputsFields::*; + + let mut actions = BTreeMap::new(); + + actions.insert(17, (Z, PositiveAxis)); // W + actions.insert(30, (X, NegativeAxis)); // A + actions.insert(31, (Z, NegativeAxis)); // S + actions.insert(32, (X, PositiveAxis)); // D + actions.insert(29, (Y, NegativeAxis)); // Ctrl + actions.insert(57, (Y, PositiveAxis)); // Space + + MovementInputsManager::new(actions) + }; + + let ratio = window.inner_size().width as f32 / window.inner_size().height as f32; + + // Load everything into the session + let mut session = Session::new( + move |resources| { + resources.insert(map); + resources.insert(manager); + resources.insert(Timing::default()); + resources.insert(Mouse::default()); + }, + move |schedule| { + schedule + .add_system(update_deltatime_system()) + .add_system(process_window_events_system::< + MovementInputsManager, + Dp<'static>, + >()) + .flush() + .add_system(hello_world_system()) + .add_system(flycam_move_system::()) + .flush() + .add_thread_local(calc_vp_matrix_system(ratio)); + }, + ); + + // Add our player entity + let player = session.world.push(( + Transform { + position: Vector3::new(0.0, 0.0, 0.0), + rotation: Vector3::new(0.0, 0.0, 0.0), + }, + CameraSettings { + far: 1024.0, + fov: 90.0, + near: 0.1, + }, + CameraVPMatrix::default(), + FlycamControlled::new(512.0, 400.0), + )); + + // Create the renderer + let (renderer, tx): (Renderer>, _) = Renderer::new(&window, &session, player)?; + let new_control_flow = renderer.update_control_flow.clone(); + + // Populate the initial UI state + ui.populate_initial_state(&renderer); + + session.resources.insert(renderer); + session.resources.insert(ui); + + // Done loading - This is our main loop. + // It just communicates events to the session and continuously ticks + event_loop.run(move |event, _, flow| { + match event { + Event::MainEventsCleared => { + window.request_redraw(); + } + Event::RedrawRequested(_) => { + session.do_update(); + let mut renderer = session + .resources + .get_mut::>>() + .unwrap(); + renderer.render(&session).unwrap(); + } + _ => { + if let Some(we) = WindowEvent::from(&event) { + tx.send(we).unwrap() + } + } + } + + // Update the control flow if the session has requested it. + { + let new_control_flow = new_control_flow.read().unwrap(); + if *new_control_flow != *flow { + *flow = *new_control_flow; + } + }; + }); +} diff --git a/stockton-input-codegen/src/lib.rs b/stockton-input-codegen/src/lib.rs index 06d3ff2..89bbef5 100644 --- a/stockton-input-codegen/src/lib.rs +++ b/stockton-input-codegen/src/lib.rs @@ -29,13 +29,13 @@ pub fn derive_inputmanager(input: TokenStream) -> TokenStream { let fields_enum = gen_fields_enum(&fields_enum_ident, &caps_buttons, &caps_axes); let manager_struct = gen_manager_struct( &manager_ident, - &struct_ident, + struct_ident, &fields_enum_ident, buttons.len(), ); let trait_impl = gen_trait_impl( &manager_ident, - &struct_ident, + struct_ident, &fields_enum_ident, &buttons, &axes, @@ -233,9 +233,9 @@ fn gen_trait_impl( buttons_caps: &[Ident], axes_caps: &[Ident], ) -> TokenStream2 { - let just_hot_resets = gen_just_hot_resets(&buttons); + let just_hot_resets = gen_just_hot_resets(buttons); let field_match_modify = - gen_field_mutation(&buttons, &axes, &buttons_caps, &axes_caps, &fields_enum); + gen_field_mutation(buttons, axes, buttons_caps, axes_caps, fields_enum); quote!( impl InputManager for #manager { @@ -305,8 +305,8 @@ fn gen_field_mutation( ) -> TokenStream2 { let arms = { let mut btn_arms: Vec = - gen_mutate_match_arms_buttons(buttons, &buttons_caps, fields_enum_ident); - let mut axes_arms = gen_mutate_match_arms_axes(axes, &axes_caps, fields_enum_ident); + gen_mutate_match_arms_buttons(buttons, buttons_caps, fields_enum_ident); + let mut axes_arms = gen_mutate_match_arms_axes(axes, axes_caps, fields_enum_ident); btn_arms.append(&mut axes_arms); diff --git a/stockton-levels/Cargo.toml b/stockton-levels/Cargo.toml index 526b21c..b70268b 100644 --- a/stockton-levels/Cargo.toml +++ b/stockton-levels/Cargo.toml @@ -9,4 +9,5 @@ edition = "2018" [dependencies] nalgebra = "^0.20" -serde = { version = "1.0", features = ["derive"] } \ No newline at end of file +serde = { version = "1.0", features = ["derive"] } +stockton-types = { path = "../stockton-types" } diff --git a/stockton-levels/src/features.rs b/stockton-levels/src/features.rs index f748bd0..b4ddb99 100644 --- a/stockton-levels/src/features.rs +++ b/stockton-levels/src/features.rs @@ -14,5 +14,8 @@ use crate::parts::*; -pub trait MinRenderFeatures: HasFaces + HasTextures + Send + Sync {} -impl MinRenderFeatures for T where T: HasFaces + HasTextures + Send + Sync {} +pub trait MinRenderFeatures<'a>: HasFaces + HasTextures + HasVisData<'a> + Send + Sync {} +impl<'a, T> MinRenderFeatures<'a> for T where + T: HasFaces + HasTextures + HasVisData<'a> + Send + Sync +{ +} diff --git a/stockton-levels/src/parts/faces.rs b/stockton-levels/src/parts/faces.rs index 0168cd8..1023af7 100644 --- a/stockton-levels/src/parts/faces.rs +++ b/stockton-levels/src/parts/faces.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; pub type FaceRef = u32; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Geometry { Vertices(Vertex, Vertex, Vertex), } diff --git a/stockton-levels/src/parts/vertices.rs b/stockton-levels/src/parts/vertices.rs index 0b7dfd6..f2f5a2d 100644 --- a/stockton-levels/src/parts/vertices.rs +++ b/stockton-levels/src/parts/vertices.rs @@ -42,7 +42,7 @@ impl<'de> Deserialize<'de> for Vertex { TexV, Color, } - const FIELDS: &'static [&'static str] = + const FIELDS: &[&str] = &["pos_x", "pos_y", "pos_z", "tex_x", "tex_y", "color"]; struct VertexVisitor; diff --git a/stockton-levels/src/parts/visdata.rs b/stockton-levels/src/parts/visdata.rs index f311bf7..aa2ec3d 100644 --- a/stockton-levels/src/parts/visdata.rs +++ b/stockton-levels/src/parts/visdata.rs @@ -1,8 +1,8 @@ use super::faces::FaceRef; -use na::Vector3; use std::iter::Iterator; +use stockton_types::components::{CameraSettings, Transform}; -pub trait HasVisData { +pub trait HasVisData<'a> { type Faces: Iterator; - fn get_visible(pos: Vector3, rot: Vector3) -> Self::Faces; + fn get_visible(&'a self, transform: &Transform, settings: &CameraSettings) -> Self::Faces; } diff --git a/stockton-render/Cargo.toml b/stockton-render/Cargo.toml index 6777a66..7f93b3b 100644 --- a/stockton-render/Cargo.toml +++ b/stockton-render/Cargo.toml @@ -22,6 +22,7 @@ rendy-memory = { path = "../rendy-memory" } rendy-descriptor = { path = "../rendy-descriptor" } anyhow = "1.0.40" thiserror = "1.0.25" +derive_builder = "0.10.2" [features] default = ["vulkan"] diff --git a/stockton-render/src/draw/buffers/mod.rs b/stockton-render/src/draw/buffers/mod.rs index 5093872..dc7df65 100644 --- a/stockton-render/src/draw/buffers/mod.rs +++ b/stockton-render/src/draw/buffers/mod.rs @@ -11,9 +11,9 @@ use hal::{ MemoryTypeId, }; -mod dedicated_image; -mod draw_buffers; -mod staged; +pub mod dedicated_image; +pub mod draw_buffers; +pub mod staged; pub use dedicated_image::DedicatedLoadedImage; pub use draw_buffers::DrawBuffers; @@ -58,11 +58,6 @@ pub trait ModifiableBuffer: IndexMut { /// Get a handle to the underlying GPU buffer fn get_buffer(&mut self) -> &BufferT; - /// Commit all changes to GPU memory, returning a handle to the GPU buffer - fn commit<'a>( - &'a mut self, - device: &DeviceT, - command_queue: &mut QueueT, - command_pool: &mut CommandPoolT, - ) -> Result<&'a BufferT>; + /// Record the command(s) required to commit changes to this buffer to the given command buffer. + fn record_commit_cmds<'a>(&'a mut self, cmd_buffer: &mut CommandBufferT) -> Result<()>; } diff --git a/stockton-render/src/draw/buffers/staged.rs b/stockton-render/src/draw/buffers/staged.rs index f92c41d..71b5204 100644 --- a/stockton-render/src/draw/buffers/staged.rs +++ b/stockton-render/src/draw/buffers/staged.rs @@ -1,20 +1,19 @@ //! A buffer that can be written to by the CPU using staging memory use super::{create_buffer, ModifiableBuffer}; -use crate::{error::EnvironmentError, types::*}; +use crate::types::*; use core::mem::{size_of, ManuallyDrop}; use std::{ convert::TryInto, - iter::{empty, once}, ops::{Index, IndexMut}, }; use anyhow::{Context, Result}; use hal::{ buffer::Usage, - memory::{Properties, Segment, SparseFlags}, - MemoryTypeId, + command::BufferCopy, + memory::{Properties, Segment}, }; /// A GPU buffer that is written to using a staging buffer @@ -34,9 +33,6 @@ pub struct StagedBuffer<'a, T: Sized> { /// Where staged buffer is mapped in CPU memory staged_mapped_memory: &'a mut [T], - /// If staged memory has been changed since last `commit` - staged_is_dirty: bool, - /// The highest index in the buffer that's been written to. pub highest_used: usize, } @@ -88,7 +84,6 @@ impl<'a, T: Sized> StagedBuffer<'a, T> { buffer: ManuallyDrop::new(buffer), memory: ManuallyDrop::new(memory), staged_mapped_memory, - staged_is_dirty: false, highest_used: 0, }) } @@ -112,60 +107,20 @@ impl<'a, T: Sized> ModifiableBuffer for StagedBuffer<'a, T> { &self.buffer } - fn commit<'b>( - &'b mut self, - device: &DeviceT, - command_queue: &mut QueueT, - command_pool: &mut CommandPoolT, - ) -> Result<&'b BufferT> { - // Only commit if there's changes to commit. - if self.staged_is_dirty { - // Copy from staged to buffer - let buf = unsafe { - use hal::command::{BufferCopy, CommandBufferFlags}; - // Get a command buffer - let mut buf = command_pool.allocate_one(hal::command::Level::Primary); - - // Put in our copy command - buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT); - buf.copy_buffer( - &self.staged_buffer, - &self.buffer, - std::iter::once(BufferCopy { - src: 0, - dst: 0, - size: ((self.highest_used + 1) * size_of::()) as u64, - }), - ); - buf.finish(); - - buf - }; - - // Submit it and wait for completion - // TODO: Proper management of transfer operations - unsafe { - let mut copy_finished = device.create_fence(false)?; - command_queue.submit( - once(&buf), - empty::<(&SemaphoreT, hal::pso::PipelineStage)>(), - empty::<&SemaphoreT>(), - Some(&mut copy_finished), - ); - - device - .wait_for_fence(©_finished, core::u64::MAX) - .context("Error waiting for fence")?; - - // Destroy temporary resources - device.destroy_fence(copy_finished); - command_pool.free(once(buf)); - } - - self.staged_is_dirty = false; + fn record_commit_cmds(&mut self, buf: &mut CommandBufferT) -> Result<()> { + unsafe { + buf.copy_buffer( + &self.staged_buffer, + &self.buffer, + std::iter::once(BufferCopy { + src: 0, + dst: 0, + size: ((self.highest_used + 1) * size_of::()) as u64, + }), + ); } - Ok(&self.buffer) + Ok(()) } } @@ -179,7 +134,6 @@ impl<'a, T: Sized> Index for StagedBuffer<'a, T> { impl<'a, T: Sized> IndexMut for StagedBuffer<'a, T> { fn index_mut(&mut self, index: usize) -> &mut Self::Output { - self.staged_is_dirty = true; if index > self.highest_used { self.highest_used = index; } diff --git a/stockton-render/src/draw/builders/mod.rs b/stockton-render/src/draw/builders/mod.rs new file mode 100644 index 0000000..002c09f --- /dev/null +++ b/stockton-render/src/draw/builders/mod.rs @@ -0,0 +1,3 @@ +pub mod pipeline; +pub mod renderpass; +pub mod shader; diff --git a/stockton-render/src/draw/builders/pipeline.rs b/stockton-render/src/draw/builders/pipeline.rs new file mode 100644 index 0000000..cdd9736 --- /dev/null +++ b/stockton-render/src/draw/builders/pipeline.rs @@ -0,0 +1,276 @@ +use super::{renderpass::RenderpassSpec, shader::ShaderDesc}; +use crate::{draw::target::SwapchainProperties, error::EnvironmentError, types::*}; + +use std::{mem::ManuallyDrop, ops::Range}; + +use anyhow::{Context, Result}; +use hal::{ + format::Format, + pso::{ + AttributeDesc, BakedStates, BasePipeline, BlendDesc, BufferIndex, DepthStencilDesc, + ElemStride, Element, GraphicsPipelineDesc, InputAssemblerDesc, PipelineCreationFlags, + PrimitiveAssemblerDesc, Rasterizer, Rect, ShaderStageFlags, VertexBufferDesc, + VertexInputRate, Viewport, + }, +}; +use shaderc::Compiler; + +pub struct VertexBufferSpec { + pub attributes: Vec, + pub rate: VertexInputRate, +} + +impl VertexBufferSpec { + pub fn as_attribute_desc(&self, binding: BufferIndex) -> Vec { + let mut v = Vec::with_capacity(self.attributes.len()); + let mut offset = 0; + for (idx, format) in self.attributes.iter().enumerate() { + v.push(AttributeDesc { + location: idx as u32, + binding, + element: Element { + offset, + format: *format, + }, + }); + offset += get_size(*format); + } + + v + } + pub fn stride(&self) -> ElemStride { + self.attributes.iter().fold(0, |x, f| x + get_size(*f)) + } +} + +fn get_size(f: Format) -> u32 { + match f { + Format::Rgb32Sfloat => 4 * 3, + Format::R32Sint => 4, + Format::Rg32Sfloat => 4 * 2, + _ => unimplemented!("dont know size of format {:?}", f), + } +} + +#[derive(Debug, Clone)] +pub struct VertexPrimitiveAssemblerSpec { + buffers: Vec, + attributes: Vec, + input_assembler: InputAssemblerDesc, +} + +impl VertexPrimitiveAssemblerSpec { + pub fn with_buffer(&mut self, bd: VertexBufferSpec) -> &mut Self { + let idx = self.buffers.len() as u32; + self.buffers.push(VertexBufferDesc { + binding: idx, + stride: bd.stride(), + rate: bd.rate, + }); + + self.attributes.extend(bd.as_attribute_desc(idx)); + + self + } + + pub fn with_buffers(iad: InputAssemblerDesc, mut bds: Vec) -> Self { + let mut this = VertexPrimitiveAssemblerSpec { + buffers: vec![], + attributes: vec![], + input_assembler: iad, + }; + + for bd in bds.drain(..) { + this.with_buffer(bd); + } + + this + } +} + +#[derive(Builder, Debug)] +#[builder(public)] +pub struct PipelineSpec { + rasterizer: Rasterizer, + depth_stencil: DepthStencilDesc, + blender: BlendDesc, + primitive_assembler: VertexPrimitiveAssemblerSpec, + + shader_vertex: ShaderDesc, + #[builder(setter(strip_option))] + shader_fragment: Option, + #[builder(setter(strip_option), default)] + shader_geom: Option, + #[builder(setter(strip_option), default)] + shader_tesselation: Option<(ShaderDesc, ShaderDesc)>, + + push_constants: Vec<(ShaderStageFlags, Range)>, + + renderpass: RenderpassSpec, +} + +impl PipelineSpec { + pub fn build<'b, T: Iterator + std::fmt::Debug>( + self, + device: &mut DeviceT, + extent: hal::image::Extent, + _swapchain_properties: &SwapchainProperties, + set_layouts: T, + ) -> Result { + // Renderpass + let renderpass = self.renderpass.build_renderpass(device)?; + + // Subpass + let subpass = hal::pass::Subpass { + index: 0, + main_pass: &renderpass, + }; + + let mut compiler = Compiler::new().ok_or(EnvironmentError::NoShaderC)?; + let (vs_module, fs_module, gm_module, ts_module) = { + ( + self.shader_vertex.compile(&mut compiler, device)?, + self.shader_fragment + .as_ref() + .map(|x| x.compile(&mut compiler, device)) + .transpose()?, + self.shader_geom + .as_ref() + .map(|x| x.compile(&mut compiler, device)) + .transpose()?, + self.shader_tesselation + .as_ref() + .map::, _>(|(a, b)| { + Ok(( + a.compile(&mut compiler, device)?, + b.compile(&mut compiler, device)?, + )) + }) + .transpose()?, + ) + }; + + // Safety: *_module is always populated when shader_* is, so this is safe + let (vs_entry, fs_entry, gm_entry, ts_entry) = ( + self.shader_vertex.as_entry(&vs_module), + self.shader_fragment + .as_ref() + .map(|x| x.as_entry(fs_module.as_ref().unwrap())), + self.shader_geom + .as_ref() + .map(|x| x.as_entry(gm_module.as_ref().unwrap())), + self.shader_tesselation.as_ref().map(|(a, b)| { + ( + a.as_entry(&ts_module.as_ref().unwrap().0), + b.as_entry(&ts_module.as_ref().unwrap().1), + ) + }), + ); + + // Pipeline layout + let layout = unsafe { + device.create_pipeline_layout(set_layouts.into_iter(), self.push_constants.into_iter()) + } + .context("Error creating pipeline layout")?; + + // Baked states + let baked_states = BakedStates { + viewport: Some(Viewport { + rect: extent.rect(), + depth: (0.0..1.0), + }), + scissor: Some(extent.rect()), + blend_constants: None, + depth_bounds: None, + }; + + // Primitive assembler + let primitive_assembler = PrimitiveAssemblerDesc::Vertex { + buffers: self.primitive_assembler.buffers.as_slice(), + attributes: self.primitive_assembler.attributes.as_slice(), + input_assembler: self.primitive_assembler.input_assembler, + vertex: vs_entry, + tessellation: ts_entry, + geometry: gm_entry, + }; + + // Pipeline description + let pipeline_desc = GraphicsPipelineDesc { + label: Some("stockton"), + rasterizer: self.rasterizer, + fragment: fs_entry, + blender: self.blender, + depth_stencil: self.depth_stencil, + multisampling: None, + baked_states, + layout: &layout, + subpass, + flags: PipelineCreationFlags::empty(), + parent: BasePipeline::None, + primitive_assembler, + }; + + // Pipeline + let pipeline = unsafe { device.create_graphics_pipeline(&pipeline_desc, None) } + .context("Error creating graphics pipeline")?; + + Ok(CompletePipeline { + renderpass: ManuallyDrop::new(renderpass), + pipeline_layout: ManuallyDrop::new(layout), + pipeline: ManuallyDrop::new(pipeline), + vs_module: ManuallyDrop::new(vs_module), + fs_module, + gm_module, + ts_module, + render_area: extent.rect(), + }) + } +} + +pub struct CompletePipeline { + /// Our main render pass + pub(crate) renderpass: ManuallyDrop, + + /// The layout of our main graphics pipeline + pub(crate) pipeline_layout: ManuallyDrop, + + /// Our main graphics pipeline + pub(crate) pipeline: ManuallyDrop, + + /// The vertex shader module + pub(crate) vs_module: ManuallyDrop, + + /// The fragment shader module + pub(crate) fs_module: Option, + pub(crate) gm_module: Option, + pub(crate) ts_module: Option<(ShaderModuleT, ShaderModuleT)>, + + pub(crate) render_area: Rect, +} + +impl CompletePipeline { + /// Deactivate vulkan resources. Use before dropping + pub fn deactivate(mut self, device: &mut DeviceT) { + unsafe { + use core::ptr::read; + + device.destroy_render_pass(ManuallyDrop::into_inner(read(&self.renderpass))); + + device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module))); + if let Some(x) = self.fs_module.take() { + device.destroy_shader_module(x) + } + if let Some(x) = self.gm_module.take() { + device.destroy_shader_module(x) + } + self.ts_module.take().map(|(a, b)| { + device.destroy_shader_module(a); + device.destroy_shader_module(b); + }); + + device.destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline))); + + device.destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout))); + } + } +} diff --git a/stockton-render/src/draw/builders/renderpass.rs b/stockton-render/src/draw/builders/renderpass.rs new file mode 100644 index 0000000..43f0eb2 --- /dev/null +++ b/stockton-render/src/draw/builders/renderpass.rs @@ -0,0 +1,75 @@ +use crate::types::*; + +use std::iter::{empty, once}; + +use anyhow::Result; +use hal::pass::{Attachment, AttachmentRef, SubpassDesc}; + +#[derive(Debug, Clone)] +pub struct RenderpassSpec { + pub colors: Vec, + pub depth: Option, + pub inputs: Vec, + pub resolves: Vec, + pub preserves: Vec, +} + +impl RenderpassSpec { + pub fn build_renderpass(self, device: &mut DeviceT) -> Result { + let mut next_offset = 0; + + let colors: Vec = self + .colors + .iter() + .enumerate() + .map(|(i, a)| (next_offset + i, a.layouts.end)) + .collect(); + next_offset = colors.len(); + + let depth_stencil = self.depth.as_ref().map(|x| (next_offset, x.layouts.end)); + if depth_stencil.is_some() { + next_offset += 1; + } + + let inputs: Vec = self + .inputs + .iter() + .enumerate() + .map(|(i, a)| (next_offset + i, a.layouts.end)) + .collect(); + next_offset += inputs.len(); + + let resolves: Vec = self + .resolves + .iter() + .enumerate() + .map(|(i, a)| (next_offset + i, a.layouts.end)) + .collect(); + next_offset += resolves.len(); + + let preserves: Vec = self + .preserves + .iter() + .enumerate() + .map(|(i, _a)| next_offset + i) + .collect(); + + let sp_desc = SubpassDesc { + colors: colors.as_slice(), + depth_stencil: depth_stencil.as_ref(), + inputs: inputs.as_slice(), + resolves: resolves.as_slice(), + preserves: preserves.as_slice(), + }; + + let all_attachments = self + .colors + .into_iter() + .chain(self.depth.into_iter()) + .chain(self.inputs.into_iter()) + .chain(self.resolves.into_iter()) + .chain(self.preserves.into_iter()); + + Ok(unsafe { device.create_render_pass(all_attachments, once(sp_desc), empty())? }) + } +} diff --git a/stockton-render/src/draw/builders/shader.rs b/stockton-render/src/draw/builders/shader.rs new file mode 100644 index 0000000..fde185d --- /dev/null +++ b/stockton-render/src/draw/builders/shader.rs @@ -0,0 +1,35 @@ +use crate::types::*; + +use anyhow::{Context, Result}; +use hal::pso::Specialization; +use shaderc::{Compiler, ShaderKind}; + +#[derive(Debug, Clone)] +pub struct ShaderDesc { + pub source: String, + pub entry: String, + pub kind: ShaderKind, +} + +impl ShaderDesc { + pub fn compile(&self, compiler: &mut Compiler, device: &mut DeviceT) -> Result { + let artifact = compiler + .compile_into_spirv(&self.source, self.kind, "shader", &self.entry, None) + .context("Shader compilation failed")?; + + // Make into shader module + Ok(unsafe { + device + .create_shader_module(artifact.as_binary()) + .context("Shader module creation failed")? + }) + } + + pub fn as_entry<'a>(&'a self, module: &'a ShaderModuleT) -> EntryPoint<'a> { + EntryPoint { + entry: &self.entry, + module, + specialization: Specialization::default(), + } + } +} diff --git a/stockton-render/src/draw/camera.rs b/stockton-render/src/draw/camera.rs index 421b661..495e6a2 100644 --- a/stockton-render/src/draw/camera.rs +++ b/stockton-render/src/draw/camera.rs @@ -1,14 +1,15 @@ //! Things related to converting 3D world space to 2D screen space use legion::maybe_changed; +use na::{look_at_lh, perspective_lh_zo}; +use stockton_types::{ + components::{CameraSettings, CameraVPMatrix, Transform}, + Vector3, +}; + + -use nalgebra_glm::look_at_lh; -use nalgebra_glm::perspective_lh_zo; -use stockton_levels::prelude::MinRenderFeatures; -use crate::Renderer; -use stockton_types::components::{CameraSettings, Transform}; -use stockton_types::Vector3; fn euler_to_direction(euler: &Vector3) -> Vector3 { let pitch = euler.x; @@ -22,35 +23,34 @@ fn euler_to_direction(euler: &Vector3) -> Vector3 { ) } -// #[system(for_each)] -// #[filter(maybe_changed::() | maybe_changed::())] -// pub fn calc_vp_matrix( -// transform: &Transform, -// settings: &CameraSettings, -// #[resource] renderer: &mut Renderer, -// ) { -// let ratio = renderer.context.target_chain.properties.extent.width as f32 -// / renderer.context.target_chain.properties.extent.height as f32; -// // Get look direction from euler angles -// let direction = euler_to_direction(&transform.rotation); - -// // Converts world space to camera space -// let view_matrix = look_at_lh( -// &transform.position, -// &(transform.position + direction), -// &Vector3::new(0.0, 1.0, 0.0), -// ); - -// // Converts camera space to screen space -// let projection_matrix = { -// let mut temp = perspective_lh_zo(ratio, settings.fov, settings.near, settings.far); - -// // Vulkan's co-ord system is different from OpenGLs -// temp[(1, 1)] *= -1.0; - -// temp -// }; - -// // Chain them together into a single matrix -// renderer.context.vp_matrix = projection_matrix * view_matrix -// } +#[system(for_each)] +#[filter(maybe_changed::() | maybe_changed::())] +pub fn calc_vp_matrix( + transform: &Transform, + settings: &CameraSettings, + matrix: &mut CameraVPMatrix, + #[state] ratio: &mut f32, +) { + // Get look direction from euler angles + let direction = euler_to_direction(&transform.rotation); + + // Converts world space to camera space + let view_matrix = look_at_lh( + &transform.position, + &(transform.position + direction), + &Vector3::new(0.0, 1.0, 0.0), + ); + + // Converts camera space to screen space + let projection_matrix = { + let mut temp = perspective_lh_zo(*ratio, settings.fov, settings.near, settings.far); + + // Vulkan's co-ord system is different from OpenGLs + temp[(1, 1)] *= -1.0; + + temp + }; + + // Chain them together into a single matrix + matrix.vp_matrix = projection_matrix * view_matrix; +} diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs index 1a690fe..65dcff6 100644 --- a/stockton-render/src/draw/context.rs +++ b/stockton-render/src/draw/context.rs @@ -10,20 +10,19 @@ use std::{ use anyhow::{Context, Result}; use hal::pool::CommandPoolCreateFlags; use log::debug; -use na::Mat4; + use winit::window::Window; use super::{ - draw_passes::{DrawPass, IntoDrawPass, LevelDrawPass}, + draw_passes::{DrawPass, IntoDrawPass}, queue_negotiator::{DrawQueue, QueueNegotiator}, target::{SwapchainProperties, TargetChain}, }; use crate::{ error::{EnvironmentError, LockPoisoned}, types::*, - window::UiState, }; -use stockton_levels::prelude::*; + use stockton_types::Session; /// Contains all the hal related stuff. @@ -53,17 +52,15 @@ pub struct RenderingContext { /// Deals with drawing logic, and holds any data required for drawing. draw_pass: ManuallyDrop, - /// View projection matrix - pub(crate) vp_matrix: Mat4, - pub(crate) pixels_per_point: f32, } impl RenderingContext { /// Create a new RenderingContext for the given window. - pub fn new>( + pub fn new>( window: &Window, - idp: ILDP, + session: &Session, + idp: IDP, ) -> Result { // Create surface let (instance, surface, mut adapters) = unsafe { @@ -97,7 +94,7 @@ impl RenderingContext { // Auxiliary queues for DP queue_families_specs.extend( - DP::find_aux_queues(&adapter, &mut qn) + IDP::find_aux_queues(&adapter, &mut qn) .context("Level pass couldn't populate queue negotiator")?, ); @@ -105,7 +102,7 @@ impl RenderingContext { }; // Device & Queue groups - let (device_lock, mut queue_groups) = { + let (device_lock, queue_groups) = { // TODO: This sucks, but hal is restrictive on how we can pass this specific argument. let queue_families_specs_real: Vec<_> = queue_families_specs .iter() @@ -122,16 +119,22 @@ impl RenderingContext { (Arc::new(RwLock::new(gpu.device)), gpu.queue_groups) }; + queue_negotiator.set_queue_groups(queue_groups); + // Figure out what our swapchain will look like let swapchain_properties = SwapchainProperties::find_best(&adapter, &surface) .context("Error getting properties for swapchain")?; // Draw pass - let dp = idp.init( - device_lock.clone(), - &mut queue_negotiator, - &swapchain_properties, - )?; + let dp = idp + .init( + session, + &adapter, + device_lock.clone(), + &mut queue_negotiator, + &swapchain_properties, + ) + .context("Error initialising draw pass")?; // Lock device let mut device = device_lock @@ -172,7 +175,7 @@ impl RenderingContext { adapter, queue: queue_negotiator - .get_queue::(&mut queue_groups) + .get_queue::() .ok_or(EnvironmentError::NoQueues) .context("Error getting draw queue")?, @@ -180,8 +183,6 @@ impl RenderingContext { target_chain: ManuallyDrop::new(target_chain), cmd_pool: ManuallyDrop::new(cmd_pool), - vp_matrix: Mat4::identity(), - // pixels_per_point: window.scale_factor() as f32, pixels_per_point: window.scale_factor() as f32, }) @@ -237,7 +238,7 @@ impl RenderingContext { // Level draw pass self.target_chain - .do_draw_with(&mut device, &mut queue, &*self.draw_pass, session) + .do_draw_with(&mut device, &mut queue, &mut *self.draw_pass, session) .context("Error preparing next target")?; Ok(()) diff --git a/stockton-render/src/draw/draw_passes/cons.rs b/stockton-render/src/draw/draw_passes/cons.rs index 76e2f32..8f912ec 100644 --- a/stockton-render/src/draw/draw_passes/cons.rs +++ b/stockton-render/src/draw/draw_passes/cons.rs @@ -1,8 +1,10 @@ //! Code for using multiple draw passes in place of just one //! Note that this can be extended to an arbitrary amount of draw passes. +use std::sync::{Arc, RwLock}; + use super::DrawPass; -use crate::{draw::queue_negotiator::QueueNegotiator, types::*}; +use crate::types::*; use stockton_types::Session; use anyhow::Result; @@ -14,23 +16,21 @@ pub struct ConsDrawPass { } impl DrawPass for ConsDrawPass { - fn queue_draw(&self, session: &Session, cmd_buffer: &mut CommandBufferT) -> Result<()> { - self.a.queue_draw(&session, cmd_buffer)?; - self.b.queue_draw(&session, cmd_buffer)?; + fn queue_draw( + &mut self, + session: &Session, + img_view: &ImageViewT, + cmd_buffer: &mut CommandBufferT, + ) -> Result<()> { + self.a.queue_draw(session, img_view, cmd_buffer)?; + self.b.queue_draw(session, img_view, cmd_buffer)?; Ok(()) } - fn find_aux_queues<'a>( - adapter: &'a Adapter, - queue_negotiator: &mut QueueNegotiator, - ) -> Result)>> { - let mut vec = Vec::new(); - - vec.extend(A::find_aux_queues(adapter, queue_negotiator)?); - vec.extend(B::find_aux_queues(adapter, queue_negotiator)?); - - Ok(vec) + fn deactivate(self, device: &mut Arc>) -> Result<()> { + self.a.deactivate(device)?; + self.b.deactivate(device) } } @@ -38,15 +38,16 @@ impl DrawPass for ConsDrawPass { pub struct NilDrawPass; impl DrawPass for NilDrawPass { - - fn queue_draw(&self, _input: &Session, _cmd_buffer: &mut CommandBufferT) -> Result<()> { + fn queue_draw( + &mut self, + _input: &Session, + _img_view: &ImageViewT, + _cmd_buffer: &mut CommandBufferT, + ) -> Result<()> { Ok(()) } - fn find_aux_queues<'a>( - _adapter: &'a Adapter, - _queue_negotiator: &mut QueueNegotiator, - ) -> Result)>> { - Ok(vec![]) + fn deactivate(self, _device: &mut Arc>) -> Result<()> { + Ok(()) } -} \ No newline at end of file +} diff --git a/stockton-render/src/draw/draw_passes/level.rs b/stockton-render/src/draw/draw_passes/level.rs index b968a1a..3a4e748 100644 --- a/stockton-render/src/draw/draw_passes/level.rs +++ b/stockton-render/src/draw/draw_passes/level.rs @@ -2,18 +2,57 @@ use super::{DrawPass, IntoDrawPass}; use crate::{ - draw::{queue_negotiator::QueueNegotiator, target::SwapchainProperties, texture::TextureRepo}, - error::EnvironmentError, + draw::{ + buffers::{ + draw_buffers::{DrawBuffers, INITIAL_INDEX_SIZE, INITIAL_VERT_SIZE}, + DedicatedLoadedImage, ModifiableBuffer, + }, + builders::{ + pipeline::{ + CompletePipeline, PipelineSpecBuilder, VertexBufferSpec, + VertexPrimitiveAssemblerSpec, + }, + renderpass::RenderpassSpec, + shader::ShaderDesc, + }, + queue_negotiator::QueueNegotiator, + target::SwapchainProperties, + texture::{resolver::FsResolver, TexLoadQueue, TextureLoadConfig, TextureRepo}, + }, + error::{EnvironmentError, LevelError, LockPoisoned}, types::*, }; -use stockton_levels::features::MinRenderFeatures; -use stockton_types::*; +use hal::{ + buffer::SubRange, + command::{ClearColor, ClearDepthStencil, ClearValue, RenderAttachmentInfo, SubpassContents}, + format::{Aspects, Format}, + image::{ + Filter, FramebufferAttachment, Layout, SubresourceRange, Usage, ViewCapabilities, WrapMode, + }, + pass::{Attachment, AttachmentLoadOp, AttachmentOps, AttachmentStoreOp}, + pso::{ + BlendDesc, BlendOp, BlendState, ColorBlendDesc, ColorMask, Comparison, DepthStencilDesc, + DepthTest, Face, Factor, FrontFace, InputAssemblerDesc, LogicOp, PolygonMode, Primitive, + Rasterizer, ShaderStageFlags, State, VertexInputRate, + }, +}; +use legion::{Entity, IntoQuery}; +use shaderc::ShaderKind; +use stockton_levels::{ + features::MinRenderFeatures, + parts::{data::Geometry, IsFace}, +}; +use stockton_types::{ + components::{CameraSettings, CameraVPMatrix, Transform}, + *, +}; use std::{ array::IntoIter, + convert::TryInto, iter::{empty, once}, marker::PhantomData, - mem::{size_of, ManuallyDrop}, + path::Path, sync::{Arc, RwLock}, }; @@ -24,435 +63,398 @@ use anyhow::{Context, Result}; struct UvPoint(pub Vector3, pub i32, pub Vector2); /// Draw a level -pub struct LevelDrawPass { +pub struct LevelDrawPass<'a, M> { pipeline: CompletePipeline, repo: TextureRepo, + active_camera: Entity, + draw_buffers: DrawBuffers<'a, UvPoint>, + + framebuffers: Vec, + depth_buffers: Vec, + next_resources: usize, + _d: PhantomData, } -impl DrawPass for LevelDrawPass { +impl<'a, M> DrawPass for LevelDrawPass<'a, M> +where + M: for<'b> MinRenderFeatures<'b> + 'static, +{ fn queue_draw( - &self, - _input: &Session, - _cmd_buffer: &mut crate::types::CommandBufferT, + &mut self, + session: &Session, + img_view: &ImageViewT, + cmd_buffer: &mut crate::types::CommandBufferT, ) -> anyhow::Result<()> { - todo!() - // // Get visible faces - // // let faces = get_visible_faces( - // // pos, - // // &*self - // // .context - // // .map - // // .read() - // // .map_err(|_| LockPoisoned::Map) - // // .context("Error getting read lock on map")?, - // // ); - // let faces: Vec = { - // let map = &*self - // .context - // .map - // .read() - // .map_err(|_| LockPoisoned::Map) - // .context("Error getting read lock on map")?; - - // map.iter_faces().map(|x| x.index(map)).collect() - // }; - - // // Iterate over faces, copying them in and drawing groups that use the same texture chunk all at once. - // let mut current_chunk = file - // .get_face(0) - // .ok_or(LevelError::BadReference)? - // .texture_idx(file) as usize - // / 8; - // let mut chunk_start = 0; - - // let mut curr_vert_idx: usize = 0; - // let mut curr_idx_idx: usize = 0; - - // for face in faces.iter().map(|idx| file.get_face(*idx)) { - // if let Some(face) = face { - // if current_chunk != face.texture_idx(file) as usize / 8 { - // // Last index was last of group, so draw it all if textures are loaded. - // draw_or_queue( - // current_chunk, - // self.tex_repo, - // cmd_buffer, - // self.pipeline.pipeline_layout, - // chunk_start as u32, - // curr_idx_idx as u32, - // )?; - - // // Next group of same-chunked faces starts here. - // chunk_start = curr_idx_idx; - // current_chunk = face.texture_idx(file) as usize / 8; - // } - - // match face.geometry(file) { - // Geometry::Vertices(v1, v2, v3) => { - // for v in [v1, v2, v3] { - // let uvp = - // UvPoint(v.position, face.texture_idx(file).try_into()?, v.tex); - - // draw_buffers.vertex_buffer[curr_vert_idx] = uvp; - // curr_vert_idx += 1; - // } - // draw_buffers.index_buffer[curr_idx_idx] = ( - // curr_vert_idx as u16 - 2, - // curr_vert_idx as u16 - 1, - // curr_vert_idx as u16, - // ); - // curr_idx_idx += 1; - // } - // } - - // if curr_vert_idx >= INITIAL_VERT_SIZE.try_into()? - // || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into()? - // { - // println!("out of vertex buffer space!"); - // break; - // } - // } else { - // anyhow::bail!(LevelError::BadReference); - // } - // } - - // // Draw the final group of chunks - // draw_or_queue( - // current_chunk, - // self.tex_repo, - // cmd_buffer, - // self.pipeline.pipeline_layout, - // chunk_start as u32, - // curr_idx_idx as u32, - // )?; - - // Ok(()) - } - - fn find_aux_queues<'a>( - _adapter: &'a Adapter, - _queue_negotiator: &mut QueueNegotiator, - ) -> Result)>> { - todo!() - // queue_negotiator.find(TexLoadQueue) - } -} - -impl IntoDrawPass> for () { - fn init( - self, - _device_lock: Arc>, - _queue_negotiator: &mut QueueNegotiator, - _swapchain_properties: &SwapchainProperties, - ) -> Result> { - todo!() - // let repo = TextureRepo::new( - // device_lock.clone(), - // queue_negotiator - // .family() - // .ok_or(EnvironmentError::NoQueues)?, - // ); - // let pipeline = { - // let device = device_lock.write().or(Err(LockPoisoned::Device))?; - // CompletePipeline::new( - // device, - // swapchain_properties.extent, - // swapchain_properties, - // std::iter::empty(), - // )? - // }; - // Ok(LevelDrawPass { - // pipeline, - // repo, - // _d: PhantomData, - // }) - } -} - -/// Entry point name for shaders -const ENTRY_NAME: &str = "main"; - -/// Source for vertex shader. TODO -const VERTEX_SOURCE: &str = include_str!("../data/stockton.vert"); + // We might have loaded more textures + self.repo.process_responses(); + + // Make sure we update the vertex buffers after they're written to, but before they're read from. + self.draw_buffers + .vertex_buffer + .record_commit_cmds(cmd_buffer)?; + self.draw_buffers + .index_buffer + .record_commit_cmds(cmd_buffer)?; + + // Get level & camera + let mut query = <(&Transform, &CameraSettings, &CameraVPMatrix)>::query(); + let (camera_transform, camera_settings, camera_vp) = query + .get(&session.world, self.active_camera) + .context("Couldn't find camera components")?; + let map_lock: Arc> = session.resources.get::>>().unwrap().clone(); + let map = map_lock.read().map_err(|_| LockPoisoned::Map)?; + + // Get framebuffer and depth buffer + let fb = &self.framebuffers[self.next_resources]; + let db = &self.depth_buffers[self.next_resources]; + self.next_resources = (self.next_resources + 1) % self.framebuffers.len(); -/// Source for fragment shader. TODO -const FRAGMENT_SOURCE: &str = include_str!("../data/stockton.frag"); - -/// A complete graphics pipeline and associated resources -pub struct CompletePipeline { - /// Our main render pass - pub(crate) renderpass: ManuallyDrop, - - /// The layout of our main graphics pipeline - pub(crate) pipeline_layout: ManuallyDrop, - - /// Our main graphics pipeline - pub(crate) pipeline: ManuallyDrop, - - /// The vertex shader module - pub(crate) vs_module: ManuallyDrop, + unsafe { + cmd_buffer.begin_render_pass( + &self.pipeline.renderpass, + fb, + self.pipeline.render_area, + vec![ + RenderAttachmentInfo { + image_view: img_view, + clear_value: ClearValue { + color: ClearColor { + float32: [0.0, 0.0, 0.0, 1.0], + }, + }, + }, + RenderAttachmentInfo { + image_view: &*db.image_view, + clear_value: ClearValue { + depth_stencil: ClearDepthStencil { + depth: 1.0, + stencil: 0, + }, + }, + }, + ] + .into_iter(), + SubpassContents::Inline, + ); + cmd_buffer.bind_graphics_pipeline(&self.pipeline.pipeline); + + // VP Matrix + let vp = &*(camera_vp.vp_matrix.data.as_slice() as *const [f32] as *const [u32]); + + cmd_buffer.push_graphics_constants( + &self.pipeline.pipeline_layout, + ShaderStageFlags::VERTEX, + 0, + vp, + ); + + // Bind buffers + cmd_buffer.bind_vertex_buffers( + 0, + once(( + self.draw_buffers.vertex_buffer.get_buffer(), + SubRange { + offset: 0, + size: None, + }, + )), + ); + cmd_buffer.bind_index_buffer( + self.draw_buffers.index_buffer.get_buffer(), + SubRange { + offset: 0, + size: None, + }, + hal::IndexType::U16, + ); + } - /// The fragment shader module - pub(crate) fs_module: ManuallyDrop, -} + // Get visible faces + let mut faces = map.get_visible(camera_transform, camera_settings); + + // Iterate over faces, copying them in and drawing groups that use the same texture chunk all at once. + let face = faces.next(); + if let Some(face) = face { + let mut face = map.get_face(face).ok_or(LevelError::BadReference)?; + let mut current_chunk = face.texture_idx(&map) as usize / 8; + let mut chunk_start = 0; + + let mut curr_vert_idx: usize = 0; + let mut curr_idx_idx: usize = 0; + loop { + if current_chunk != face.texture_idx(&map) as usize / 8 { + // Last index was last of group, so draw it all if textures are loaded. + draw_or_queue( + current_chunk, + &mut self.repo, + cmd_buffer, + &*self.pipeline.pipeline_layout, + chunk_start as u32, + curr_idx_idx as u32, + )?; + + // Next group of same-chunked faces starts here. + chunk_start = curr_idx_idx; + current_chunk = face.texture_idx(&map) as usize / 8; + } + + match face.geometry(&map) { + Geometry::Vertices(v1, v2, v3) => { + for v in [v1, v2, v3] { + let uvp = + UvPoint(v.position, face.texture_idx(&map).try_into()?, v.tex); + + self.draw_buffers.vertex_buffer[curr_vert_idx] = uvp; + curr_vert_idx += 1; + } + self.draw_buffers.index_buffer[curr_idx_idx] = ( + curr_vert_idx as u16 - 3, + curr_vert_idx as u16 - 2, + curr_vert_idx as u16 - 1, + ); + curr_idx_idx += 1; + } + } + + if curr_vert_idx >= INITIAL_VERT_SIZE.try_into()? + || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into()? + { + println!("out of vertex buffer space!"); + break; + } + + match faces.next() { + Some(x) => face = map.get_face(x).ok_or(LevelError::BadReference)?, + None => break, + }; + } -impl CompletePipeline { - pub fn new<'a, T: Iterator + std::fmt::Debug>( - device: &mut DeviceT, - extent: hal::image::Extent, - swapchain_properties: &SwapchainProperties, - set_layouts: T, - ) -> Result { - use hal::format::Format; - use hal::pso::*; - - // Renderpass - let renderpass = { - use hal::{image::Layout, pass::*}; - - let img_attachment = Attachment { - format: Some(swapchain_properties.format), - samples: 1, - ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::Store), - stencil_ops: AttachmentOps::new( - AttachmentLoadOp::Clear, - AttachmentStoreOp::DontCare, - ), - layouts: Layout::Undefined..Layout::ColorAttachmentOptimal, - }; + // Draw the final group of chunks + draw_or_queue( + current_chunk, + &mut self.repo, + cmd_buffer, + &*self.pipeline.pipeline_layout, + chunk_start as u32, + curr_idx_idx as u32, + )?; + } - let depth_attachment = Attachment { - format: Some(swapchain_properties.depth_format), - samples: 1, - ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::DontCare), - stencil_ops: AttachmentOps::new( - AttachmentLoadOp::DontCare, - AttachmentStoreOp::DontCare, - ), - layouts: Layout::Undefined..Layout::DepthStencilAttachmentOptimal, - }; + unsafe { + cmd_buffer.end_render_pass(); + } - let subpass = SubpassDesc { - colors: &[(0, Layout::ColorAttachmentOptimal)], - depth_stencil: Some(&(1, Layout::DepthStencilAttachmentOptimal)), - inputs: &[], - resolves: &[], - preserves: &[], - }; + Ok(()) + } - unsafe { - device.create_render_pass( - IntoIter::new([img_attachment, depth_attachment]), - once(subpass), - empty(), - ) + fn deactivate(self, device_lock: &mut Arc>) -> Result<()> { + unsafe { + let mut device = device_lock.write().map_err(|_| LockPoisoned::Device)?; + self.pipeline.deactivate(&mut device); + self.draw_buffers.deactivate(&mut device); + for fb in self.framebuffers.into_iter() { + device.destroy_framebuffer(fb); } - .context("Error creating render pass")? - }; - - // Subpass - let subpass = hal::pass::Subpass { - index: 0, - main_pass: &renderpass, - }; - - // Shader modules - let (vs_module, fs_module) = { - let mut compiler = shaderc::Compiler::new().ok_or(EnvironmentError::NoShaderC)?; - - let vertex_compile_artifact = compiler - .compile_into_spirv( - VERTEX_SOURCE, - shaderc::ShaderKind::Vertex, - "vertex.vert", - ENTRY_NAME, - None, - ) - .context("Error compiling vertex shader")?; - - let fragment_compile_artifact = compiler - .compile_into_spirv( - FRAGMENT_SOURCE, - shaderc::ShaderKind::Fragment, - "fragment.frag", - ENTRY_NAME, - None, - ) - .context("Error compiling fragment shader")?; - - // Make into shader module - unsafe { - ( - device - .create_shader_module(vertex_compile_artifact.as_binary()) - .context("Error creating vertex shader module")?, - device - .create_shader_module(fragment_compile_artifact.as_binary()) - .context("Error creating fragment shader module")?, - ) + for db in self.depth_buffers.into_iter() { + db.deactivate(&mut device); } - }; - - // Shader entry points (ShaderStage) - let (vs_entry, fs_entry) = ( - EntryPoint:: { - entry: ENTRY_NAME, - module: &vs_module, - specialization: Specialization::default(), - }, - EntryPoint:: { - entry: ENTRY_NAME, - module: &fs_module, - specialization: Specialization::default(), - }, - ); - - // Rasterizer - let rasterizer = Rasterizer { - polygon_mode: PolygonMode::Fill, - cull_face: Face::BACK, - front_face: FrontFace::CounterClockwise, - depth_clamping: false, - depth_bias: None, - conservative: true, - line_width: State::Static(1.0), - }; - - // Depth stencil - let depth_stencil = DepthStencilDesc { - depth: Some(DepthTest { - fun: Comparison::Less, - write: true, - }), - depth_bounds: false, - stencil: None, - }; - - // Pipeline layout - let layout = unsafe { - device.create_pipeline_layout( - set_layouts.into_iter(), - // vp matrix, 4x4 f32 - IntoIter::new([(ShaderStageFlags::VERTEX, 0..64)]), - ) } - .context("Error creating pipeline layout")?; - - // Colour blending - let blender = { - let blend_state = BlendState { - color: BlendOp::Add { - src: Factor::One, - dst: Factor::Zero, - }, - alpha: BlendOp::Add { - src: Factor::One, - dst: Factor::Zero, - }, - }; + self.repo.deactivate(device_lock); + + Ok(()) + } +} - BlendDesc { +impl<'a, M> IntoDrawPass> for Entity +where + M: for<'b> MinRenderFeatures<'b> + 'static, +{ + fn init( + self, + session: &Session, + adapter: &Adapter, + device_lock: Arc>, + queue_negotiator: &mut QueueNegotiator, + swapchain_properties: &SwapchainProperties, + ) -> Result> { + let spec = PipelineSpecBuilder::default() + .rasterizer(Rasterizer { + polygon_mode: PolygonMode::Fill, + cull_face: Face::BACK, + front_face: FrontFace::CounterClockwise, + depth_clamping: false, + depth_bias: None, + conservative: true, + line_width: State::Static(1.0), + }) + .depth_stencil(DepthStencilDesc { + depth: Some(DepthTest { + fun: Comparison::Less, + write: true, + }), + depth_bounds: false, + stencil: None, + }) + .blender(BlendDesc { logic_op: Some(LogicOp::Copy), targets: vec![ColorBlendDesc { mask: ColorMask::ALL, - blend: Some(blend_state), + blend: Some(BlendState { + color: BlendOp::Add { + src: Factor::One, + dst: Factor::Zero, + }, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::Zero, + }, + }), + }], + }) + .primitive_assembler(VertexPrimitiveAssemblerSpec::with_buffers( + InputAssemblerDesc::new(Primitive::TriangleList), + vec![VertexBufferSpec { + attributes: vec![Format::Rgb32Sfloat, Format::R32Sint, Format::Rg32Sfloat], + rate: VertexInputRate::Vertex, + }], + )) + .shader_vertex(ShaderDesc { + source: include_str!("../data/stockton.vert").to_string(), + entry: "main".to_string(), + kind: ShaderKind::Vertex, + }) + .shader_fragment(ShaderDesc { + source: include_str!("../data/stockton.frag").to_string(), + entry: "main".to_string(), + kind: ShaderKind::Fragment, + }) + .push_constants(vec![(ShaderStageFlags::VERTEX, 0..64)]) + .renderpass(RenderpassSpec { + colors: vec![Attachment { + format: Some(swapchain_properties.format), + samples: 1, + ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::Store), + stencil_ops: AttachmentOps::new( + AttachmentLoadOp::Clear, + AttachmentStoreOp::DontCare, + ), + layouts: Layout::ColorAttachmentOptimal..Layout::ColorAttachmentOptimal, }], + depth: Some(Attachment { + format: Some(swapchain_properties.depth_format), + samples: 1, + ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::DontCare), + stencil_ops: AttachmentOps::new( + AttachmentLoadOp::DontCare, + AttachmentStoreOp::DontCare, + ), + layouts: Layout::Undefined..Layout::DepthStencilAttachmentOptimal, + }), + inputs: vec![], + resolves: vec![], + preserves: vec![], + }) + .build() + .context("Error building pipeline")?; + + let map_lock: Arc> = session.resources.get::>>().unwrap().clone(); + let repo = TextureRepo::new( + device_lock.clone(), + queue_negotiator + .family::() + .ok_or(EnvironmentError::NoSuitableFamilies) + .context("Error finding texture queue")?, + queue_negotiator + .get_queue::() + .ok_or(EnvironmentError::NoQueues) + .context("Error finding texture queue")?, + adapter, + TextureLoadConfig { + resolver: FsResolver::new(Path::new("textures"), map_lock), + filter: Filter::Linear, + wrap_mode: WrapMode::Tile, + }, + ) + .context("Error creating texture repo")?; + + let (draw_buffers, pipeline, framebuffers, depth_buffers) = { + let mut device = device_lock.write().map_err(|_| LockPoisoned::Device)?; + let draw_buffers = + DrawBuffers::new(&mut device, adapter).context("Error creating draw buffers")?; + let pipeline = spec + .build( + &mut device, + swapchain_properties.extent, + swapchain_properties, + once(&*repo.get_ds_layout()?), + ) + .context("Error building pipeline")?; + + let mut framebuffers = Vec::with_capacity(swapchain_properties.image_count as usize); + let mut depth_buffers = Vec::with_capacity(swapchain_properties.image_count as usize); + let fat = FramebufferAttachment { + usage: Usage::COLOR_ATTACHMENT, + format: swapchain_properties.format, + view_caps: ViewCapabilities::empty(), + }; + let dat = FramebufferAttachment { + usage: Usage::DEPTH_STENCIL_ATTACHMENT, + format: swapchain_properties.depth_format, + view_caps: ViewCapabilities::empty(), + }; + for _i in 0..swapchain_properties.image_count { + unsafe { + framebuffers.push(device.create_framebuffer( + &pipeline.renderpass, + IntoIter::new([fat.clone(), dat.clone()]), + swapchain_properties.extent, + )?); + depth_buffers.push( + DedicatedLoadedImage::new( + &mut device, + adapter, + swapchain_properties.depth_format, + Usage::DEPTH_STENCIL_ATTACHMENT, + SubresourceRange { + aspects: Aspects::DEPTH, + level_start: 0, + level_count: Some(1), + layer_start: 0, + layer_count: Some(1), + }, + swapchain_properties.extent.width as usize, + swapchain_properties.extent.height as usize, + ) + .context("Error creating depth buffer")?, + ) + } } - }; - - // Baked states - let baked_states = BakedStates { - viewport: Some(Viewport { - rect: extent.rect(), - depth: (0.0..1.0), - }), - scissor: Some(extent.rect()), - blend_constants: None, - depth_bounds: None, - }; - - // Primitive assembler - let primitive_assembler = PrimitiveAssemblerDesc::Vertex { - buffers: &[VertexBufferDesc { - binding: 0, - stride: (size_of::() * 6) as u32, - rate: VertexInputRate::Vertex, - }], - attributes: &[ - AttributeDesc { - location: 0, - binding: 0, - element: Element { - format: Format::Rgb32Sfloat, - offset: 0, - }, - }, - AttributeDesc { - location: 1, - binding: 0, - element: Element { - format: Format::R32Sint, - offset: (size_of::() * 3) as u32, - }, - }, - AttributeDesc { - location: 2, - binding: 0, - element: Element { - format: Format::Rg32Sfloat, - offset: (size_of::() * 4) as u32, - }, - }, - ], - input_assembler: InputAssemblerDesc::new(Primitive::TriangleList), - vertex: vs_entry, - tessellation: None, - geometry: None, - }; - // Pipeline description - let pipeline_desc = GraphicsPipelineDesc { - label: Some("3D"), - rasterizer, - fragment: Some(fs_entry), - blender, - depth_stencil, - multisampling: None, - baked_states, - layout: &layout, - subpass, - flags: PipelineCreationFlags::empty(), - parent: BasePipeline::None, - primitive_assembler, + (draw_buffers, pipeline, framebuffers, depth_buffers) }; - // Pipeline - let pipeline = unsafe { device.create_graphics_pipeline(&pipeline_desc, None) } - .context("Error creating graphics pipeline")?; - - Ok(CompletePipeline { - renderpass: ManuallyDrop::new(renderpass), - pipeline_layout: ManuallyDrop::new(layout), - pipeline: ManuallyDrop::new(pipeline), - vs_module: ManuallyDrop::new(vs_module), - fs_module: ManuallyDrop::new(fs_module), + Ok(LevelDrawPass { + pipeline, + repo, + draw_buffers, + active_camera: self, + _d: PhantomData, + framebuffers, + depth_buffers, + next_resources: 0, }) } - /// Deactivate vulkan resources. Use before dropping - pub fn deactivate(self, device: &mut DeviceT) { - unsafe { - use core::ptr::read; - - device.destroy_render_pass(ManuallyDrop::into_inner(read(&self.renderpass))); - - device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module))); - device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.fs_module))); + fn find_aux_queues<'c>( + adapter: &'c Adapter, + queue_negotiator: &mut QueueNegotiator, + ) -> Result)>> { + queue_negotiator.find(adapter, &TexLoadQueue)?; - device.destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline))); - - device.destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout))); - } + Ok(vec![queue_negotiator + .family_spec::(&adapter.queue_families, 1) + .ok_or(EnvironmentError::NoSuitableFamilies)?]) } } diff --git a/stockton-render/src/draw/draw_passes/mod.rs b/stockton-render/src/draw/draw_passes/mod.rs index 566a64b..70f1786 100644 --- a/stockton-render/src/draw/draw_passes/mod.rs +++ b/stockton-render/src/draw/draw_passes/mod.rs @@ -10,22 +10,21 @@ use anyhow::Result; mod cons; mod level; -pub use level::LevelDrawPass; pub use cons::{ConsDrawPass, NilDrawPass}; +pub use level::LevelDrawPass; /// One of several 'passes' that draw on each frame. pub trait DrawPass { /// Queue any necessary draw commands to cmd_buffer /// This should assume the command buffer isn't in the middle of a renderpass, and should leave it as such. - fn queue_draw(&self, session: &Session, cmd_buffer: &mut CommandBufferT) -> Result<()>; + fn queue_draw( + &mut self, + session: &Session, + img_view: &ImageViewT, + cmd_buffer: &mut CommandBufferT, + ) -> Result<()>; - /// This function should ask the queue negotatior to find families for any auxilary operations this draw pass needs to perform - /// For example, .find(&TexLoadQueue) - /// It should return then call .family_spec for each queue type negotiated and return the results. - fn find_aux_queues<'a>( - adapter: &'a Adapter, - queue_negotiator: &mut QueueNegotiator, - ) -> Result)>>; + fn deactivate(self, device: &mut Arc>) -> Result<()>; } /// A type that can be made into a specific draw pass type. @@ -33,8 +32,18 @@ pub trait DrawPass { pub trait IntoDrawPass { fn init( self, + session: &Session, + adapter: &Adapter, device: Arc>, queue_negotiator: &mut QueueNegotiator, swapchain_properties: &SwapchainProperties, ) -> Result; + + /// This function should ask the queue negotatior to find families for any auxilary operations this draw pass needs to perform + /// For example, .find(&TexLoadQueue) + /// It should return then call .family_spec for each queue type negotiated and return the results. + fn find_aux_queues<'a>( + adapter: &'a Adapter, + queue_negotiator: &mut QueueNegotiator, + ) -> Result)>>; } diff --git a/stockton-render/src/draw/mod.rs b/stockton-render/src/draw/mod.rs index 411e835..b570b12 100644 --- a/stockton-render/src/draw/mod.rs +++ b/stockton-render/src/draw/mod.rs @@ -3,7 +3,8 @@ pub mod target; mod buffers; -mod camera; +mod builders; +pub mod camera; mod context; pub mod draw_passes; mod queue_negotiator; diff --git a/stockton-render/src/draw/queue_negotiator.rs b/stockton-render/src/draw/queue_negotiator.rs index b39678f..65c7aa4 100644 --- a/stockton-render/src/draw/queue_negotiator.rs +++ b/stockton-render/src/draw/queue_negotiator.rs @@ -12,6 +12,7 @@ use std::{ pub struct QueueNegotiator { family_ids: HashMap, already_allocated: HashMap>>, usize)>, + all: Vec, } /// Can be used to select a specific queue family @@ -25,6 +26,7 @@ impl QueueNegotiator { QueueNegotiator { family_ids: HashMap::new(), already_allocated: HashMap::new(), + all: vec![], } } @@ -57,20 +59,23 @@ impl QueueNegotiator { Ok(()) } - pub fn get_queue( - &mut self, - groups: &mut Vec, - ) -> Option>> { + pub fn set_queue_groups(&mut self, queue_groups: Vec) { + self.all = queue_groups + } + + pub fn get_queue(&mut self) -> Option>> { let tid = TypeId::of::(); let family_id = self.family_ids.get(&tid)?; - - match groups + log::debug!("{:?}", self.all); + log::debug!("{:?}", self.already_allocated); + match self + .all .iter() .position(|x| !x.queues.is_empty() && x.family == *family_id) { Some(idx) => { // At least one remaining queue - let queue = groups[idx].queues.pop().unwrap(); + let queue = self.all[idx].queues.pop().unwrap(); let queue = Arc::new(RwLock::new(queue)); self.add_to_allocated::(queue.clone()); diff --git a/stockton-render/src/draw/target.rs b/stockton-render/src/draw/target.rs index c46feb5..de803aa 100644 --- a/stockton-render/src/draw/target.rs +++ b/stockton-render/src/draw/target.rs @@ -1,19 +1,21 @@ //! Resources needed for drawing on the screen, including sync objects use std::{ + borrow::Borrow, iter::{empty, once}, mem::ManuallyDrop, }; use hal::{ command::CommandBufferFlags, - format::{ChannelType, Format, ImageFeature}, - image::{Extent, Usage as ImgUsage}, - pso::Viewport, + format::{Aspects, ChannelType, Format, ImageFeature}, + image::{Access, Extent, Layout, SubresourceRange, Usage as ImgUsage}, + memory::{Barrier, Dependencies}, + pso::{PipelineStage, Viewport}, window::{CompositeAlphaMode, Extent2D, PresentMode, SwapchainConfig}, }; -use super::{buffers::DedicatedLoadedImage, draw_passes::DrawPass}; +use super::{draw_passes::DrawPass}; use crate::{error::EnvironmentError, types::*}; use anyhow::{Context, Result}; use stockton_types::Session; @@ -26,6 +28,7 @@ pub struct SwapchainProperties { pub composite_alpha_mode: CompositeAlphaMode, pub viewport: Viewport, pub extent: Extent, + pub image_count: u32, } impl SwapchainProperties { @@ -97,6 +100,11 @@ impl SwapchainProperties { composite_alpha_mode, extent, viewport, + image_count: if present_mode == PresentMode::MAILBOX { + ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(3)) + } else { + ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(2)) + }, }) } } @@ -104,12 +112,8 @@ impl SwapchainProperties { pub struct TargetChain { /// Surface we're targeting pub surface: ManuallyDrop, - pub properties: SwapchainProperties, - /// The depth buffer/image used for drawing - pub depth_buffer: ManuallyDrop, - /// Resources tied to each target frame in the swapchain pub targets: Box<[TargetResources]>, @@ -155,28 +159,6 @@ impl TargetChain { image_usage: ImgUsage::COLOR_ATTACHMENT, }; - let depth_buffer = { - use hal::format::Aspects; - use hal::image::SubresourceRange; - - DedicatedLoadedImage::new( - device, - adapter, - properties.depth_format, - ImgUsage::DEPTH_STENCIL_ATTACHMENT, - SubresourceRange { - aspects: Aspects::DEPTH, - level_start: 0, - level_count: Some(1), - layer_start: 0, - layer_count: Some(1), - }, - properties.extent.width as usize, - properties.extent.height as usize, - ) - .context("Error creating depth buffer")? - }; - let _fat = swap_config.framebuffer_attachment(); let mut targets: Vec = Vec::with_capacity(swap_config.image_count as usize); @@ -203,7 +185,6 @@ impl TargetChain { surface: ManuallyDrop::new(surface), targets: targets.into_boxed_slice(), sync_objects: sync_objects.into_boxed_slice(), - depth_buffer: ManuallyDrop::new(depth_buffer), properties, last_syncs: (image_count - 1) as usize, // This means the next one to be used is index 0 last_image: 0, @@ -230,8 +211,6 @@ impl TargetChain { ) -> SurfaceT { use core::ptr::read; unsafe { - ManuallyDrop::into_inner(read(&self.depth_buffer)).deactivate(device); - for i in 0..self.targets.len() { read(&self.targets[i]).deactivate(device, cmd_pool); } @@ -250,7 +229,7 @@ impl TargetChain { &'a mut self, device: &mut DeviceT, command_queue: &mut QueueT, - dp: &DP, + dp: &mut DP, session: &Session, ) -> Result<()> { self.last_syncs = (self.last_syncs + 1) % self.sync_objects.len(); @@ -280,9 +259,45 @@ impl TargetChain { unsafe { target.cmd_buffer.begin_primary(CommandBufferFlags::empty()); - dp.queue_draw(session, &mut target.cmd_buffer) + target.cmd_buffer.pipeline_barrier( + PipelineStage::TOP_OF_PIPE..PipelineStage::TOP_OF_PIPE, + Dependencies::empty(), + once(Barrier::Image { + states: (Access::empty(), Layout::Undefined) + ..(Access::empty(), Layout::ColorAttachmentOptimal), + target: img.borrow(), + range: SubresourceRange { + aspects: Aspects::COLOR, + level_start: 0, + level_count: Some(1), + layer_start: 0, + layer_count: Some(1), + }, + families: None, + }), + ); + + dp.queue_draw(session, img.borrow(), &mut target.cmd_buffer) .context("Error in draw pass")?; + target.cmd_buffer.pipeline_barrier( + PipelineStage::BOTTOM_OF_PIPE..PipelineStage::BOTTOM_OF_PIPE, + Dependencies::empty(), + once(Barrier::Image { + states: (Access::empty(), Layout::ColorAttachmentOptimal) + ..(Access::empty(), Layout::Present), + target: img.borrow(), + range: SubresourceRange { + aspects: Aspects::COLOR, + level_start: 0, + level_count: Some(1), + layer_start: 0, + layer_count: Some(1), + }, + families: None, + }), + ); + target.cmd_buffer.finish(); } diff --git a/stockton-render/src/draw/texture/resolver.rs b/stockton-render/src/draw/texture/resolver.rs index 1dbc62d..4b61c41 100644 --- a/stockton-render/src/draw/texture/resolver.rs +++ b/stockton-render/src/draw/texture/resolver.rs @@ -4,7 +4,6 @@ use crate::draw::texture::image::LoadableImage; use stockton_levels::{parts::IsTexture, prelude::HasTextures}; use std::{ - mem::drop, path::Path, sync::{Arc, RwLock}, }; @@ -39,8 +38,8 @@ impl<'a, T: HasTextures> TextureResolver for FsResolver<'a, T> { let tex = map.get_texture(tex)?; let path = self.path.join(&tex.name()); - drop(tex); - drop(map); + // drop(tex); + // drop(map); if let Ok(file) = Reader::open(path) { if let Ok(guessed) = file.with_guessed_format() { @@ -50,6 +49,7 @@ impl<'a, T: HasTextures> TextureResolver for FsResolver<'a, T> { } } + log::warn!("Couldn't resolve texture {:?}", tex.name()); None } } diff --git a/stockton-render/src/lib.rs b/stockton-render/src/lib.rs index 850d3eb..17dbf03 100644 --- a/stockton-render/src/lib.rs +++ b/stockton-render/src/lib.rs @@ -5,6 +5,9 @@ extern crate gfx_backend_vulkan as back; extern crate gfx_hal as hal; extern crate nalgebra_glm as na; +#[macro_use] +extern crate derive_builder; + #[macro_use] extern crate legion; @@ -15,22 +18,18 @@ mod types; pub mod window; use draw::{ + draw_passes::{DrawPass, IntoDrawPass}, RenderingContext, - draw_passes::{DrawPass, IntoDrawPass} }; -use error::full_error_display; -use legion::world::SubWorld; -use legion::IntoQuery; + use std::sync::mpsc::{Receiver, Sender}; use std::sync::Arc; use std::sync::RwLock; pub use window::{UiState, WindowEvent}; use anyhow::Result; -use log::error; -use stockton_levels::prelude::*; -use stockton_types::components::{CameraSettings, Transform}; -use stockton_types::{Vector3, Session}; + +use stockton_types::Session; use winit::event_loop::ControlFlow; use winit::window::Window; @@ -51,13 +50,17 @@ pub struct Renderer { impl Renderer { /// Create a new Renderer. - pub fn new>(window: &Window, ui: &mut UiState, idp: IDP) -> Result<(Self, Sender)> { + pub fn new>( + window: &Window, + session: &Session, + idp: IDP, + ) -> Result<(Self, Sender)> { let (tx, rx) = channel(); let update_control_flow = Arc::new(RwLock::new(ControlFlow::Poll)); Ok(( Renderer { - context: RenderingContext::new(window, idp)?, + context: RenderingContext::new(window, session, idp)?, window_events: rx, update_control_flow, }, @@ -66,7 +69,7 @@ impl Renderer { } /// Render a single frame of the given session. - fn render(&mut self, session: &Session) -> Result<()> { + pub fn render(&mut self, session: &Session) -> Result<()> { // Try to draw if self.context.draw_next_frame(session).is_err() { // Probably the surface changed @@ -82,4 +85,4 @@ impl Renderer { fn resize(&mut self) -> Result<()> { unsafe { self.context.handle_surface_change() } } -} \ No newline at end of file +} diff --git a/stockton-render/src/systems.rs b/stockton-render/src/systems.rs index 67cea84..5f86c29 100644 --- a/stockton-render/src/systems.rs +++ b/stockton-render/src/systems.rs @@ -1 +1,2 @@ +pub use crate::draw::camera::calc_vp_matrix_system; pub use crate::window::process_window_events_system; diff --git a/stockton-render/src/types.rs b/stockton-render/src/types.rs index 797ced9..03c6e37 100644 --- a/stockton-render/src/types.rs +++ b/stockton-render/src/types.rs @@ -25,6 +25,7 @@ pub type FramebufferT = ::Framebuffer; pub type RenderPassT = ::RenderPass; pub type Adapter = hal::adapter::Adapter; +pub type EntryPoint<'a> = hal::pso::EntryPoint<'a, back::Backend>; pub type QueueGroup = hal::queue::QueueGroup; pub type DescriptorAllocator = rendy_descriptor::DescriptorAllocator; diff --git a/stockton-render/src/window.rs b/stockton-render/src/window.rs index 6e6a0e1..62e43d3 100644 --- a/stockton-render/src/window.rs +++ b/stockton-render/src/window.rs @@ -1,8 +1,8 @@ -use crate::{error::full_error_display, Renderer, DrawPass}; +use crate::{error::full_error_display, DrawPass, Renderer}; use egui::{Modifiers, Rect, Vec2}; use legion::systems::Runnable; use log::debug; -use stockton_levels::prelude::MinRenderFeatures; + use egui::{CtxRef, Event, Output, Pos2, RawInput}; use epaint::ClippedShape; @@ -93,7 +93,7 @@ impl UiState { } } - pub fn populate_initial_state(&mut self, renderer: &Renderer) { + pub fn populate_initial_state<'a, T: DrawPass>(&mut self, renderer: &Renderer) { let props = &renderer.context.target_chain.properties; self.set_dimensions(props.extent.width, props.extent.height); self.set_pixels_per_point(Some(renderer.context.pixels_per_point)); diff --git a/stockton-types/Cargo.toml b/stockton-types/Cargo.toml index f473c5f..13f1014 100644 --- a/stockton-types/Cargo.toml +++ b/stockton-types/Cargo.toml @@ -7,4 +7,3 @@ edition = "2018" [dependencies] nalgebra-glm = "^0.6" legion = { version = "^0.3" } -stockton-levels = { path = "../stockton-levels" } diff --git a/stockton-types/src/components/mod.rs b/stockton-types/src/components/mod.rs index a90f5e8..421cf9c 100644 --- a/stockton-types/src/components/mod.rs +++ b/stockton-types/src/components/mod.rs @@ -59,3 +59,17 @@ pub struct CameraSettings { /// Far clipping plane (world units) pub far: f32, } + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct CameraVPMatrix { + /// The camera's VP Matrix + pub vp_matrix: Mat4, +} + +impl Default for CameraVPMatrix { + fn default() -> Self { + CameraVPMatrix { + vp_matrix: Mat4::identity(), + } + } +} diff --git a/stockton-types/src/session.rs b/stockton-types/src/session.rs index 06779d3..f3d4e50 100644 --- a/stockton-types/src/session.rs +++ b/stockton-types/src/session.rs @@ -6,7 +6,7 @@ use legion::*; /// A loaded world. pub struct Session { pub world: World, - resources: Resources, + pub resources: Resources, schedule: Schedule, } -- cgit v1.2.3