Compare commits
100 commits
Author | SHA1 | Date | |
---|---|---|---|
Mars | f8278f4a74 | ||
Mars | 7d10d6c480 | ||
Mars | 3bd0b7e88b | ||
Mars | e4e688b720 | ||
Mars | 52f3e0cd8f | ||
Mars | e72e9bd51f | ||
Mars | 32a3d21488 | ||
Mars | 5c5d004a66 | ||
Mars | bca2a4e999 | ||
Mars | 0f4d0d72d9 | ||
Mars | a6fa5b0570 | ||
Mars | d4163fa7d6 | ||
Mars | 599eb29925 | ||
Mars | 2b77ce40b5 | ||
Mars | cf7b42b95c | ||
Mars | 4c82bbe275 | ||
Mars | 2f779d28ac | ||
Mars | 924fb0be7a | ||
Mars | 45e8a99bd1 | ||
Mars | c552fb40bc | ||
Mars | 769dd30fdd | ||
avery | 9b468e5c8a | ||
Mars | 450c92ec55 | ||
Mars | 0f7c86bd4b | ||
Mars | 2fa8e016da | ||
Mars | 5b7f400b7b | ||
Mars | 31f772eb2d | ||
Mars | f99ff172db | ||
Mars | 40af687b7f | ||
Mars | e2eec3fbeb | ||
Mars | 0caa990a93 | ||
Mars | edbcf2406b | ||
Mars | 4a4939e65b | ||
Mars | 52123f27ac | ||
Mars | 059dc159bd | ||
Mars | 3fdca6c6db | ||
Mars | ed9141ae8f | ||
Mars | fa2d41ac81 | ||
Mars | e06d360e28 | ||
Mars | b2779c119a | ||
Mars | 154a81721d | ||
Mars | 7632347218 | ||
Mars | bac5d088f8 | ||
Mars | 780a7301f5 | ||
Mars | 545975d6bb | ||
Mars | 96a92ec0e2 | ||
Mars | fdc9507670 | ||
Mars | 7dafdfffa6 | ||
Mars | 8bb2fafe01 | ||
Mars | 8285b60211 | ||
Mars | 02cd99a73a | ||
Mars | f541f6ec8c | ||
Mars | bdc1ebc047 | ||
Mars | b97a9e2b7b | ||
Mars | f4fcfd3fda | ||
Mars | ae7de1f8ee | ||
Mars | f0e85c0d88 | ||
Mars | 1732d56e22 | ||
Mars | 7cc871fb48 | ||
Mars | c2ee7e8677 | ||
Mars | 31b93deecb | ||
Mars | 1eade711ba | ||
Mars | 79fdc8c38a | ||
Mars | 61a2e9367b | ||
Mars | f4f4b7898b | ||
Mars | 6711f4b6e0 | ||
Mars | e3cc2bd8f3 | ||
Mars | 0d77992e67 | ||
Mars | df0e12a783 | ||
Mars | ecc11a2751 | ||
Mars | daad4cc907 | ||
Mars | 83631f940e | ||
Mars | 14ca81b3cb | ||
Mars | 23bb6b871f | ||
Mars | 76fa86d622 | ||
Mars | 7fd7beea60 | ||
Mars | 7648a55f8d | ||
Mars | e0b7e93bd8 | ||
Mars | 98bd5f7bc2 | ||
Mars | ba46d3d834 | ||
Mars | 9ae5a4675a | ||
Mars | 623c51d335 | ||
Mars | 87c6018de1 | ||
Mars | aadf46f066 | ||
Mars | 10af83237f | ||
Mars | 6395c6b95c | ||
Mars | 9b221b81b4 | ||
Mars | 658595e0c5 | ||
Mars | 134b43c1d4 | ||
Mars | 2735eb5807 | ||
Mars | ffd3f44464 | ||
Mars | ee96290c80 | ||
Mars | 329eeb76c7 | ||
Mars | a4c78acebf | ||
Mars | d489322ab2 | ||
Mars | df6ec77374 | ||
Mars | 01cdd533c5 | ||
Mars | 651f339537 | ||
Mars | d6c93896d1 | ||
Mars | 12c4d95aff |
|
@ -20,6 +20,7 @@ IndentWidth: 2
|
||||||
NamespaceIndentation: All
|
NamespaceIndentation: All
|
||||||
SpaceBeforeCpp11BracedList: true
|
SpaceBeforeCpp11BracedList: true
|
||||||
SpacesBeforeTrailingComments: 1
|
SpacesBeforeTrailingComments: 1
|
||||||
|
Standard: Latest
|
||||||
|
|
||||||
IncludeBlocks: Regroup
|
IncludeBlocks: Regroup
|
||||||
IncludeCategories:
|
IncludeCategories:
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
# noinspection SpellCheckingInspection
|
|
||||||
Checks: >
|
Checks: >
|
||||||
*,
|
*,
|
||||||
-ctad-maybe-unsupported,
|
-ctad-maybe-unsupported,
|
||||||
|
@ -8,9 +7,11 @@ Checks: >
|
||||||
-bugprone-implicit-widening-of-multiplication-result,
|
-bugprone-implicit-widening-of-multiplication-result,
|
||||||
-cert-env33-c,
|
-cert-env33-c,
|
||||||
-concurrency-mt-unsafe,
|
-concurrency-mt-unsafe,
|
||||||
|
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||||
-cppcoreguidelines-avoid-magic-numbers,
|
-cppcoreguidelines-avoid-magic-numbers,
|
||||||
-cppcoreguidelines-owning-memory,
|
-cppcoreguidelines-owning-memory,
|
||||||
-cppcoreguidelines-pro-type-member-init,
|
-cppcoreguidelines-pro-type-member-init,
|
||||||
|
-cppcoreguidelines-pro-type-union-access,
|
||||||
-cppcoreguidelines-pro-type-vararg,
|
-cppcoreguidelines-pro-type-vararg,
|
||||||
-fuchsia-*,
|
-fuchsia-*,
|
||||||
-google-*,
|
-google-*,
|
||||||
|
|
4
.clangd
4
.clangd
|
@ -1,4 +0,0 @@
|
||||||
Diagnostics:
|
|
||||||
Suppress: >
|
|
||||||
-Wmissing-template-arg-list-after-template-kw,
|
|
||||||
-Wctad-maybe-unsupported
|
|
3
.envrc
3
.envrc
|
@ -1,2 +1 @@
|
||||||
export NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1
|
use_flake
|
||||||
use_flake . --impure
|
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
.direnv/
|
.direnv/
|
||||||
.vscode/
|
.vscode/
|
||||||
build/
|
build/
|
||||||
|
imgui.ini
|
||||||
|
|
|
@ -18,5 +18,25 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"version": "11.0.2"
|
"version": "11.0.2"
|
||||||
|
},
|
||||||
|
"imgui": {
|
||||||
|
"cargoLocks": null,
|
||||||
|
"date": "2024-11-15",
|
||||||
|
"extract": null,
|
||||||
|
"name": "imgui",
|
||||||
|
"passthru": null,
|
||||||
|
"pinned": false,
|
||||||
|
"src": {
|
||||||
|
"deepClone": false,
|
||||||
|
"fetchSubmodules": false,
|
||||||
|
"leaveDotGit": false,
|
||||||
|
"name": null,
|
||||||
|
"owner": "ocornut",
|
||||||
|
"repo": "imgui",
|
||||||
|
"rev": "8082a849035ab9de2f9e9821f0ef96ead51b930d",
|
||||||
|
"sha256": "sha256-IAg27igFpypMuGsCyCKAYaqPpvnC+qtfiUp4kZ+CT0Q=",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"version": "8082a849035ab9de2f9e9821f0ef96ead51b930d"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,4 +12,16 @@
|
||||||
sha256 = "sha256-IKNt4xUoVi750zBti5iJJcCk3zivTt7nU12RIf8pM+0=";
|
sha256 = "sha256-IKNt4xUoVi750zBti5iJJcCk3zivTt7nU12RIf8pM+0=";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
imgui = {
|
||||||
|
pname = "imgui";
|
||||||
|
version = "8082a849035ab9de2f9e9821f0ef96ead51b930d";
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "ocornut";
|
||||||
|
repo = "imgui";
|
||||||
|
rev = "8082a849035ab9de2f9e9821f0ef96ead51b930d";
|
||||||
|
fetchSubmodules = false;
|
||||||
|
sha256 = "sha256-IAg27igFpypMuGsCyCKAYaqPpvnC+qtfiUp4kZ+CT0Q=";
|
||||||
|
};
|
||||||
|
date = "2024-11-15";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
279
file.txt
Normal file
279
file.txt
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
INFO: Vulkan Loader Version 1.3.296
|
||||||
|
INFO: Vulkan Loader Version 1.3.290
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
LAYER: Searching for explicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d
|
||||||
|
LAYER: Found the following files:
|
||||||
|
LAYER: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json
|
||||||
|
INFO: Found manifest file /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json (file version 1.2.0)
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
LAYER: Searching for explicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d
|
||||||
|
LAYER: Found the following files:
|
||||||
|
LAYER: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json
|
||||||
|
INFO: Found manifest file /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json (file version 1.2.0)
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
LAYER: Searching for explicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d
|
||||||
|
LAYER: Found the following files:
|
||||||
|
LAYER: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json
|
||||||
|
INFO: Found manifest file /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json (file version 1.2.0)
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
LAYER: Searching for explicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d
|
||||||
|
LAYER: Found the following files:
|
||||||
|
LAYER: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json
|
||||||
|
INFO: Found manifest file /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json (file version 1.2.0)
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
DRIVER: Searching for driver manifest files
|
||||||
|
DRIVER: In following locations:
|
||||||
|
DRIVER: /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json
|
||||||
|
DRIVER: Found the following files:
|
||||||
|
DRIVER: /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json
|
||||||
|
DRIVER: Found ICD manifest file /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json, version 1.0.0
|
||||||
|
DEBUG | DRIVER: Searching for ICD drivers named /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/lib/libMoltenVK.dylib
|
||||||
|
DRIVER: Searching for driver manifest files
|
||||||
|
DRIVER: In following locations:
|
||||||
|
DRIVER: /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json
|
||||||
|
DRIVER: Found the following files:
|
||||||
|
DRIVER: /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json
|
||||||
|
DRIVER: Found ICD manifest file /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json, version 1.0.0
|
||||||
|
DEBUG | DRIVER: Searching for ICD drivers named /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/lib/libMoltenVK.dylib
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
DRIVER: Searching for driver manifest files
|
||||||
|
DRIVER: In following locations:
|
||||||
|
DRIVER: /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json
|
||||||
|
DRIVER: Found the following files:
|
||||||
|
DRIVER: /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json
|
||||||
|
DRIVER: Found ICD manifest file /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json, version 1.0.0
|
||||||
|
DEBUG | DRIVER: Searching for ICD drivers named /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/lib/libMoltenVK.dylib
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
INFO: Portability enumeration bit was set, enumerating portability drivers.
|
||||||
|
LAYER: Searching for implicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /Users/marshall/vulkan-test/build/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.config/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/etc/xdg/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/lunarg/Dev/macos-sdk-build/Vulkan-Loader/build/install/etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /etc/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.local/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/store/kxrdwph3yw03h27g9h1w8yskf57savdm-vulkan-extension-layer-1.3.296.0/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /Users/marshall/.nix-profile/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /run/current-system/sw/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: /nix/var/nix/profiles/default/share/vulkan/implicit_layer.d
|
||||||
|
LAYER: Found no files
|
||||||
|
LAYER: Searching for explicit layer manifest files
|
||||||
|
LAYER: In following locations:
|
||||||
|
LAYER: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d
|
||||||
|
LAYER: Found the following files:
|
||||||
|
LAYER: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json
|
||||||
|
INFO: Found manifest file /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json (file version 1.2.0)
|
||||||
|
DRIVER: Searching for driver manifest files
|
||||||
|
DRIVER: In following locations:
|
||||||
|
DRIVER: /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json
|
||||||
|
DRIVER: Found the following files:
|
||||||
|
DRIVER: /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json
|
||||||
|
DRIVER: Found ICD manifest file /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/share/vulkan/icd.d/MoltenVK_icd.json, version 1.0.0
|
||||||
|
DEBUG | DRIVER: Searching for ICD drivers named /nix/store/6npkzf33ypdazap6m5iqr2sx041mvnnj-MoltenVK-1.2.11/lib/libMoltenVK.dylib
|
||||||
|
DEBUG | LAYER: Loading layer library /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/lib/libVkLayer_khronos_validation.dylib
|
||||||
|
INFO | LAYER: Insert instance layer "VK_LAYER_KHRONOS_validation" (/nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/lib/libVkLayer_khronos_validation.dylib)
|
||||||
|
LAYER: vkCreateInstance layer callstack setup to:
|
||||||
|
LAYER: <Application>
|
||||||
|
LAYER: ||
|
||||||
|
LAYER: <Loader>
|
||||||
|
LAYER: ||
|
||||||
|
LAYER: VK_LAYER_KHRONOS_validation
|
||||||
|
LAYER: Type: Explicit
|
||||||
|
LAYER: Manifest: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/share/vulkan/explicit_layer.d/VkLayer_khronos_validation.json
|
||||||
|
LAYER: Library: /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/lib/libVkLayer_khronos_validation.dylib
|
||||||
|
LAYER: ||
|
||||||
|
LAYER: <Drivers>
|
||||||
|
DEBUG | LAYER: Unloading layer library /nix/store/ihcv7k5smi4bn0ld97003v4gls1g49lg-vulkan-validation-layers-1.3.296.0/lib/libVkLayer_khronos_validation.dylib
|
||||||
|
Available extensions:
|
||||||
|
VK_KHR_surface
|
||||||
|
VK_EXT_metal_surface
|
||||||
|
VK_EXT_debug_utils
|
||||||
|
VK_KHR_portability_enumeration
|
||||||
|
VK_KHR_get_physical_device_properties2
|
||||||
|
Available devices:
|
||||||
|
Apple M2
|
||||||
|
Failed to find a suitable GPU!
|
98
flake.lock
98
flake.lock
|
@ -1,12 +1,63 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"flake-compat": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1688025799,
|
||||||
|
"narHash": "sha256-ktpB4dRtnksm9F5WawoIkEneh1nrEvuxb5lJFt1iOyw=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "8bf105319d44f6b9f0d764efa4fdef9f1cc9ba1c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixos-asahi": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731536673,
|
||||||
|
"narHash": "sha256-bEkcE98/AwmKzlipCruFdf3KK3CBmtfzabquHtrKURM=",
|
||||||
|
"owner": "zzywysm",
|
||||||
|
"repo": "nixos-asahi",
|
||||||
|
"rev": "09d4e26b7d49323faad37264763cf57988cfd720",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "zzywysm",
|
||||||
|
"repo": "nixos-asahi",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1727065772,
|
"lastModified": 1731139594,
|
||||||
"narHash": "sha256-U9baiEXL2YsS67QKlBAPIUq+OB+eUPKv8n1vGNdhiec=",
|
"narHash": "sha256-IigrKK3vYRpUu+HEjPL/phrfh7Ox881er1UEsZvw9Q4=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "76612b17c0ce71689921ca12d9ffdc9c23ce40b2",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731640008,
|
||||||
|
"narHash": "sha256-81hruQPQXZf1xtcyYct9XPvBWvKIk6/DSDCc5XcYKT4=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "989dc4cbf6a95f2e5fefc8cd61d2198a8fb6834a",
|
"rev": "63de88ed5f65084bb5cde3bdcb716e28cc03a933",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -15,13 +66,13 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1726481836,
|
"lastModified": 1726871744,
|
||||||
"narHash": "sha256-MWTBH4dd5zIz2iatDb8IkqSjIeFum9jAqkFxgHLdzO4=",
|
"narHash": "sha256-V5LpfdHyQkUF7RfOaDPrZDP+oqz88lTJrMT1+stXNwo=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "20f9370d5f588fb8c72e844c54511cab054b5f40",
|
"rev": "a1d92660c6b3b7c26fb883500a80ea9d33321be2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -33,11 +84,28 @@
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs",
|
"nixos-asahi": "nixos-asahi",
|
||||||
|
"nixpkgs": "nixpkgs_2",
|
||||||
"treefmt-nix": "treefmt-nix",
|
"treefmt-nix": "treefmt-nix",
|
||||||
"utils": "utils"
|
"utils": "utils"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1686795910,
|
||||||
|
"narHash": "sha256-jDa40qRZ0GRQtP9EMZdf+uCbvzuLnJglTUI2JoHfWDc=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "5c2b97c0a9bc5217fc3dfb1555aae0fb756d99f9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"systems": {
|
"systems": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681028828,
|
"lastModified": 1681028828,
|
||||||
|
@ -55,14 +123,14 @@
|
||||||
},
|
},
|
||||||
"treefmt-nix": {
|
"treefmt-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_3"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1726734507,
|
"lastModified": 1730321837,
|
||||||
"narHash": "sha256-VUH5O5AcOSxb0uL/m34dDkxFKP6WLQ6y4I1B4+N3L2w=",
|
"narHash": "sha256-vK+a09qq19QNu2MlLcvN4qcRctJbqWkX7ahgPZ/+maI=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"rev": "ee41a466c2255a3abe6bc50fc6be927cdee57a9f",
|
"rev": "746901bb8dba96d154b66492a29f5db0693dbfcc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -76,11 +144,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1726560853,
|
"lastModified": 1731533236,
|
||||||
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
39
flake.nix
39
flake.nix
|
@ -2,6 +2,7 @@
|
||||||
description = "C/C++ environment";
|
description = "C/C++ environment";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
|
nixos-asahi.url = "github:zzywysm/nixos-asahi";
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs";
|
nixpkgs.url = "github:NixOS/nixpkgs";
|
||||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||||
utils.url = "github:numtide/flake-utils";
|
utils.url = "github:numtide/flake-utils";
|
||||||
|
@ -10,13 +11,20 @@
|
||||||
outputs = {
|
outputs = {
|
||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
|
nixos-asahi,
|
||||||
treefmt-nix,
|
treefmt-nix,
|
||||||
utils,
|
utils,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
utils.lib.eachDefaultSystem (
|
utils.lib.eachDefaultSystem (
|
||||||
system: let
|
system: let
|
||||||
pkgs = import nixpkgs {inherit system;};
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
config = {
|
||||||
|
allowUnfree = true;
|
||||||
|
allowUnsupportedSystem = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
stdenv =
|
stdenv =
|
||||||
if pkgs.hostPlatform.isLinux
|
if pkgs.hostPlatform.isLinux
|
||||||
|
@ -32,16 +40,20 @@
|
||||||
inherit (sources.${name}) pname version src;
|
inherit (sources.${name}) pname version src;
|
||||||
};
|
};
|
||||||
|
|
||||||
fmt = mkPkg "fmt";
|
imgui = (mkPkg "imgui").override {
|
||||||
|
IMGUI_BUILD_GLFW_BINDING = true;
|
||||||
|
IMGUI_BUILD_VULKAN_BINDING = true;
|
||||||
|
};
|
||||||
|
|
||||||
deps = with pkgs; [
|
deps = with pkgs; [
|
||||||
fmt
|
|
||||||
glfw
|
glfw
|
||||||
glm
|
glm
|
||||||
|
imgui
|
||||||
|
shaderc.dev
|
||||||
|
shaderc.lib
|
||||||
vulkan-extension-layer
|
vulkan-extension-layer
|
||||||
vulkan-memory-allocator
|
vulkan-memory-allocator
|
||||||
vulkan-utility-libraries
|
vulkan-utility-libraries
|
||||||
vulkan-headers
|
|
||||||
vulkan-loader
|
vulkan-loader
|
||||||
vulkan-tools
|
vulkan-tools
|
||||||
];
|
];
|
||||||
|
@ -82,7 +94,6 @@
|
||||||
projectRootFile = "flake.nix";
|
projectRootFile = "flake.nix";
|
||||||
programs = {
|
programs = {
|
||||||
alejandra.enable = true;
|
alejandra.enable = true;
|
||||||
deadnix.enable = true;
|
|
||||||
|
|
||||||
clang-format = {
|
clang-format = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -92,13 +103,15 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
devShell = mkShell.override {inherit stdenv;} {
|
devShell = mkShell.override {inherit stdenv;} {
|
||||||
packages =
|
buildInputs =
|
||||||
[
|
[
|
||||||
alejandra
|
alejandra
|
||||||
bear
|
bear
|
||||||
|
cmake
|
||||||
(llvmPackages_18.clang-tools.override {enableLibcxx = true;})
|
(llvmPackages_18.clang-tools.override {enableLibcxx = true;})
|
||||||
lldb
|
lldb
|
||||||
meson
|
meson
|
||||||
|
nil
|
||||||
ninja
|
ninja
|
||||||
nvfetcher
|
nvfetcher
|
||||||
pkg-config
|
pkg-config
|
||||||
|
@ -113,6 +126,20 @@
|
||||||
|
|
||||||
VULKAN_SDK = "${vulkan-headers}";
|
VULKAN_SDK = "${vulkan-headers}";
|
||||||
VK_LAYER_PATH = "${vulkan-validation-layers}/share/vulkan/explicit_layer.d";
|
VK_LAYER_PATH = "${vulkan-validation-layers}/share/vulkan/explicit_layer.d";
|
||||||
|
VK_ICD_FILENAMES =
|
||||||
|
if stdenv.isDarwin
|
||||||
|
then "${darwin.moltenvk}/share/vulkan/icd.d/MoltenVK_icd.json"
|
||||||
|
else let
|
||||||
|
vulkanDir =
|
||||||
|
if stdenv.hostPlatform.isx86_64
|
||||||
|
then "${mesa.drivers}/share/vulkan/icd.d"
|
||||||
|
else "${nixos-asahi.packages.aarch64-linux.mesa-asahi-edge.drivers}/share/vulkan/icd.d";
|
||||||
|
vulkanFiles = builtins.filter (file: builtins.match ".*\\.json$" file != null) (builtins.attrNames (builtins.readDir vulkanDir));
|
||||||
|
vulkanPaths = lib.concatStringsSep ":" (map (file: "${vulkanDir}/${file}") vulkanFiles);
|
||||||
|
in
|
||||||
|
if stdenv.hostPlatform.isx86_64
|
||||||
|
then "${linuxPackages_latest.nvidia_x11_beta}/share/vulkan/icd.d/nvidia_icd.x86_64.json:${vulkanPaths}"
|
||||||
|
else vulkanPaths;
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
export PATH="${llvmPackages_18.clang-tools.override {enableLibcxx = true;}}/bin:$PATH"
|
export PATH="${llvmPackages_18.clang-tools.override {enableLibcxx = true;}}/bin:$PATH"
|
||||||
|
|
8617
include/stb_image.h
Normal file
8617
include/stb_image.h
Normal file
File diff suppressed because it is too large
Load diff
3542
include/tiny_obj_loader.h
Normal file
3542
include/tiny_obj_loader.h
Normal file
File diff suppressed because it is too large
Load diff
5015
include/vkfw.hpp
Normal file
5015
include/vkfw.hpp
Normal file
File diff suppressed because it is too large
Load diff
47
meson.build
47
meson.build
|
@ -2,7 +2,7 @@ project(
|
||||||
'graphics-test',
|
'graphics-test',
|
||||||
'cpp',
|
'cpp',
|
||||||
version: '0.1.0',
|
version: '0.1.0',
|
||||||
default_options: ['cpp_std=c++20', 'warning_level=everything', 'buildtype=debugoptimized'],
|
default_options: ['cpp_std=c++26', 'warning_level=everything', 'buildtype=debugoptimized'],
|
||||||
)
|
)
|
||||||
|
|
||||||
cpp = meson.get_compiler('cpp')
|
cpp = meson.get_compiler('cpp')
|
||||||
|
@ -12,37 +12,40 @@ common_cpp_args = [
|
||||||
'-Wno-c++20-extensions',
|
'-Wno-c++20-extensions',
|
||||||
'-Wno-c++98-compat',
|
'-Wno-c++98-compat',
|
||||||
'-Wno-c++98-compat-pedantic',
|
'-Wno-c++98-compat-pedantic',
|
||||||
'-Wno-disabled-macro-expansion',
|
|
||||||
'-Wno-missing-prototypes',
|
|
||||||
'-Wno-padded',
|
|
||||||
'-Wno-pre-c++20-compat-pedantic',
|
'-Wno-pre-c++20-compat-pedantic',
|
||||||
|
'-Wno-padded',
|
||||||
'-Wno-switch-default',
|
'-Wno-switch-default',
|
||||||
'-Wno-unsafe-buffer-usage',
|
'-mavx2',
|
||||||
'-Wunused-function',
|
|
||||||
'-fvisibility=hidden',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
add_project_arguments(cpp.get_supported_arguments(common_cpp_args), language: 'cpp')
|
add_project_arguments(cpp.get_supported_arguments(common_cpp_args), language: 'cpp')
|
||||||
|
|
||||||
source_file_names = [
|
|
||||||
'src/main.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
sources = []
|
|
||||||
|
|
||||||
foreach file : source_file_names
|
|
||||||
sources += files(file)
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
dependency('fmt', static: true),
|
dependency('glfw3', include_type: 'system'),
|
||||||
dependency('glfw3'),
|
dependency('glm', include_type: 'system'),
|
||||||
dependency('glm'),
|
dependency('vulkan', include_type: 'system'),
|
||||||
dependency('vulkan'),
|
dependency('shaderc', include_type: 'system'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
imgui_dep = dependency('imgui', required: false, include_type: 'system')
|
||||||
|
|
||||||
|
if not imgui_dep.found()
|
||||||
|
imgui_dep = cpp.find_library('imgui', required: true)
|
||||||
|
endif
|
||||||
|
|
||||||
|
deps += imgui_dep
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
'graphics-test',
|
'graphics-test',
|
||||||
sources,
|
sources: [
|
||||||
|
'src/main.cpp',
|
||||||
|
'src/camera/camera.cpp',
|
||||||
|
'src/gui/imgui_manager.cpp',
|
||||||
|
'src/init/vulkan_instance.cpp',
|
||||||
|
'src/init/debug_messenger.cpp',
|
||||||
|
'src/init/device_manager.cpp',
|
||||||
|
'src/window/window_manager.cpp',
|
||||||
|
],
|
||||||
|
include_directories: include_directories('include', is_system: true),
|
||||||
dependencies: deps,
|
dependencies: deps,
|
||||||
)
|
)
|
16053
models/viking_room.obj
Normal file
16053
models/viking_room.obj
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,4 @@
|
||||||
[fmt]
|
[imgui]
|
||||||
src.github = "fmtlib/fmt"
|
src.git = "https://github.com/ocornut/imgui.git"
|
||||||
fetch.github = "fmtlib/fmt"
|
src.branch = "docking"
|
||||||
|
fetch.github = "ocornut/imgui"
|
||||||
|
|
8
shaders/crosshair_fragment.glsl
Normal file
8
shaders/crosshair_fragment.glsl
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 fragColor;
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = vec4(fragColor, 1.0);
|
||||||
|
}
|
11
shaders/crosshair_vertex.glsl
Normal file
11
shaders/crosshair_vertex.glsl
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 inPosition;
|
||||||
|
layout(location = 1) in vec3 inColor;
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(inPosition, 0.0, 1.0);
|
||||||
|
fragColor = inColor;
|
||||||
|
}
|
47
shaders/fragment.glsl
Normal file
47
shaders/fragment.glsl
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(binding = 3) uniform sampler2D texSampler;
|
||||||
|
|
||||||
|
layout(binding = 1) uniform LightInfo {
|
||||||
|
vec3 position;
|
||||||
|
vec3 color;
|
||||||
|
float ambient_strength;
|
||||||
|
float specular_strength;
|
||||||
|
} light;
|
||||||
|
|
||||||
|
layout(binding = 2) uniform CameraInfo {
|
||||||
|
vec3 position;
|
||||||
|
} camera;
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 fragColor;
|
||||||
|
layout(location = 1) in vec2 fragTexCoord;
|
||||||
|
layout(location = 2) in vec3 fragNormal;
|
||||||
|
layout(location = 3) in vec3 fragWorldPos;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// Get base color from texture
|
||||||
|
vec4 texColor = texture(texSampler, fragTexCoord);
|
||||||
|
|
||||||
|
// Normalize vectors
|
||||||
|
vec3 normal = normalize(fragNormal);
|
||||||
|
vec3 lightDir = normalize(light.position - fragWorldPos);
|
||||||
|
vec3 viewDir = normalize(camera.position - fragWorldPos);
|
||||||
|
vec3 reflectDir = reflect(-lightDir, normal);
|
||||||
|
|
||||||
|
// Ambient
|
||||||
|
vec3 ambient = light.ambient_strength * light.color;
|
||||||
|
|
||||||
|
// Diffuse
|
||||||
|
float diff = max(dot(normal, lightDir), 0.0);
|
||||||
|
vec3 diffuse = diff * light.color;
|
||||||
|
|
||||||
|
// Specular
|
||||||
|
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);
|
||||||
|
vec3 specular = light.specular_strength * spec * light.color;
|
||||||
|
|
||||||
|
// Combine lighting components
|
||||||
|
vec3 lighting = (ambient + diffuse + specular);
|
||||||
|
outColor = vec4(lighting * texColor.rgb, texColor.a);
|
||||||
|
}
|
28
shaders/vertex.glsl
Normal file
28
shaders/vertex.glsl
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(binding = 0) uniform UniformBufferObject {
|
||||||
|
mat4 model;
|
||||||
|
mat4 view;
|
||||||
|
mat4 proj;
|
||||||
|
} ubo;
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 inPosition;
|
||||||
|
layout(location = 1) in vec3 inColor;
|
||||||
|
layout(location = 2) in vec2 inTexCoord;
|
||||||
|
layout(location = 3) in vec3 inNormal;
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
layout(location = 1) out vec2 fragTexCoord;
|
||||||
|
layout(location = 2) out vec3 fragNormal;
|
||||||
|
layout(location = 3) out vec3 fragWorldPos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 worldPos = ubo.model * vec4(inPosition, 1.0);
|
||||||
|
gl_Position = ubo.proj * ubo.view * worldPos;
|
||||||
|
|
||||||
|
// Transform normal to world space
|
||||||
|
fragNormal = mat3(transpose(inverse(ubo.model))) * inNormal;
|
||||||
|
fragWorldPos = worldPos.xyz;
|
||||||
|
fragColor = inColor;
|
||||||
|
fragTexCoord = inTexCoord;
|
||||||
|
}
|
98
src/camera/camera.cpp
Normal file
98
src/camera/camera.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#include "camera.hpp"
|
||||||
|
|
||||||
|
#include "../util/constants.hpp"
|
||||||
|
|
||||||
|
using namespace constants;
|
||||||
|
|
||||||
|
Camera::Camera()
|
||||||
|
: mPosition(2.0, 2.0, 0.5),
|
||||||
|
mFront(glm::normalize(glm::dvec3(0.0, 1.0, 0.0))),
|
||||||
|
mUp(0.0, 0.0, 1.0),
|
||||||
|
mRight(glm::normalize(glm::cross(mFront, glm::dvec3(0.0, 0.0, 1.0)))),
|
||||||
|
mYaw(180.0),
|
||||||
|
mPitch(0.0) {
|
||||||
|
updateCameraVectors();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Camera::getPosition() const -> glm::dvec3 { return mPosition; }
|
||||||
|
|
||||||
|
fn Camera::getFront() const -> glm::dvec3 { return mFront; }
|
||||||
|
|
||||||
|
fn Camera::getYaw() const -> f64 { return mYaw; }
|
||||||
|
|
||||||
|
fn Camera::getPitch() const -> f64 { return mPitch; }
|
||||||
|
|
||||||
|
fn Camera::getViewMatrix() const -> glm::mat4 { return glm::lookAt(mPosition, mPosition + mFront, mUp); }
|
||||||
|
|
||||||
|
fn Camera::moveForward(f64 deltaTime) -> void {
|
||||||
|
// Project front vector onto horizontal plane by zeroing Z component
|
||||||
|
glm::dvec3 horizontalFront = mFront;
|
||||||
|
horizontalFront.z = 0.0;
|
||||||
|
horizontalFront = glm::normalize(horizontalFront);
|
||||||
|
mPosition += horizontalFront * CAMERA_SPEED * deltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Camera::moveBackward(f64 deltaTime) -> void {
|
||||||
|
// Project front vector onto horizontal plane by zeroing Z component
|
||||||
|
glm::dvec3 horizontalFront = mFront;
|
||||||
|
horizontalFront.z = 0.0;
|
||||||
|
horizontalFront = glm::normalize(horizontalFront);
|
||||||
|
mPosition -= horizontalFront * CAMERA_SPEED * deltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Camera::moveLeft(f64 deltaTime) -> void {
|
||||||
|
// Project right vector onto horizontal plane by zeroing Z component
|
||||||
|
glm::dvec3 horizontalRight = mRight;
|
||||||
|
horizontalRight.z = 0.0;
|
||||||
|
horizontalRight = glm::normalize(horizontalRight);
|
||||||
|
mPosition -= horizontalRight * CAMERA_SPEED * deltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Camera::moveRight(f64 deltaTime) -> void {
|
||||||
|
// Project right vector onto horizontal plane by zeroing Z component
|
||||||
|
glm::dvec3 horizontalRight = mRight;
|
||||||
|
horizontalRight.z = 0.0;
|
||||||
|
horizontalRight = glm::normalize(horizontalRight);
|
||||||
|
mPosition += horizontalRight * CAMERA_SPEED * deltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Camera::moveUp(f64 deltaTime) -> void {
|
||||||
|
mPosition += glm::dvec3(0.0, 0.0, 1.0) * CAMERA_SPEED * deltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Camera::moveDown(f64 deltaTime) -> void {
|
||||||
|
mPosition -= glm::dvec3(0.0, 0.0, 1.0) * CAMERA_SPEED * deltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Camera::rotate(f64 xoffset, double yoffset) -> void {
|
||||||
|
const f64 sensitivity = 0.1;
|
||||||
|
mYaw += xoffset * sensitivity;
|
||||||
|
mPitch += yoffset * sensitivity;
|
||||||
|
|
||||||
|
// Clamp yaw to [-180, 180] range
|
||||||
|
if (mYaw > 180.0)
|
||||||
|
mYaw -= 360.0;
|
||||||
|
if (mYaw < -180.0)
|
||||||
|
mYaw += 360.0;
|
||||||
|
|
||||||
|
// Constrain pitch to avoid camera flipping
|
||||||
|
if (mPitch > 89.0)
|
||||||
|
mPitch = 89.0;
|
||||||
|
if (mPitch < -89.0)
|
||||||
|
mPitch = -89.0;
|
||||||
|
|
||||||
|
updateCameraVectors();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn Camera::updateCameraVectors() -> void {
|
||||||
|
// Calculate new front vector
|
||||||
|
glm::dvec3 newFront;
|
||||||
|
newFront.x = cos(glm::radians(mYaw)) * cos(glm::radians(mPitch));
|
||||||
|
newFront.y = sin(glm::radians(mYaw)) * cos(glm::radians(mPitch));
|
||||||
|
newFront.z = sin(glm::radians(mPitch));
|
||||||
|
|
||||||
|
mFront = glm::normalize(newFront);
|
||||||
|
// Recalculate right and up vectors
|
||||||
|
mRight = glm::normalize(glm::cross(mFront, glm::dvec3(0.0, 0.0, 1.0)));
|
||||||
|
mUp = glm::normalize(glm::cross(mRight, mFront));
|
||||||
|
}
|
38
src/camera/camera.hpp
Normal file
38
src/camera/camera.hpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
#include "../util/types.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Camera class for handling 3D camera movement and perspective
|
||||||
|
*/
|
||||||
|
class Camera {
|
||||||
|
public:
|
||||||
|
Camera();
|
||||||
|
|
||||||
|
[[nodiscard]] fn getPosition() const -> glm::dvec3;
|
||||||
|
[[nodiscard]] fn getFront() const -> glm::dvec3;
|
||||||
|
[[nodiscard]] fn getYaw() const -> f64;
|
||||||
|
[[nodiscard]] fn getPitch() const -> f64;
|
||||||
|
[[nodiscard]] fn getViewMatrix() const -> glm::mat4;
|
||||||
|
|
||||||
|
fn moveForward(f64 deltaTime) -> void;
|
||||||
|
fn moveBackward(f64 deltaTime) -> void;
|
||||||
|
fn moveLeft(f64 deltaTime) -> void;
|
||||||
|
fn moveRight(f64 deltaTime) -> void;
|
||||||
|
fn moveUp(f64 deltaTime) -> void;
|
||||||
|
fn moveDown(f64 deltaTime) -> void;
|
||||||
|
fn rotate(f64 xoffset, f64 yoffset) -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
fn updateCameraVectors() -> void;
|
||||||
|
|
||||||
|
glm::dvec3 mPosition;
|
||||||
|
glm::dvec3 mFront;
|
||||||
|
glm::dvec3 mUp;
|
||||||
|
glm::dvec3 mRight;
|
||||||
|
f64 mYaw;
|
||||||
|
f64 mPitch;
|
||||||
|
};
|
202
src/gui/imgui_manager.cpp
Normal file
202
src/gui/imgui_manager.cpp
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
#include "imgui_manager.hpp"
|
||||||
|
|
||||||
|
ImGuiManager::~ImGuiManager() { cleanup(); }
|
||||||
|
|
||||||
|
void ImGuiManager::init(
|
||||||
|
vk::Instance instance,
|
||||||
|
vk::PhysicalDevice physicalDevice,
|
||||||
|
vk::Device device,
|
||||||
|
uint32_t queueFamily,
|
||||||
|
vk::Queue queue,
|
||||||
|
vk::RenderPass renderPass,
|
||||||
|
uint32_t minImageCount,
|
||||||
|
uint32_t imageCount,
|
||||||
|
vk::SampleCountFlagBits msaaSamples,
|
||||||
|
GLFWwindow* window
|
||||||
|
) {
|
||||||
|
mDevice = device;
|
||||||
|
|
||||||
|
// Create ImGui context
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
|
||||||
|
ImGuiIO& imGuiIO = ImGui::GetIO();
|
||||||
|
imGuiIO.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||||
|
imGuiIO.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||||
|
imGuiIO.IniFilename = nullptr; // Disable writing imgui.ini
|
||||||
|
|
||||||
|
// Setup Dear ImGui style
|
||||||
|
ImGui::StyleColorsDark();
|
||||||
|
|
||||||
|
// Initialize ImGui for GLFW and Vulkan
|
||||||
|
ImGui_ImplGlfw_InitForVulkan(window, true);
|
||||||
|
|
||||||
|
vk::DescriptorPoolSize descriptorPoolSize {
|
||||||
|
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::DescriptorPoolCreateInfo poolInfo {
|
||||||
|
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
|
||||||
|
.maxSets = 1,
|
||||||
|
.poolSizeCount = 1,
|
||||||
|
.pPoolSizes = &descriptorPoolSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
mDescriptorPool = device.createDescriptorPoolUnique(poolInfo);
|
||||||
|
|
||||||
|
ImGui_ImplVulkan_InitInfo initInfo {
|
||||||
|
.Instance = instance,
|
||||||
|
.PhysicalDevice = physicalDevice,
|
||||||
|
.Device = device,
|
||||||
|
.QueueFamily = queueFamily,
|
||||||
|
.Queue = queue,
|
||||||
|
.DescriptorPool = mDescriptorPool.get(),
|
||||||
|
.RenderPass = renderPass,
|
||||||
|
.MinImageCount = minImageCount,
|
||||||
|
.ImageCount = imageCount,
|
||||||
|
.MSAASamples = static_cast<VkSampleCountFlagBits>(msaaSamples),
|
||||||
|
.PipelineCache = VK_NULL_HANDLE,
|
||||||
|
.Subpass = 0,
|
||||||
|
.UseDynamicRendering = false,
|
||||||
|
.PipelineRenderingCreateInfo = {},
|
||||||
|
.Allocator = nullptr,
|
||||||
|
.CheckVkResultFn = nullptr,
|
||||||
|
.MinAllocationSize = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
ImGui_ImplVulkan_Init(&initInfo);
|
||||||
|
mInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiManager::cleanup() {
|
||||||
|
if (mInitialized) {
|
||||||
|
ImGui_ImplVulkan_Shutdown();
|
||||||
|
ImGui_ImplGlfw_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
mInitialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiManager::newFrame() {
|
||||||
|
ImGui_ImplVulkan_NewFrame();
|
||||||
|
ImGui_ImplGlfw_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
ImGui::Begin("Controls");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiManager::render() {
|
||||||
|
ImGui::End();
|
||||||
|
ImGui::Render();
|
||||||
|
|
||||||
|
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
|
||||||
|
ImGui::UpdatePlatformWindows();
|
||||||
|
ImGui::RenderPlatformWindowsDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiManager::renderControls(
|
||||||
|
float& cameraSpeed,
|
||||||
|
float& fieldOfView,
|
||||||
|
bool& wireframeMode,
|
||||||
|
float& lineWidth,
|
||||||
|
float maxLineWidth,
|
||||||
|
bool wideLineSupport,
|
||||||
|
Camera& camera,
|
||||||
|
LightInfo& lightSettings,
|
||||||
|
bool& needsPipelineRecreation
|
||||||
|
) {
|
||||||
|
// Camera Settings
|
||||||
|
if (ImGui::CollapsingHeader("Camera Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
ImGui::SliderFloat("Camera Speed", &cameraSpeed, 0.1F, 10.0F, "%.1f");
|
||||||
|
ImGui::SliderFloat("Field of View", &fieldOfView, 45.0F, 120.0F, "%.1f");
|
||||||
|
if (ImGui::Button("Reset Camera"))
|
||||||
|
camera = Camera();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rendering Settings
|
||||||
|
if (ImGui::CollapsingHeader("Rendering Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
if (ImGui::Checkbox("Wireframe Mode", &wireframeMode))
|
||||||
|
needsPipelineRecreation = true;
|
||||||
|
|
||||||
|
if (wireframeMode) {
|
||||||
|
if (wideLineSupport) {
|
||||||
|
if (ImGui::SliderFloat("Line Width", &lineWidth, 1.0F, maxLineWidth, "%.1f")) {
|
||||||
|
needsPipelineRecreation = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::TextColored(ImVec4(1.0F, 0.5F, 0.5F, 1.0F), "Wide lines not supported on this device");
|
||||||
|
lineWidth = 1.0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderControlsHelp();
|
||||||
|
renderFrameMetrics();
|
||||||
|
renderCameraInfo(camera);
|
||||||
|
renderLightControls(lightSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiManager::renderControlsHelp() {
|
||||||
|
if (ImGui::CollapsingHeader("Controls", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
ImGui::BulletText("Use mouse to look around");
|
||||||
|
ImGui::BulletText("WASD to move horizontally");
|
||||||
|
ImGui::BulletText("Space/Shift to move up/down");
|
||||||
|
ImGui::BulletText("ESC to toggle mouse capture");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiManager::renderFrameMetrics() {
|
||||||
|
if (ImGui::CollapsingHeader("Performance", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
ImGui::Text(
|
||||||
|
"Application average %.3f ms/frame (%.1f FPS)",
|
||||||
|
static_cast<double>(1000.0F / ImGui::GetIO().Framerate),
|
||||||
|
static_cast<double>(ImGui::GetIO().Framerate)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiManager::renderMemoryUsage(
|
||||||
|
size_t vertexSize,
|
||||||
|
size_t indexSize,
|
||||||
|
size_t vertexCount,
|
||||||
|
size_t indexCount
|
||||||
|
) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Memory Usage:");
|
||||||
|
ImGui::Text(
|
||||||
|
"Vertex Buffer: %.2f MB",
|
||||||
|
(static_cast<double>(vertexCount) * static_cast<double>(vertexSize)) / (1024.0 * 1024.0)
|
||||||
|
);
|
||||||
|
ImGui::Text(
|
||||||
|
"Index Buffer: %.2f MB",
|
||||||
|
(static_cast<double>(indexCount) * static_cast<double>(indexSize)) / (1024.0 * 1024.0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiManager::renderCameraInfo(const Camera& camera) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Camera Information:");
|
||||||
|
ImGui::Text(
|
||||||
|
"Position: (%.2f, %.2f, %.2f)", camera.getPosition().x, camera.getPosition().y, camera.getPosition().z
|
||||||
|
);
|
||||||
|
ImGui::Text(
|
||||||
|
"Front Vector: (%.2f, %.2f, %.2f)", camera.getFront().x, camera.getFront().y, camera.getFront().z
|
||||||
|
);
|
||||||
|
ImGui::Text("Yaw: %.2f°, Pitch: %.2f°", camera.getYaw(), camera.getPitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiManager::renderLightControls(LightInfo& lightSettings) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Light Controls:");
|
||||||
|
|
||||||
|
// Light Position
|
||||||
|
ImGui::DragFloat3("Light Position", &lightSettings.position.x, 0.1F, -10.0F, 10.0F);
|
||||||
|
|
||||||
|
// Light Color
|
||||||
|
ImGui::ColorEdit3("Light Color", &lightSettings.color.x);
|
||||||
|
|
||||||
|
// Light Strengths
|
||||||
|
ImGui::SliderFloat("Ambient Strength", &lightSettings.ambient_strength, 0.0F, 1.0F);
|
||||||
|
ImGui::SliderFloat("Specular Strength", &lightSettings.specular_strength, 0.0F, 1.0F);
|
||||||
|
}
|
61
src/gui/imgui_manager.hpp
Normal file
61
src/gui/imgui_manager.hpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_impl_glfw.h>
|
||||||
|
#include <imgui_impl_vulkan.h>
|
||||||
|
|
||||||
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
#include "../camera/camera.hpp"
|
||||||
|
#include "../structs/light_info.hpp"
|
||||||
|
|
||||||
|
class ImGuiManager {
|
||||||
|
public:
|
||||||
|
ImGuiManager() = default;
|
||||||
|
ImGuiManager(const ImGuiManager&) = delete;
|
||||||
|
ImGuiManager(ImGuiManager&&) = delete;
|
||||||
|
fn operator=(const ImGuiManager&)->ImGuiManager& = delete;
|
||||||
|
fn operator=(ImGuiManager&&)->ImGuiManager& = delete;
|
||||||
|
~ImGuiManager();
|
||||||
|
|
||||||
|
void init(
|
||||||
|
vk::Instance instance,
|
||||||
|
vk::PhysicalDevice physicalDevice,
|
||||||
|
vk::Device device,
|
||||||
|
uint32_t queueFamily,
|
||||||
|
vk::Queue queue,
|
||||||
|
vk::RenderPass renderPass,
|
||||||
|
uint32_t minImageCount,
|
||||||
|
uint32_t imageCount,
|
||||||
|
vk::SampleCountFlagBits msaaSamples,
|
||||||
|
GLFWwindow* window
|
||||||
|
);
|
||||||
|
|
||||||
|
fn cleanup() -> void;
|
||||||
|
static fn newFrame() -> void;
|
||||||
|
static fn render() -> void;
|
||||||
|
static fn renderControls(
|
||||||
|
float& cameraSpeed,
|
||||||
|
float& fieldOfView,
|
||||||
|
bool& wireframeMode,
|
||||||
|
float& lineWidth,
|
||||||
|
float maxLineWidth,
|
||||||
|
bool wideLineSupport,
|
||||||
|
Camera& camera,
|
||||||
|
LightInfo& lightSettings,
|
||||||
|
bool& needsPipelineRecreation
|
||||||
|
) -> void;
|
||||||
|
static fn renderMemoryUsage(size_t vertexSize, size_t indexSize, size_t vertexCount, size_t indexCount)
|
||||||
|
-> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vk::UniqueDescriptorPool mDescriptorPool;
|
||||||
|
vk::Device mDevice = nullptr;
|
||||||
|
bool mInitialized = false;
|
||||||
|
|
||||||
|
static fn renderControlsHelp() -> void;
|
||||||
|
static fn renderFrameMetrics() -> void;
|
||||||
|
static fn renderCameraInfo(const Camera& camera) -> void;
|
||||||
|
static fn renderLightControls(LightInfo& lightSettings) -> void;
|
||||||
|
};
|
105
src/init/debug_messenger.cpp
Normal file
105
src/init/debug_messenger.cpp
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
#include "debug_messenger.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr std::string_view ANSI_RESET = "\033[0m";
|
||||||
|
constexpr std::string_view ANSI_BOLD = "\033[1m";
|
||||||
|
constexpr std::string_view ANSI_RED = "\033[31m";
|
||||||
|
constexpr std::string_view ANSI_YELLOW = "\033[33m";
|
||||||
|
constexpr std::string_view ANSI_LIGHT_BLUE = "\033[94m";
|
||||||
|
constexpr std::string_view ANSI_WHITE = "\033[97m";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DebugMessenger::create(const vk::Instance& instance, Config config)
|
||||||
|
-> std::expected<vk::UniqueDebugUtilsMessengerEXT, std::string> {
|
||||||
|
#ifdef NDEBUG
|
||||||
|
return nullptr;
|
||||||
|
#else
|
||||||
|
try {
|
||||||
|
vk::DebugUtilsMessengerCreateInfoEXT createInfo {
|
||||||
|
.messageSeverity = config.severity_flags,
|
||||||
|
.messageType = config.type_flags,
|
||||||
|
.pfnUserCallback = debugCallback,
|
||||||
|
.pUserData = &config,
|
||||||
|
};
|
||||||
|
|
||||||
|
return instance.createDebugUtilsMessengerEXTUnique(createInfo);
|
||||||
|
} catch (const vk::SystemError& e) {
|
||||||
|
return std::unexpected(std::format("Failed to create debug messenger: {}", e.what()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
VKAPI_ATTR VkBool32 VKAPI_CALL DebugMessenger::debugCallback(
|
||||||
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
|
void* pUserData
|
||||||
|
) {
|
||||||
|
const auto* config = static_cast<const Config*>(pUserData);
|
||||||
|
|
||||||
|
Message msg { .message = pCallbackData->pMessage,
|
||||||
|
.severity = static_cast<vk::DebugUtilsMessageSeverityFlagBitsEXT>(messageSeverity),
|
||||||
|
.type = static_cast<vk::DebugUtilsMessageTypeFlagsEXT>(messageType),
|
||||||
|
.function_name = pCallbackData->pMessageIdName
|
||||||
|
? std::optional<std::string_view>(pCallbackData->pMessageIdName)
|
||||||
|
: std::nullopt,
|
||||||
|
.id = pCallbackData->messageIdNumber };
|
||||||
|
|
||||||
|
const auto formattedMessage = formatMessage(msg);
|
||||||
|
|
||||||
|
if (config && config->use_stderr_for_errors &&
|
||||||
|
(messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)) {
|
||||||
|
std::println(stderr, "{}", formattedMessage);
|
||||||
|
} else {
|
||||||
|
std::println("{}", formattedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DebugMessenger::formatMessage(const Message& msg) -> std::string {
|
||||||
|
// Color based on severity
|
||||||
|
std::string_view colorCode = ANSI_WHITE;
|
||||||
|
std::string_view severityText;
|
||||||
|
|
||||||
|
switch (msg.severity) {
|
||||||
|
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose:
|
||||||
|
colorCode = ANSI_LIGHT_BLUE;
|
||||||
|
severityText = "VERBOSE";
|
||||||
|
break;
|
||||||
|
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo:
|
||||||
|
colorCode = ANSI_WHITE;
|
||||||
|
severityText = "INFO";
|
||||||
|
break;
|
||||||
|
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning:
|
||||||
|
colorCode = ANSI_YELLOW;
|
||||||
|
severityText = "WARNING";
|
||||||
|
break;
|
||||||
|
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eError:
|
||||||
|
colorCode = ANSI_RED;
|
||||||
|
severityText = "ERROR";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build message type string
|
||||||
|
std::string typeStr;
|
||||||
|
if (msg.type & vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral)
|
||||||
|
typeStr += "GENERAL ";
|
||||||
|
if (msg.type & vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation)
|
||||||
|
typeStr += "VALIDATION ";
|
||||||
|
if (msg.type & vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance)
|
||||||
|
typeStr += "PERFORMANCE ";
|
||||||
|
|
||||||
|
// Format the message with color and structure
|
||||||
|
return std::format(
|
||||||
|
"{}{}[{}] {} {}{}: {}{}",
|
||||||
|
colorCode,
|
||||||
|
ANSI_BOLD,
|
||||||
|
severityText,
|
||||||
|
typeStr,
|
||||||
|
msg.function_name.has_value() ? std::format("in {} ", *msg.function_name) : "",
|
||||||
|
msg.id,
|
||||||
|
msg.message,
|
||||||
|
ANSI_RESET
|
||||||
|
);
|
||||||
|
}
|
72
src/init/debug_messenger.hpp
Normal file
72
src/init/debug_messenger.hpp
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 // Use dynamic dispatch for Vulkan functions
|
||||||
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include <expected>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
#include "../util/types.hpp"
|
||||||
|
|
||||||
|
class DebugMessenger {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Configuration for debug messenger
|
||||||
|
*/
|
||||||
|
struct Config {
|
||||||
|
vk::DebugUtilsMessageSeverityFlagsEXT severity_flags;
|
||||||
|
vk::DebugUtilsMessageTypeFlagsEXT type_flags;
|
||||||
|
bool use_stderr_for_errors;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug message information
|
||||||
|
*/
|
||||||
|
struct Message {
|
||||||
|
std::string_view message;
|
||||||
|
vk::DebugUtilsMessageSeverityFlagBitsEXT severity;
|
||||||
|
vk::DebugUtilsMessageTypeFlagsEXT type;
|
||||||
|
std::optional<std::string_view> function_name;
|
||||||
|
i32 id;
|
||||||
|
};
|
||||||
|
|
||||||
|
DebugMessenger() = default;
|
||||||
|
DebugMessenger(const DebugMessenger&) = default;
|
||||||
|
DebugMessenger(DebugMessenger&&) = delete;
|
||||||
|
fn operator=(const DebugMessenger&)->DebugMessenger& = default;
|
||||||
|
fn operator=(DebugMessenger&&)->DebugMessenger& = delete;
|
||||||
|
~DebugMessenger() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a debug messenger with the specified configuration
|
||||||
|
* @param instance Vulkan instance
|
||||||
|
* @param config Debug messenger configuration
|
||||||
|
* @return Expected containing the debug messenger or an error message
|
||||||
|
*/
|
||||||
|
static fn create(
|
||||||
|
const vk::Instance& instance,
|
||||||
|
Config config = { .severity_flags = vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
|
||||||
|
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
|
||||||
|
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError,
|
||||||
|
.type_flags = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
|
||||||
|
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
|
||||||
|
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
|
||||||
|
.use_stderr_for_errors = true }
|
||||||
|
) -> std::expected<vk::UniqueDebugUtilsMessengerEXT, std::string>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||||
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
|
void* pUserData
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Formats a debug message for output
|
||||||
|
* @param msg Message information
|
||||||
|
* @return Formatted message string
|
||||||
|
*/
|
||||||
|
static fn formatMessage(const Message& msg) -> std::string;
|
||||||
|
};
|
204
src/init/device_manager.cpp
Normal file
204
src/init/device_manager.cpp
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
#include <expected>
|
||||||
|
#include <set>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
#include "device_manager.hpp"
|
||||||
|
|
||||||
|
#include "../structs/swap_chain_support_details.hpp"
|
||||||
|
|
||||||
|
struct PhysicalDeviceInfo {
|
||||||
|
vk::PhysicalDevice physical_device;
|
||||||
|
vk::SampleCountFlagBits msaa_samples;
|
||||||
|
f32 max_line_width;
|
||||||
|
bool wide_line_support;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LogicalDeviceInfo {
|
||||||
|
vk::UniqueDevice device;
|
||||||
|
vk::Queue graphics_queue;
|
||||||
|
vk::Queue present_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn DeviceManager::pickPhysicalDevice(
|
||||||
|
const vk::Instance& instance,
|
||||||
|
const vk::SurfaceKHR& surface,
|
||||||
|
std::span<const char* const> requiredExtensions
|
||||||
|
) -> std::expected<PhysicalDeviceInfo, std::string> {
|
||||||
|
// Get all available physical devices
|
||||||
|
auto devices = instance.enumeratePhysicalDevices();
|
||||||
|
|
||||||
|
if (devices.empty())
|
||||||
|
return std::unexpected("Failed to find GPUs with Vulkan support!");
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::println("Available devices:");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Find the first suitable device using ranges
|
||||||
|
auto suitableDevice = std::ranges::find_if(devices, [&](const auto& device) {
|
||||||
|
return isDeviceSuitable(device, surface, requiredExtensions);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (suitableDevice == devices.end())
|
||||||
|
return std::unexpected("Failed to find a suitable GPU!");
|
||||||
|
|
||||||
|
vk::PhysicalDeviceProperties deviceProperties = suitableDevice->getProperties();
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::println("\t{}", deviceProperties.deviceName.data());
|
||||||
|
std::println("Maximum supported line width: {}", deviceProperties.limits.lineWidthRange[1]);
|
||||||
|
std::println("Wide lines supported: {}", deviceProperties.limits.lineWidthRange[1] > 1.0F ? "yes" : "no");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return PhysicalDeviceInfo {
|
||||||
|
.physical_device = *suitableDevice,
|
||||||
|
.msaa_samples = getMaxUsableSampleCount(*suitableDevice),
|
||||||
|
.max_line_width = deviceProperties.limits.lineWidthRange[1],
|
||||||
|
.wide_line_support = deviceProperties.limits.lineWidthRange[1] > 1.0F,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DeviceManager::createLogicalDevice(
|
||||||
|
const vk::PhysicalDevice& physicalDevice,
|
||||||
|
const vk::SurfaceKHR& surface,
|
||||||
|
std::span<const char* const> requiredExtensions,
|
||||||
|
bool enableValidationLayers,
|
||||||
|
std::span<const char* const> validationLayers
|
||||||
|
) -> std::expected<LogicalDeviceInfo, std::string> {
|
||||||
|
try {
|
||||||
|
QueueFamilyIndices indices = findQueueFamilies(physicalDevice, surface);
|
||||||
|
|
||||||
|
std::set<u32> uniqueQueueFamilies = { indices.graphics_family.value(), indices.present_family.value() };
|
||||||
|
|
||||||
|
std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
|
||||||
|
f32 queuePriority = 1.0F;
|
||||||
|
|
||||||
|
// Use ranges to transform unique queue families into create infos
|
||||||
|
std::ranges::transform(uniqueQueueFamilies, std::back_inserter(queueCreateInfos), [&](u32 queueFamily) {
|
||||||
|
return vk::DeviceQueueCreateInfo {
|
||||||
|
.queueFamilyIndex = queueFamily,
|
||||||
|
.queueCount = 1,
|
||||||
|
.pQueuePriorities = &queuePriority,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
vk::PhysicalDeviceFeatures deviceFeatures {
|
||||||
|
.fillModeNonSolid = vk::True,
|
||||||
|
.wideLines = vk::True,
|
||||||
|
.samplerAnisotropy = vk::True,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::DeviceCreateInfo createInfo {
|
||||||
|
.queueCreateInfoCount = static_cast<u32>(queueCreateInfos.size()),
|
||||||
|
.pQueueCreateInfos = queueCreateInfos.data(),
|
||||||
|
.enabledExtensionCount = static_cast<u32>(requiredExtensions.size()),
|
||||||
|
.ppEnabledExtensionNames = requiredExtensions.data(),
|
||||||
|
.pEnabledFeatures = &deviceFeatures,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (enableValidationLayers) {
|
||||||
|
createInfo.enabledLayerCount = static_cast<u32>(validationLayers.size());
|
||||||
|
createInfo.ppEnabledLayerNames = validationLayers.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto device = physicalDevice.createDeviceUnique(createInfo);
|
||||||
|
auto graphicsQueue = device->getQueue(indices.graphics_family.value(), 0);
|
||||||
|
auto presentQueue = device->getQueue(indices.present_family.value(), 0);
|
||||||
|
|
||||||
|
return LogicalDeviceInfo {
|
||||||
|
.device = std::move(device),
|
||||||
|
.graphics_queue = graphicsQueue,
|
||||||
|
.present_queue = presentQueue,
|
||||||
|
};
|
||||||
|
} catch (const vk::SystemError& e) {
|
||||||
|
return std::unexpected(std::format("Failed to create logical device: {}", e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DeviceManager::getMaxUsableSampleCount(const vk::PhysicalDevice& physicalDevice
|
||||||
|
) -> vk::SampleCountFlagBits {
|
||||||
|
vk::PhysicalDeviceProperties physicalDeviceProperties = physicalDevice.getProperties();
|
||||||
|
|
||||||
|
vk::SampleCountFlags counts = physicalDeviceProperties.limits.framebufferColorSampleCounts &
|
||||||
|
physicalDeviceProperties.limits.framebufferDepthSampleCounts;
|
||||||
|
|
||||||
|
if (counts & vk::SampleCountFlagBits::e64)
|
||||||
|
return vk::SampleCountFlagBits::e64;
|
||||||
|
if (counts & vk::SampleCountFlagBits::e32)
|
||||||
|
return vk::SampleCountFlagBits::e32;
|
||||||
|
if (counts & vk::SampleCountFlagBits::e16)
|
||||||
|
return vk::SampleCountFlagBits::e16;
|
||||||
|
if (counts & vk::SampleCountFlagBits::e8)
|
||||||
|
return vk::SampleCountFlagBits::e8;
|
||||||
|
if (counts & vk::SampleCountFlagBits::e4)
|
||||||
|
return vk::SampleCountFlagBits::e4;
|
||||||
|
if (counts & vk::SampleCountFlagBits::e2)
|
||||||
|
return vk::SampleCountFlagBits::e2;
|
||||||
|
|
||||||
|
return vk::SampleCountFlagBits::e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DeviceManager::findQueueFamilies(const vk::PhysicalDevice& device, const vk::SurfaceKHR& surface)
|
||||||
|
-> QueueFamilyIndices {
|
||||||
|
QueueFamilyIndices indices;
|
||||||
|
|
||||||
|
// Get queue family properties
|
||||||
|
std::vector<vk::QueueFamilyProperties> queueFamilies = device.getQueueFamilyProperties();
|
||||||
|
|
||||||
|
// Find queue family with graphics support
|
||||||
|
for (size_t i = 0; i < queueFamilies.size(); i++) {
|
||||||
|
if (queueFamilies[i].queueFlags & vk::QueueFlagBits::eGraphics)
|
||||||
|
indices.graphics_family = static_cast<u32>(i);
|
||||||
|
|
||||||
|
// Check for presentation support
|
||||||
|
if (device.getSurfaceSupportKHR(static_cast<u32>(i), surface))
|
||||||
|
indices.present_family = static_cast<u32>(i);
|
||||||
|
|
||||||
|
if (indices.isComplete())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DeviceManager::isDeviceSuitable(
|
||||||
|
const vk::PhysicalDevice& device,
|
||||||
|
const vk::SurfaceKHR& surface,
|
||||||
|
std::span<const char* const> requiredExtensions
|
||||||
|
) -> bool {
|
||||||
|
// Check queue family support
|
||||||
|
QueueFamilyIndices indices = findQueueFamilies(device, surface);
|
||||||
|
|
||||||
|
// Check extension support
|
||||||
|
bool extensionsSupported = checkDeviceExtensionSupport(device, requiredExtensions);
|
||||||
|
|
||||||
|
// Check swap chain support
|
||||||
|
bool swapChainAdequate = false;
|
||||||
|
if (extensionsSupported) {
|
||||||
|
SwapChainSupportDetails swapChainSupport;
|
||||||
|
swapChainSupport.capabilities = device.getSurfaceCapabilitiesKHR(surface);
|
||||||
|
swapChainSupport.formats = device.getSurfaceFormatsKHR(surface);
|
||||||
|
swapChainSupport.present_modes = device.getSurfacePresentModesKHR(surface);
|
||||||
|
swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.present_modes.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check device features
|
||||||
|
vk::PhysicalDeviceFeatures supportedFeatures = device.getFeatures();
|
||||||
|
|
||||||
|
return indices.isComplete() && extensionsSupported && swapChainAdequate &&
|
||||||
|
supportedFeatures.samplerAnisotropy;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DeviceManager::checkDeviceExtensionSupport(
|
||||||
|
const vk::PhysicalDevice& device,
|
||||||
|
std::span<const char* const> requiredExtensions
|
||||||
|
) -> bool {
|
||||||
|
std::vector<vk::ExtensionProperties> availableExtensions = device.enumerateDeviceExtensionProperties();
|
||||||
|
|
||||||
|
// Use ranges to check if all required extensions are available
|
||||||
|
return std::ranges::all_of(requiredExtensions, [&](const char* required) {
|
||||||
|
return std::ranges::any_of(availableExtensions, [&](const vk::ExtensionProperties& available) {
|
||||||
|
return strcmp(required, available.extensionName) == 0;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
106
src/init/device_manager.hpp
Normal file
106
src/init/device_manager.hpp
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <expected>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
#include "../structs/queue_family_indices.hpp"
|
||||||
|
#include "../util/types.hpp"
|
||||||
|
|
||||||
|
class DeviceManager {
|
||||||
|
public:
|
||||||
|
DeviceManager() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Result type for physical device selection
|
||||||
|
*/
|
||||||
|
struct PhysicalDeviceInfo {
|
||||||
|
vk::PhysicalDevice physical_device;
|
||||||
|
vk::SampleCountFlagBits msaa_samples;
|
||||||
|
f32 max_line_width;
|
||||||
|
bool wide_line_support;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Result type for logical device creation
|
||||||
|
*/
|
||||||
|
struct LogicalDeviceInfo {
|
||||||
|
vk::UniqueDevice device;
|
||||||
|
vk::Queue graphics_queue;
|
||||||
|
vk::Queue present_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Picks a suitable physical device (GPU) for the application.
|
||||||
|
*
|
||||||
|
* @param instance Vulkan instance to use for device selection
|
||||||
|
* @param surface Surface to check for compatibility
|
||||||
|
* @param requiredExtensions List of required device extensions
|
||||||
|
* @return std::expected<PhysicalDeviceInfo, std::string> Physical device info or error message
|
||||||
|
*/
|
||||||
|
static fn pickPhysicalDevice(
|
||||||
|
const vk::Instance& instance,
|
||||||
|
const vk::SurfaceKHR& surface,
|
||||||
|
std::span<const char* const> requiredExtensions
|
||||||
|
) -> std::expected<PhysicalDeviceInfo, std::string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a logical device with the specified features.
|
||||||
|
*
|
||||||
|
* @param physicalDevice Physical device to create logical device from
|
||||||
|
* @param surface Surface to create device with
|
||||||
|
* @param requiredExtensions Device extensions to enable
|
||||||
|
* @param enableValidationLayers Whether to enable validation layers
|
||||||
|
* @param validationLayers Validation layers to enable if enabled
|
||||||
|
* @return std::expected<LogicalDeviceInfo, std::string> Logical device info or error message
|
||||||
|
*/
|
||||||
|
static fn createLogicalDevice(
|
||||||
|
const vk::PhysicalDevice& physicalDevice,
|
||||||
|
const vk::SurfaceKHR& surface,
|
||||||
|
std::span<const char* const> requiredExtensions,
|
||||||
|
bool enableValidationLayers,
|
||||||
|
std::span<const char* const> validationLayers
|
||||||
|
) -> std::expected<LogicalDeviceInfo, std::string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the maximum supported MSAA sample count.
|
||||||
|
*
|
||||||
|
* @param physicalDevice Physical device to check
|
||||||
|
* @return vk::SampleCountFlagBits Maximum supported sample count
|
||||||
|
*/
|
||||||
|
static fn getMaxUsableSampleCount(const vk::PhysicalDevice& physicalDevice) -> vk::SampleCountFlagBits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Finds queue families that support required operations.
|
||||||
|
*
|
||||||
|
* @param device Physical device to check
|
||||||
|
* @param surface Surface to check presentation support
|
||||||
|
* @return QueueFamilyIndices Indices of suitable queue families
|
||||||
|
*/
|
||||||
|
static fn findQueueFamilies(const vk::PhysicalDevice& device, const vk::SurfaceKHR& surface)
|
||||||
|
-> QueueFamilyIndices;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a physical device is suitable for the application.
|
||||||
|
*
|
||||||
|
* @param device Physical device to check
|
||||||
|
* @param surface Surface to check compatibility with
|
||||||
|
* @param requiredExtensions Required device extensions
|
||||||
|
* @return bool True if device is suitable
|
||||||
|
*/
|
||||||
|
static fn isDeviceSuitable(
|
||||||
|
const vk::PhysicalDevice& device,
|
||||||
|
const vk::SurfaceKHR& surface,
|
||||||
|
std::span<const char* const> requiredExtensions
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the device supports the required extensions.
|
||||||
|
*/
|
||||||
|
static fn checkDeviceExtensionSupport(
|
||||||
|
const vk::PhysicalDevice& device,
|
||||||
|
std::span<const char* const> requiredExtensions
|
||||||
|
) -> bool;
|
||||||
|
};
|
97
src/init/vulkan_instance.cpp
Normal file
97
src/init/vulkan_instance.cpp
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
||||||
|
|
||||||
|
#include "vulkan_instance.hpp"
|
||||||
|
|
||||||
|
#include "../util/constants.hpp"
|
||||||
|
|
||||||
|
using namespace constants;
|
||||||
|
|
||||||
|
fn VulkanInstance::create() -> vk::UniqueInstance {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Make sure validation layers are supported
|
||||||
|
if (!checkValidationLayerSupport())
|
||||||
|
throw std::runtime_error("Validation layers requested, but not available!");
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Application metadata
|
||||||
|
vk::ApplicationInfo appInfo {
|
||||||
|
.pApplicationName = "Vulkan App",
|
||||||
|
.applicationVersion = 1,
|
||||||
|
.pEngineName = "No Engine",
|
||||||
|
.engineVersion = 1,
|
||||||
|
.apiVersion = vk::ApiVersion13,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get required extensions
|
||||||
|
std::vector<const char*> extensions = getRequiredExtensions();
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::println("Available extensions:");
|
||||||
|
for (const char* extension : extensions) { std::println("\t{}", extension); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create the instance
|
||||||
|
vk::InstanceCreateInfo createInfo {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
.flags = vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR,
|
||||||
|
#endif
|
||||||
|
.pApplicationInfo = &appInfo,
|
||||||
|
#ifdef NDEBUG
|
||||||
|
.enabledLayerCount = 0,
|
||||||
|
.ppEnabledLayerNames = nullptr,
|
||||||
|
#else
|
||||||
|
.enabledLayerCount = static_cast<u32>(validationLayers.size()),
|
||||||
|
.ppEnabledLayerNames = validationLayers.data(),
|
||||||
|
#endif
|
||||||
|
.enabledExtensionCount = static_cast<u32>(extensions.size()),
|
||||||
|
.ppEnabledExtensionNames = extensions.data()
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::UniqueInstance instance = vk::createInstanceUnique(createInfo);
|
||||||
|
|
||||||
|
// Initialize the dynamic dispatcher with the instance
|
||||||
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance.get());
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn VulkanInstance::getRequiredExtensions() -> std::vector<const char*> {
|
||||||
|
// Get the required extensions from GLFW
|
||||||
|
std::span<const char*> extensionsSpan = vkfw::getRequiredInstanceExtensions();
|
||||||
|
std::vector<const char*> extensions(extensionsSpan.begin(), extensionsSpan.end());
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Add debug utils extension in debug mode
|
||||||
|
extensions.push_back(vk::EXTDebugUtilsExtensionName);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// Add required macOS extensions
|
||||||
|
extensions.push_back(vk::KHRPortabilityEnumerationExtensionName);
|
||||||
|
extensions.push_back("VK_KHR_get_physical_device_properties2");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn VulkanInstance::checkValidationLayerSupport() -> bool {
|
||||||
|
// Get available layers
|
||||||
|
std::vector<vk::LayerProperties> availableLayers = vk::enumerateInstanceLayerProperties();
|
||||||
|
|
||||||
|
// Check if all requested validation layers are available
|
||||||
|
for (const char* layerName : validationLayers) {
|
||||||
|
bool layerFound = false;
|
||||||
|
|
||||||
|
for (const vk::LayerProperties& layerProperties : availableLayers)
|
||||||
|
if (strcmp(layerName, layerProperties.layerName) == 0) {
|
||||||
|
layerFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!layerFound)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
25
src/init/vulkan_instance.hpp
Normal file
25
src/init/vulkan_instance.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define VKFW_NO_STRUCT_CONSTRUCTORS // Use aggregate initialization for GLFW structs
|
||||||
|
#include <vkfw.hpp>
|
||||||
|
|
||||||
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
#include "../util/types.hpp"
|
||||||
|
|
||||||
|
class VulkanInstance {
|
||||||
|
public:
|
||||||
|
VulkanInstance() = default;
|
||||||
|
VulkanInstance(const VulkanInstance&) = default;
|
||||||
|
VulkanInstance(VulkanInstance&&) = delete;
|
||||||
|
fn operator=(const VulkanInstance&)->VulkanInstance& = default;
|
||||||
|
fn operator=(VulkanInstance&&)->VulkanInstance& = delete;
|
||||||
|
~VulkanInstance() = default;
|
||||||
|
|
||||||
|
static fn create() -> vk::UniqueInstance;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static fn getRequiredExtensions() -> std::vector<const char*>;
|
||||||
|
static fn checkValidationLayerSupport() -> bool;
|
||||||
|
};
|
2893
src/main.cpp
2893
src/main.cpp
File diff suppressed because it is too large
Load diff
10
src/structs/camera_info.hpp
Normal file
10
src/structs/camera_info.hpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing camera information for shading.
|
||||||
|
*/
|
||||||
|
struct CameraInfo {
|
||||||
|
alignas(16) glm::vec3 position; ///< Camera position in world space
|
||||||
|
};
|
13
src/structs/light_info.hpp
Normal file
13
src/structs/light_info.hpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct containing light information for shading.
|
||||||
|
*/
|
||||||
|
struct LightInfo {
|
||||||
|
alignas(16) glm::vec3 position; ///< Light position
|
||||||
|
alignas(16) glm::vec3 color; ///< Light color
|
||||||
|
alignas(4) float ambient_strength; ///< Ambient strength
|
||||||
|
alignas(4) float specular_strength; ///< Specular strength
|
||||||
|
};
|
23
src/structs/queue_family_indices.hpp
Normal file
23
src/structs/queue_family_indices.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include "../util/types.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct to store queue family indices.
|
||||||
|
*
|
||||||
|
* This struct contains the indices of the graphics and presentation queue families.
|
||||||
|
*/
|
||||||
|
struct QueueFamilyIndices {
|
||||||
|
std::optional<u32> graphics_family; ///< Index of graphics queue family
|
||||||
|
std::optional<u32> present_family; ///< Index of presentation queue family
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if all required queue families are found.
|
||||||
|
*
|
||||||
|
* @return True if both graphics and presentation families are found, false otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] fn isComplete() const -> bool {
|
||||||
|
return graphics_family.has_value() && present_family.has_value();
|
||||||
|
}
|
||||||
|
};
|
17
src/structs/swap_chain_support_details.hpp
Normal file
17
src/structs/swap_chain_support_details.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct to hold swap chain support details.
|
||||||
|
*
|
||||||
|
* This struct contains information about the surface capabilities,
|
||||||
|
* supported formats, and presentation modes.
|
||||||
|
*/
|
||||||
|
struct SwapChainSupportDetails {
|
||||||
|
vk::SurfaceCapabilitiesKHR capabilities; ///< Surface capabilities
|
||||||
|
std::vector<vk::SurfaceFormatKHR> formats; ///< Supported surface formats
|
||||||
|
std::vector<vk::PresentModeKHR> present_modes; ///< Supported presentation modes
|
||||||
|
};
|
14
src/structs/uniform_buffer_object.hpp
Normal file
14
src/structs/uniform_buffer_object.hpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct representing a uniform buffer object.
|
||||||
|
*
|
||||||
|
* This struct holds the model, view, and projection matrices for use in shaders.
|
||||||
|
*/
|
||||||
|
struct UniformBufferObject {
|
||||||
|
alignas(16) glm::mat4 model; ///< Model transformation matrix
|
||||||
|
alignas(16) glm::mat4 view; ///< View transformation matrix
|
||||||
|
alignas(16) glm::mat4 proj; ///< Projection matrix
|
||||||
|
};
|
40
src/util/constants.hpp
Normal file
40
src/util/constants.hpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
namespace constants {
|
||||||
|
// Window dimensions
|
||||||
|
constexpr i32 WIDTH = 1920;
|
||||||
|
constexpr i32 HEIGHT = 1080;
|
||||||
|
|
||||||
|
// Camera settings
|
||||||
|
constexpr f64 CAMERA_SPEED = 1.0;
|
||||||
|
|
||||||
|
// Frame processing
|
||||||
|
constexpr i32 MAX_FRAMES_IN_FLIGHT = 2;
|
||||||
|
|
||||||
|
// Shader paths
|
||||||
|
constexpr const char* VERTEX_SHADER_PATH = "shaders/vertex.glsl";
|
||||||
|
constexpr const char* FRAGMENT_SHADER_PATH = "shaders/fragment.glsl";
|
||||||
|
constexpr const char* CROSSHAIR_VERTEX_SHADER_PATH = "shaders/crosshair_vertex.glsl";
|
||||||
|
constexpr const char* CROSSHAIR_FRAGMENT_SHADER_PATH = "shaders/crosshair_fragment.glsl";
|
||||||
|
|
||||||
|
// Validation layers
|
||||||
|
#ifndef NDEBUG
|
||||||
|
constexpr bool enableValidationLayers = true;
|
||||||
|
constexpr std::array<const char*, 1> validationLayers = { "VK_LAYER_KHRONOS_validation" };
|
||||||
|
#else
|
||||||
|
constexpr bool enableValidationLayers = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Device extensions
|
||||||
|
#ifdef __APPLE__
|
||||||
|
constexpr std::array<const char*, 2> deviceExtensions = { vk::KHRSwapchainExtensionName,
|
||||||
|
"VK_KHR_portability_subset" };
|
||||||
|
#else
|
||||||
|
constexpr std::array<const char*, 1> deviceExtensions = { vk::KHRSwapchainExtensionName };
|
||||||
|
#endif
|
||||||
|
}
|
49
src/util/crosshair.hpp
Normal file
49
src/util/crosshair.hpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
struct CrosshairVertex {
|
||||||
|
vec2 pos;
|
||||||
|
vec3 color;
|
||||||
|
|
||||||
|
static fn getBindingDescription() -> vk::VertexInputBindingDescription {
|
||||||
|
return { .binding = 0, .stride = sizeof(CrosshairVertex), .inputRate = vk::VertexInputRate::eVertex };
|
||||||
|
}
|
||||||
|
|
||||||
|
static fn getAttributeDescriptions() -> std::array<vk::VertexInputAttributeDescription, 2> {
|
||||||
|
return {
|
||||||
|
vk::VertexInputAttributeDescription { .location = 0,
|
||||||
|
.binding = 0,
|
||||||
|
.format = vk::Format::eR32G32Sfloat,
|
||||||
|
.offset = offsetof(CrosshairVertex, pos) },
|
||||||
|
vk::VertexInputAttributeDescription { .location = 1,
|
||||||
|
.binding = 0,
|
||||||
|
.format = vk::Format::eR32G32B32Sfloat,
|
||||||
|
.offset = offsetof(CrosshairVertex, color) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Crosshair vertices (in normalized device coordinates)
|
||||||
|
constexpr f32 CROSSHAIR_SIZE = 0.02F;
|
||||||
|
constexpr std::array<CrosshairVertex, 4> crosshairVertices = {
|
||||||
|
// Horizontal line
|
||||||
|
CrosshairVertex { { -CROSSHAIR_SIZE * (9.0F / 16.0F), 0.0F }, { 1.0F, 1.0F, 1.0F } }, // Left
|
||||||
|
CrosshairVertex { { CROSSHAIR_SIZE * (9.0F / 16.0F), 0.0F }, { 1.0F, 1.0F, 1.0F } }, // Right
|
||||||
|
// Vertical line
|
||||||
|
CrosshairVertex { { 0.0F, -CROSSHAIR_SIZE }, { 1.0F, 1.0F, 1.0F } }, // Bottom
|
||||||
|
CrosshairVertex { { 0.0F, CROSSHAIR_SIZE }, { 1.0F, 1.0F, 1.0F } } // Top
|
||||||
|
};
|
||||||
|
|
||||||
|
// Indices for drawing the crosshair lines
|
||||||
|
constexpr std::array<u16, 4> crosshairIndices = {
|
||||||
|
0,
|
||||||
|
1, // Horizontal line
|
||||||
|
2,
|
||||||
|
3 // Vertical line
|
||||||
|
};
|
File diff suppressed because it is too large
Load diff
208
src/util/shaders.hpp
Normal file
208
src/util/shaders.hpp
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
/**
|
||||||
|
* @file shaders.hpp
|
||||||
|
* @brief SPIR-V shader compilation and caching system.
|
||||||
|
*
|
||||||
|
* This file provides functionality for compiling GLSL shaders to SPIR-V and
|
||||||
|
* managing a shader cache system. It supports automatic recompilation when
|
||||||
|
* source files are modified and efficient caching of compiled shaders.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <ios>
|
||||||
|
#include <shaderc/shaderc.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles shader compilation and caching operations.
|
||||||
|
*
|
||||||
|
* This class provides static methods for compiling GLSL shaders to SPIR-V
|
||||||
|
* and managing a cache system. It automatically detects when shaders need
|
||||||
|
* to be recompiled based on file timestamps and provides efficient caching
|
||||||
|
* of compiled shader binaries.
|
||||||
|
*/
|
||||||
|
class ShaderCompiler {
|
||||||
|
public:
|
||||||
|
ShaderCompiler() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compiles or retrieves a cached SPIR-V shader.
|
||||||
|
*
|
||||||
|
* @param shaderPath Path to the GLSL shader source file
|
||||||
|
* @param kind Type of shader (vertex, fragment, compute, etc.)
|
||||||
|
* @return std::vector<u32> Compiled SPIR-V binary code
|
||||||
|
* @throws std::runtime_error If shader compilation fails or file is not found
|
||||||
|
*
|
||||||
|
* This function performs the following steps:
|
||||||
|
* 1. Checks if a cached version exists and is up-to-date
|
||||||
|
* 2. Loads from cache if available and valid
|
||||||
|
* 3. Otherwise, compiles the shader from source
|
||||||
|
* 4. Caches the newly compiled shader for future use
|
||||||
|
* 5. Returns the SPIR-V binary code
|
||||||
|
*/
|
||||||
|
static fn getCompiledShader(const std::filesystem::path& shaderPath, const shaderc_shader_kind& kind)
|
||||||
|
-> std::vector<u32> {
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// Convert to absolute path if relative
|
||||||
|
filesystem::path absPath = filesystem::absolute(shaderPath);
|
||||||
|
|
||||||
|
if (!filesystem::exists(absPath))
|
||||||
|
throw runtime_error("Shader file not found: " + absPath.string());
|
||||||
|
|
||||||
|
const string shaderName = absPath.stem().string();
|
||||||
|
const filesystem::path cacheFile = getCacheFilePath(shaderName);
|
||||||
|
|
||||||
|
// Check if we need to recompile by comparing timestamps
|
||||||
|
if (filesystem::exists(cacheFile)) {
|
||||||
|
const auto sourceTime = filesystem::last_write_time(absPath);
|
||||||
|
const auto cacheTime = filesystem::last_write_time(cacheFile);
|
||||||
|
|
||||||
|
if (cacheTime >= sourceTime) {
|
||||||
|
// Cache is up to date, load it
|
||||||
|
vector<u32> spirvCode = loadCachedShader(cacheFile);
|
||||||
|
if (!spirvCode.empty()) {
|
||||||
|
std::println("Loaded shader from cache: {}", cacheFile.string());
|
||||||
|
return spirvCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to compile the shader
|
||||||
|
std::println("Compiling shader: {}", absPath.string());
|
||||||
|
|
||||||
|
// Read shader source
|
||||||
|
ifstream file(absPath);
|
||||||
|
if (!file)
|
||||||
|
throw runtime_error("Failed to open shader file: " + absPath.string());
|
||||||
|
|
||||||
|
string shaderSource((istreambuf_iterator<char>(file)), istreambuf_iterator<char>());
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
// Compile the shader
|
||||||
|
vector<u32> spirvCode = compileShader(shaderSource.c_str(), kind);
|
||||||
|
|
||||||
|
if (spirvCode.empty())
|
||||||
|
throw runtime_error("Shader compilation failed for: " + absPath.string());
|
||||||
|
|
||||||
|
// Cache the compiled SPIR-V binary
|
||||||
|
saveCompiledShader(spirvCode, cacheFile.string());
|
||||||
|
return spirvCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Determines the platform-specific shader cache directory.
|
||||||
|
*
|
||||||
|
* @param shaderName Base name of the shader file
|
||||||
|
* @return std::filesystem::path Full path to the cache file
|
||||||
|
*
|
||||||
|
* Cache locations:
|
||||||
|
* - Windows: %LOCALAPPDATA%/VulkanApp/Shaders/
|
||||||
|
* - macOS: ~/Library/Application Support/VulkanApp/Shaders/
|
||||||
|
* - Linux: ~/.local/share/VulkanApp/Shaders/
|
||||||
|
*
|
||||||
|
* The directory is created if it doesn't exist.
|
||||||
|
*/
|
||||||
|
static fn getCacheFilePath(const string& shaderName) -> std::filesystem::path {
|
||||||
|
using namespace std::filesystem;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
path cacheDir = path(getenv("LOCALAPPDATA")) / "VulkanApp" / "Shaders";
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
path cacheDir = path(getenv("HOME")) / "Library" / "Application Support" / "VulkanApp" / "Shaders";
|
||||||
|
#else // Assume Linux or other UNIX-like systems
|
||||||
|
path cacheDir = path(getenv("HOME")) / ".local" / "share" / "VulkanApp" / "Shaders";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!exists(cacheDir))
|
||||||
|
create_directories(cacheDir);
|
||||||
|
|
||||||
|
return cacheDir / (shaderName + ".spv");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Loads a cached SPIR-V shader from disk.
|
||||||
|
*
|
||||||
|
* @param cachePath Path to the cached shader file
|
||||||
|
* @return std::vector<u32> SPIR-V binary code, empty if loading fails
|
||||||
|
*
|
||||||
|
* Reads the binary SPIR-V data from the cache file. Returns an empty
|
||||||
|
* vector if the file cannot be opened or read properly.
|
||||||
|
*/
|
||||||
|
static fn loadCachedShader(const std::filesystem::path& cachePath) -> std::vector<u32> {
|
||||||
|
std::ifstream file(cachePath, std::ios::binary);
|
||||||
|
if (!file.is_open())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// Read file size
|
||||||
|
file.seekg(0, std::ios::end);
|
||||||
|
const std::streamoff fileSize = file.tellg();
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
// Allocate buffer and read data
|
||||||
|
std::vector<u32> buffer(static_cast<u32>(fileSize) / sizeof(u32));
|
||||||
|
file.read(std::bit_cast<char*>(buffer.data()), fileSize);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compiles GLSL source code to SPIR-V.
|
||||||
|
*
|
||||||
|
* @param source GLSL shader source code
|
||||||
|
* @param kind Type of shader being compiled
|
||||||
|
* @return std::vector<u32> Compiled SPIR-V binary code
|
||||||
|
*
|
||||||
|
* Uses the shaderc library to compile GLSL to SPIR-V. The compilation
|
||||||
|
* is performed with optimization level set to performance and generates
|
||||||
|
* debug information in debug builds.
|
||||||
|
*/
|
||||||
|
static fn compileShader(const char* source, shaderc_shader_kind kind) -> std::vector<u32> {
|
||||||
|
shaderc::Compiler compiler;
|
||||||
|
shaderc::CompileOptions options;
|
||||||
|
|
||||||
|
// Set compilation options
|
||||||
|
#ifdef NDEBUG
|
||||||
|
options.SetOptimizationLevel(shaderc_optimization_level_performance);
|
||||||
|
#else
|
||||||
|
options.SetOptimizationLevel(shaderc_optimization_level_zero);
|
||||||
|
options.SetGenerateDebugInfo();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Compile the shader
|
||||||
|
shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv(source, kind, "shader", options);
|
||||||
|
|
||||||
|
if (module.GetCompilationStatus() != shaderc_compilation_status_success)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return { module.cbegin(), module.cend() };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Saves compiled SPIR-V code to the cache.
|
||||||
|
*
|
||||||
|
* @param spirv Compiled SPIR-V binary code
|
||||||
|
* @param cachePath Path where the cache file should be saved
|
||||||
|
* @return bool True if save was successful, false otherwise
|
||||||
|
*
|
||||||
|
* Writes the SPIR-V binary to disk for future use. Creates any
|
||||||
|
* necessary parent directories if they don't exist.
|
||||||
|
*/
|
||||||
|
static fn saveCompiledShader(const std::vector<u32>& spirv, const std::string& cachePath) -> bool {
|
||||||
|
std::ofstream file(cachePath, std::ios::binary);
|
||||||
|
if (!file.is_open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
file.write(
|
||||||
|
std::bit_cast<const char*>(spirv.data()), static_cast<std::streamsize>(spirv.size() * sizeof(u32))
|
||||||
|
);
|
||||||
|
|
||||||
|
return file.good();
|
||||||
|
}
|
||||||
|
};
|
128
src/util/types.h
128
src/util/types.h
|
@ -1,128 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#define fn auto
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef u8
|
|
||||||
* @brief Represents an 8-bit unsigned integer.
|
|
||||||
*
|
|
||||||
* This type alias is used for 8-bit unsigned integers, ranging from 0 to 255.
|
|
||||||
* It is based on the std::uint8_t type.
|
|
||||||
*/
|
|
||||||
using u8 = std::uint8_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef u16
|
|
||||||
* @brief Represents a 16-bit unsigned integer.
|
|
||||||
*
|
|
||||||
* This type alias is used for 16-bit unsigned integers, ranging from 0 to 65,535.
|
|
||||||
* It is based on the std::uint16_t type.
|
|
||||||
*/
|
|
||||||
using u16 = std::uint16_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef u32
|
|
||||||
* @brief Represents a 32-bit unsigned integer.
|
|
||||||
*
|
|
||||||
* This type alias is used for 32-bit unsigned integers, ranging from 0 to 4,294,967,295.
|
|
||||||
* It is based on the std::uint32_t type.
|
|
||||||
*/
|
|
||||||
using u32 = std::uint32_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef u64
|
|
||||||
* @brief Represents a 64-bit unsigned integer.
|
|
||||||
*
|
|
||||||
* This type alias is used for 64-bit unsigned integers, ranging from 0 to
|
|
||||||
* 18,446,744,073,709,551,615. It is based on the std::uint64_t type.
|
|
||||||
*/
|
|
||||||
using u64 = std::uint64_t;
|
|
||||||
|
|
||||||
// Type Aliases for Signed Integers
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef i8
|
|
||||||
* @brief Represents an 8-bit signed integer.
|
|
||||||
*
|
|
||||||
* This type alias is used for 8-bit signed integers, ranging from -128 to 127.
|
|
||||||
* It is based on the std::int8_t type.
|
|
||||||
*/
|
|
||||||
using i8 = std::int8_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef i16
|
|
||||||
* @brief Represents a 16-bit signed integer.
|
|
||||||
*
|
|
||||||
* This type alias is used for 16-bit signed integers, ranging from -32,768 to 32,767.
|
|
||||||
* It is based on the std::int16_t type.
|
|
||||||
*/
|
|
||||||
using i16 = std::int16_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef i32
|
|
||||||
* @brief Represents a 32-bit signed integer.
|
|
||||||
*
|
|
||||||
* This type alias is used for 32-bit signed integers, ranging from -2,147,483,648 to 2,147,483,647.
|
|
||||||
* It is based on the std::int32_t type.
|
|
||||||
*/
|
|
||||||
using i32 = std::int32_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef i64
|
|
||||||
* @brief Represents a 64-bit signed integer.
|
|
||||||
*
|
|
||||||
* This type alias is used for 64-bit signed integers, ranging from -9,223,372,036,854,775,808 to
|
|
||||||
* 9,223,372,036,854,775,807. It is based on the std::int64_t type.
|
|
||||||
*/
|
|
||||||
using i64 = std::int64_t;
|
|
||||||
|
|
||||||
// Type Aliases for Floating-Point Numbers
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef f32
|
|
||||||
* @brief Represents a 32-bit floating-point number.
|
|
||||||
*
|
|
||||||
* This type alias is used for 32-bit floating-point numbers, which follow the IEEE 754 standard.
|
|
||||||
* It is based on the float type.
|
|
||||||
*/
|
|
||||||
using f32 = float;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef f64
|
|
||||||
* @brief Represents a 64-bit floating-point number.
|
|
||||||
*
|
|
||||||
* This type alias is used for 64-bit floating-point numbers, which follow the IEEE 754 standard.
|
|
||||||
* It is based on the double type.
|
|
||||||
*/
|
|
||||||
using f64 = double;
|
|
||||||
|
|
||||||
// Type Aliases for Size Types
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef usize
|
|
||||||
* @brief Represents an unsigned size type.
|
|
||||||
*
|
|
||||||
* This type alias is used for representing the size of objects in bytes.
|
|
||||||
* It is based on the std::size_t type, which is the result type of the sizeof operator.
|
|
||||||
*/
|
|
||||||
using usize = std::size_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef isize
|
|
||||||
* @brief Represents a signed size type.
|
|
||||||
*
|
|
||||||
* This type alias is used for representing pointer differences.
|
|
||||||
* It is based on the std::ptrdiff_t type, which is the signed integer type returned when
|
|
||||||
* subtracting two pointers.
|
|
||||||
*/
|
|
||||||
using isize = std::ptrdiff_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef string
|
|
||||||
* @brief Represents a string.
|
|
||||||
*/
|
|
||||||
using string = std::string;
|
|
152
src/util/types.hpp
Normal file
152
src/util/types.hpp
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/**
|
||||||
|
* @file types.hpp
|
||||||
|
* @brief Core type definitions and aliases for the project.
|
||||||
|
*
|
||||||
|
* This file provides a centralized location for type definitions used throughout
|
||||||
|
* the project. It includes fixed-width integer types, floating-point types, and
|
||||||
|
* commonly used GLM vector types. The type aliases are designed to improve code
|
||||||
|
* readability and ensure consistent type usage across the codebase.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define fn auto
|
||||||
|
|
||||||
|
// Integer Types
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 8-bit unsigned integer.
|
||||||
|
* @details Range: 0 to 255
|
||||||
|
* Used for byte-level operations and color channel values.
|
||||||
|
*/
|
||||||
|
using u8 = std::uint8_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 16-bit unsigned integer.
|
||||||
|
* @details Range: 0 to 65,535
|
||||||
|
* Used for texture coordinates and small indices.
|
||||||
|
*/
|
||||||
|
using u16 = std::uint16_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 32-bit unsigned integer.
|
||||||
|
* @details Range: 0 to 4,294,967,295
|
||||||
|
* Used for array sizes, indices, and flags.
|
||||||
|
*/
|
||||||
|
using u32 = std::uint32_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 64-bit unsigned integer.
|
||||||
|
* @details Range: 0 to 18,446,744,073,709,551,615
|
||||||
|
* Used for large indices and timestamps.
|
||||||
|
*/
|
||||||
|
using u64 = std::uint64_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 8-bit signed integer.
|
||||||
|
* @details Range: -128 to 127
|
||||||
|
* Used for small signed values and relative offsets.
|
||||||
|
*/
|
||||||
|
using i8 = std::int8_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 16-bit signed integer.
|
||||||
|
* @details Range: -32,768 to 32,767
|
||||||
|
* Used for medium-range signed values.
|
||||||
|
*/
|
||||||
|
using i16 = std::int16_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 32-bit signed integer.
|
||||||
|
* @details Range: -2,147,483,648 to 2,147,483,647
|
||||||
|
* Primary signed integer type for general use.
|
||||||
|
*/
|
||||||
|
using i32 = std::int32_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 64-bit signed integer.
|
||||||
|
* @details Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
|
||||||
|
* Used for large signed values and time calculations.
|
||||||
|
*/
|
||||||
|
using i64 = std::int64_t;
|
||||||
|
|
||||||
|
// Floating-Point Types
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 32-bit floating-point number.
|
||||||
|
* @details IEEE 754 single-precision
|
||||||
|
* Used for graphics calculations, positions, and colors.
|
||||||
|
*/
|
||||||
|
using f32 = float;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 64-bit floating-point number.
|
||||||
|
* @details IEEE 754 double-precision
|
||||||
|
* Used for high-precision calculations and physics.
|
||||||
|
*/
|
||||||
|
using f64 = double;
|
||||||
|
|
||||||
|
// Size Types
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unsigned size type.
|
||||||
|
* @details Platform-dependent size (32/64-bit)
|
||||||
|
* Used for memory sizes and container sizes.
|
||||||
|
*/
|
||||||
|
using usize = std::size_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Signed size type.
|
||||||
|
* @details Platform-dependent size (32/64-bit)
|
||||||
|
* Used for pointer arithmetic and container differences.
|
||||||
|
*/
|
||||||
|
using isize = std::ptrdiff_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief String type alias.
|
||||||
|
* @details Standard string type for text handling.
|
||||||
|
*/
|
||||||
|
using string = std::string;
|
||||||
|
|
||||||
|
// GLM Vector Types
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 2D vector with 32-bit float components.
|
||||||
|
* @details Used for 2D positions, texture coordinates.
|
||||||
|
*/
|
||||||
|
using vec2 = glm::f32vec2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 3D vector with 32-bit float components.
|
||||||
|
* @details Used for 3D positions, colors, normals.
|
||||||
|
*/
|
||||||
|
using vec3 = glm::f32vec3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 4D vector with 32-bit float components.
|
||||||
|
* @details Used for homogeneous coordinates, quaternions.
|
||||||
|
*/
|
||||||
|
using vec4 = glm::f32vec4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 2D vector with 64-bit float components.
|
||||||
|
* @details Used for high-precision 2D calculations.
|
||||||
|
*/
|
||||||
|
using dvec2 = glm::f64vec2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 3D vector with 64-bit float components.
|
||||||
|
* @details Used for high-precision 3D positions and directions.
|
||||||
|
*/
|
||||||
|
using dvec3 = glm::f64vec3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 4D vector with 64-bit float components.
|
||||||
|
* @details Used for high-precision homogeneous coordinates.
|
||||||
|
*/
|
||||||
|
using dvec4 = glm::f64vec4;
|
140
src/util/unique_image.hpp
Normal file
140
src/util/unique_image.hpp
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
/**
|
||||||
|
* @file unique_image.hpp
|
||||||
|
* @brief Provides RAII wrapper for image loading and management.
|
||||||
|
*
|
||||||
|
* This file implements a RAII-compliant image handling class that uses stb_image
|
||||||
|
* for loading various image formats. It ensures proper resource management and
|
||||||
|
* provides a safe interface for image data access.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include <stb_image.h>
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
namespace stb {
|
||||||
|
/**
|
||||||
|
* @brief RAII wrapper for image data loaded via stb_image.
|
||||||
|
*
|
||||||
|
* This class provides safe resource management for loaded images, ensuring proper
|
||||||
|
* cleanup of image data. It supports move semantics but prevents copying to maintain
|
||||||
|
* single ownership of image resources.
|
||||||
|
*/
|
||||||
|
class UniqueImage {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructs a UniqueImage by loading from file.
|
||||||
|
*
|
||||||
|
* @param path Filesystem path to the image file.
|
||||||
|
* @throws std::runtime_error If image loading fails.
|
||||||
|
*
|
||||||
|
* Automatically loads the image data from the specified file using stb_image.
|
||||||
|
* The image data is stored in RGBA format with 8 bits per channel.
|
||||||
|
*/
|
||||||
|
UniqueImage(const std::filesystem::path& path) { load(path.string().c_str()); }
|
||||||
|
|
||||||
|
// Prevent copying to maintain single ownership
|
||||||
|
UniqueImage(const UniqueImage&) = delete;
|
||||||
|
fn operator=(const UniqueImage&)->UniqueImage& = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor for transferring image ownership.
|
||||||
|
*
|
||||||
|
* @param other Source UniqueImage to move from.
|
||||||
|
*
|
||||||
|
* Transfers ownership of image data from another UniqueImage instance,
|
||||||
|
* leaving the source in a valid but empty state.
|
||||||
|
*/
|
||||||
|
UniqueImage(UniqueImage&& other) noexcept
|
||||||
|
: mData(other.mData),
|
||||||
|
mWidth(static_cast<i32>(other.mWidth)),
|
||||||
|
mHeight(static_cast<i32>(other.mHeight)),
|
||||||
|
mChannels(static_cast<i32>(other.mChannels)) {
|
||||||
|
other.mData = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move assignment operator for transferring image ownership.
|
||||||
|
*
|
||||||
|
* @param other Source UniqueImage to move from.
|
||||||
|
* @return Reference to this object.
|
||||||
|
*
|
||||||
|
* Safely transfers ownership of image data, ensuring proper cleanup of
|
||||||
|
* existing resources before the transfer.
|
||||||
|
*/
|
||||||
|
fn operator=(UniqueImage&& other) noexcept -> UniqueImage& {
|
||||||
|
if (this != &other) {
|
||||||
|
if (mData)
|
||||||
|
stbi_image_free(mData);
|
||||||
|
|
||||||
|
mData = other.mData;
|
||||||
|
mWidth = static_cast<i32>(other.mWidth);
|
||||||
|
mHeight = static_cast<i32>(other.mHeight);
|
||||||
|
mChannels = static_cast<i32>(other.mChannels);
|
||||||
|
other.mData = nullptr;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor that ensures proper cleanup of image resources.
|
||||||
|
*
|
||||||
|
* Automatically frees the image data using stb_image_free when the
|
||||||
|
* object goes out of scope.
|
||||||
|
*/
|
||||||
|
~UniqueImage() {
|
||||||
|
if (mData)
|
||||||
|
stbi_image_free(mData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get raw pointer to image data.
|
||||||
|
* @return Pointer to the raw image data in memory.
|
||||||
|
*
|
||||||
|
* The data is stored in row-major order with either RGB or RGBA format,
|
||||||
|
* depending on the source image.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] fn getData() const -> u8* { return mData; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get image width in pixels.
|
||||||
|
* @return Width of the image.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] fn getWidth() const -> i32 { return mWidth; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get image height in pixels.
|
||||||
|
* @return Height of the image.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] fn getHeight() const -> i32 { return mHeight; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get number of color channels.
|
||||||
|
* @return Number of channels (e.g., 3 for RGB, 4 for RGBA).
|
||||||
|
*/
|
||||||
|
[[nodiscard]] fn getChannels() const -> i32 { return mChannels; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Internal helper function to load image data.
|
||||||
|
*
|
||||||
|
* @param path Path to the image file.
|
||||||
|
* @throws std::runtime_error If image loading fails.
|
||||||
|
*
|
||||||
|
* Uses stb_image to load the image data, automatically detecting the
|
||||||
|
* format and number of channels from the file.
|
||||||
|
*/
|
||||||
|
fn load(const char* path) -> void {
|
||||||
|
mData = stbi_load(path, &mWidth, &mHeight, &mChannels, STBI_rgb_alpha);
|
||||||
|
if (!mData)
|
||||||
|
throw std::runtime_error(std::format("Failed to load texture image: {}", path));
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* mData = nullptr; ///< Raw image data in memory
|
||||||
|
i32 mWidth = 0; ///< Image width in pixels
|
||||||
|
i32 mHeight = 0; ///< Image height in pixels
|
||||||
|
i32 mChannels = 0; ///< Number of color channels
|
||||||
|
};
|
||||||
|
}
|
124
src/util/vertex.hpp
Normal file
124
src/util/vertex.hpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/**
|
||||||
|
* @file vertex.hpp
|
||||||
|
* @brief Defines the vertex structure and its associated utilities for 3D rendering.
|
||||||
|
*
|
||||||
|
* This file contains the Vertex structure used for 3D model representation in the Vulkan
|
||||||
|
* graphics pipeline. It includes position, color, texture coordinate, and normal data, along with
|
||||||
|
* Vulkan-specific descriptors for vertex input handling.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtx/hash.hpp>
|
||||||
|
|
||||||
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Represents a vertex in 3D space with color, texture, and normal information.
|
||||||
|
*
|
||||||
|
* This structure defines a vertex with all its attributes required for rendering,
|
||||||
|
* including position in 3D space, RGB color, texture coordinates, and normal vector. It also
|
||||||
|
* provides methods for Vulkan vertex input configuration.
|
||||||
|
*/
|
||||||
|
struct Vertex {
|
||||||
|
glm::vec3 pos; ///< Position of the vertex in 3D space (x, y, z)
|
||||||
|
glm::vec3 color; ///< RGB color values, each component in range [0, 1]
|
||||||
|
glm::vec2 tex_coord; ///< Texture coordinates (u, v) for texture mapping
|
||||||
|
glm::vec3 normal; ///< Normal vector of the vertex
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides the vertex binding description for Vulkan.
|
||||||
|
*
|
||||||
|
* @return vk::VertexInputBindingDescription Describes how to bind vertex data to GPU memory.
|
||||||
|
*
|
||||||
|
* The binding description specifies:
|
||||||
|
* - Binding index (0)
|
||||||
|
* - Stride (size of one vertex)
|
||||||
|
* - Input rate (per-vertex data)
|
||||||
|
*/
|
||||||
|
static fn getBindingDescription() -> vk::VertexInputBindingDescription {
|
||||||
|
return vk::VertexInputBindingDescription {
|
||||||
|
.binding = 0,
|
||||||
|
.stride = sizeof(Vertex),
|
||||||
|
.inputRate = vk::VertexInputRate::eVertex,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides attribute descriptions for vertex data interpretation.
|
||||||
|
*
|
||||||
|
* @return std::array<vk::VertexInputAttributeDescription, 4> Array of descriptions for position, color,
|
||||||
|
* texture coordinates, and normal.
|
||||||
|
*
|
||||||
|
* The attribute descriptions specify:
|
||||||
|
* - Location indices (0 for position, 1 for color, 2 for texture coordinates, 3 for normal)
|
||||||
|
* - Binding point (0)
|
||||||
|
* - Data format (R32G32B32 for vec3, R32G32 for vec2)
|
||||||
|
* - Offset of each attribute in the vertex structure
|
||||||
|
*/
|
||||||
|
static fn getAttributeDescriptions() -> std::array<vk::VertexInputAttributeDescription, 4> {
|
||||||
|
return {
|
||||||
|
vk::VertexInputAttributeDescription {
|
||||||
|
.location = 0,
|
||||||
|
.binding = 0,
|
||||||
|
.format = vk::Format::eR32G32B32Sfloat,
|
||||||
|
.offset = offsetof(Vertex, pos),
|
||||||
|
},
|
||||||
|
vk::VertexInputAttributeDescription {
|
||||||
|
.location = 1,
|
||||||
|
.binding = 0,
|
||||||
|
.format = vk::Format::eR32G32B32Sfloat,
|
||||||
|
.offset = offsetof(Vertex, color),
|
||||||
|
},
|
||||||
|
vk::VertexInputAttributeDescription {
|
||||||
|
.location = 2,
|
||||||
|
.binding = 0,
|
||||||
|
.format = vk::Format::eR32G32Sfloat,
|
||||||
|
.offset = offsetof(Vertex, tex_coord),
|
||||||
|
},
|
||||||
|
vk::VertexInputAttributeDescription {
|
||||||
|
.location = 3,
|
||||||
|
.binding = 0,
|
||||||
|
.format = vk::Format::eR32G32B32Sfloat,
|
||||||
|
.offset = offsetof(Vertex, normal),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compares two vertices for equality.
|
||||||
|
*
|
||||||
|
* @param other The vertex to compare with.
|
||||||
|
* @return bool True if vertices are identical in position, color, texture coordinates, and normal.
|
||||||
|
*/
|
||||||
|
fn operator==(const Vertex& other) const->bool {
|
||||||
|
return pos == other.pos && color == other.color && tex_coord == other.tex_coord && normal == other.normal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
/**
|
||||||
|
* @brief Hash function specialization for Vertex type.
|
||||||
|
*
|
||||||
|
* This specialization allows Vertex objects to be used as keys in unordered containers.
|
||||||
|
* The hash combines position, color, texture coordinate, and normal data using bit operations
|
||||||
|
* to create a unique hash value.
|
||||||
|
*/
|
||||||
|
template <>
|
||||||
|
struct hash<Vertex> {
|
||||||
|
/**
|
||||||
|
* @brief Computes hash value for a vertex.
|
||||||
|
*
|
||||||
|
* @param vertex The vertex to hash.
|
||||||
|
* @return size_t Hash value combining all vertex attributes.
|
||||||
|
*/
|
||||||
|
fn operator()(Vertex const& vertex) const->size_t {
|
||||||
|
return ((hash<glm::vec3>()(vertex.pos) ^ (hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^
|
||||||
|
(hash<glm::vec2>()(vertex.tex_coord) << 1) ^ (hash<glm::vec3>()(vertex.normal) << 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
76
src/window/window_manager.cpp
Normal file
76
src/window/window_manager.cpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#include <vkfw.hpp>
|
||||||
|
|
||||||
|
#include "window_manager.hpp"
|
||||||
|
|
||||||
|
#include "../util/constants.hpp"
|
||||||
|
|
||||||
|
using namespace constants;
|
||||||
|
|
||||||
|
fn WindowManager::create(const char* title, const WindowCallbacks& callbacks)
|
||||||
|
-> std::tuple<vkfw::UniqueInstance, vkfw::UniqueWindow> {
|
||||||
|
// Initialize GLFW
|
||||||
|
vkfw::UniqueInstance instance = vkfw::initUnique();
|
||||||
|
|
||||||
|
// Don't create an OpenGL context
|
||||||
|
vkfw::WindowHints hints;
|
||||||
|
hints.clientAPI = vkfw::ClientAPI::eNone;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// Required for macOS
|
||||||
|
hints.cocoaRetinaFramebuffer = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create window
|
||||||
|
vkfw::UniqueWindow window = vkfw::createWindowUnique(WIDTH, HEIGHT, title, hints);
|
||||||
|
|
||||||
|
// Get the primary monitor and its resolution
|
||||||
|
vkfw::Monitor primaryMonitor = vkfw::getPrimaryMonitor();
|
||||||
|
const GLFWvidmode* videoMode = primaryMonitor.getVideoMode();
|
||||||
|
|
||||||
|
// Calculate window position to center it
|
||||||
|
i32 xpos = (videoMode->width - WIDTH) / 2;
|
||||||
|
i32 ypos = (videoMode->height - HEIGHT) / 2;
|
||||||
|
|
||||||
|
// Set window position
|
||||||
|
window->setPos(xpos, ypos);
|
||||||
|
|
||||||
|
// Configure cursor for FPS-style camera control
|
||||||
|
window->set<vkfw::InputMode::eCursor>(vkfw::CursorMode::eDisabled);
|
||||||
|
|
||||||
|
// Set up callbacks
|
||||||
|
if (callbacks.on_cursor_move)
|
||||||
|
window->callbacks()->on_cursor_move = callbacks.on_cursor_move;
|
||||||
|
|
||||||
|
if (callbacks.on_key)
|
||||||
|
window->callbacks()->on_key = callbacks.on_key;
|
||||||
|
|
||||||
|
if (callbacks.on_mouse_button)
|
||||||
|
window->callbacks()->on_mouse_button = callbacks.on_mouse_button;
|
||||||
|
|
||||||
|
if (callbacks.on_window_resize)
|
||||||
|
window->callbacks()->on_window_resize = callbacks.on_window_resize;
|
||||||
|
|
||||||
|
return std::make_tuple(std::move(instance), std::move(window));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn WindowManager::getRequiredExtensions() -> std::vector<const char*> {
|
||||||
|
// Get the required extensions from GLFW
|
||||||
|
std::span<const char*> extensionsSpan = vkfw::getRequiredInstanceExtensions();
|
||||||
|
return { extensionsSpan.begin(), extensionsSpan.end() };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn WindowManager::getFramebufferSize(const vkfw::Window& window) -> std::pair<i32, i32> {
|
||||||
|
return window.getFramebufferSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn WindowManager::setTitle(const vkfw::Window& window, const std::string& title) -> void {
|
||||||
|
window.setTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn WindowManager::setCursorMode(const vkfw::Window& window, vkfw::CursorMode mode) -> void {
|
||||||
|
window.set<vkfw::InputMode::eCursor>(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn WindowManager::setPosition(const vkfw::Window& window, i32 xpos, i32 ypos) -> void {
|
||||||
|
window.setPos(xpos, ypos);
|
||||||
|
}
|
72
src/window/window_manager.hpp
Normal file
72
src/window/window_manager.hpp
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define VKFW_NO_STRUCT_CONSTRUCTORS // Use aggregate initialization for GLFW structs
|
||||||
|
#include <vkfw.hpp>
|
||||||
|
|
||||||
|
#include "../util/types.hpp"
|
||||||
|
|
||||||
|
struct WindowCallbacks {
|
||||||
|
std::function<void(const vkfw::Window&, f64, f64)> on_cursor_move;
|
||||||
|
std::function<
|
||||||
|
void(const vkfw::Window&, const vkfw::Key&, i32, const vkfw::KeyAction&, const vkfw::ModifierKeyFlags&)>
|
||||||
|
on_key;
|
||||||
|
std::function<
|
||||||
|
void(const vkfw::Window&, const vkfw::MouseButton&, const vkfw::MouseButtonAction&, const vkfw::ModifierKeyFlags&)>
|
||||||
|
on_mouse_button;
|
||||||
|
std::function<void(const vkfw::Window&, usize, usize)> on_window_resize;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WindowManager {
|
||||||
|
public:
|
||||||
|
WindowManager() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a window with the specified dimensions and title.
|
||||||
|
*
|
||||||
|
* @param title Window title
|
||||||
|
* @param callbacks Window callbacks
|
||||||
|
* @return vkfw::UniqueWindow Unique pointer to the created window
|
||||||
|
*/
|
||||||
|
static fn create(const char* title, const WindowCallbacks& callbacks)
|
||||||
|
-> std::tuple<vkfw::UniqueInstance, vkfw::UniqueWindow>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the required instance extensions for window surface creation.
|
||||||
|
*
|
||||||
|
* @return std::vector<const char*> List of required extensions
|
||||||
|
*/
|
||||||
|
static fn getRequiredExtensions() -> std::vector<const char*>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the framebuffer size of the window.
|
||||||
|
*
|
||||||
|
* @param window GLFW window
|
||||||
|
* @return std::pair<i32, i32> Width and height of the framebuffer
|
||||||
|
*/
|
||||||
|
static fn getFramebufferSize(const vkfw::Window& window) -> std::pair<i32, i32>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the window title.
|
||||||
|
*
|
||||||
|
* @param window GLFW window
|
||||||
|
* @param title New window title
|
||||||
|
*/
|
||||||
|
static fn setTitle(const vkfw::Window& window, const std::string& title) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the cursor mode.
|
||||||
|
*
|
||||||
|
* @param window GLFW window
|
||||||
|
* @param mode Cursor mode (Normal or Disabled)
|
||||||
|
*/
|
||||||
|
static fn setCursorMode(const vkfw::Window& window, vkfw::CursorMode mode) -> void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the window position.
|
||||||
|
*
|
||||||
|
* @param window GLFW window
|
||||||
|
* @param xpos X position
|
||||||
|
* @param ypos Y position
|
||||||
|
*/
|
||||||
|
static fn setPosition(const vkfw::Window& window, i32 xpos, i32 ypos) -> void;
|
||||||
|
};
|
BIN
textures/viking_room.png
Normal file
BIN
textures/viking_room.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 940 KiB |
Loading…
Reference in a new issue