Compare commits

..

No commits in common. "vk-hpp" and "main" have entirely different histories.
vk-hpp ... main

47 changed files with 2328 additions and 38189 deletions

View file

@ -20,7 +20,6 @@ IndentWidth: 2
NamespaceIndentation: All
SpaceBeforeCpp11BracedList: true
SpacesBeforeTrailingComments: 1
Standard: Latest
IncludeBlocks: Regroup
IncludeCategories:

View file

@ -1,3 +1,4 @@
# noinspection SpellCheckingInspection
Checks: >
*,
-ctad-maybe-unsupported,
@ -7,11 +8,9 @@ Checks: >
-bugprone-implicit-widening-of-multiplication-result,
-cert-env33-c,
-concurrency-mt-unsafe,
-cppcoreguidelines-avoid-const-or-ref-data-members,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-owning-memory,
-cppcoreguidelines-pro-type-member-init,
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-vararg,
-fuchsia-*,
-google-*,

4
.clangd Normal file
View file

@ -0,0 +1,4 @@
Diagnostics:
Suppress: >
-Wmissing-template-arg-list-after-template-kw,
-Wctad-maybe-unsupported

3
.envrc
View file

@ -1 +1,2 @@
use_flake
export NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1
use_flake . --impure

1
.gitignore vendored
View file

@ -2,4 +2,3 @@
.direnv/
.vscode/
build/
imgui.ini

View file

@ -18,25 +18,5 @@
"type": "github"
},
"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"
}
}

View file

@ -12,16 +12,4 @@
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
View file

@ -1,279 +0,0 @@
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!

View file

@ -1,78 +1,27 @@
{
"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": {
"locked": {
"lastModified": 1731139594,
"narHash": "sha256-IigrKK3vYRpUu+HEjPL/phrfh7Ox881er1UEsZvw9Q4=",
"owner": "nixos",
"lastModified": 1727065772,
"narHash": "sha256-U9baiEXL2YsS67QKlBAPIUq+OB+eUPKv8n1vGNdhiec=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "76612b17c0ce71689921ca12d9ffdc9c23ce40b2",
"rev": "989dc4cbf6a95f2e5fefc8cd61d2198a8fb6834a",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1731640008,
"narHash": "sha256-81hruQPQXZf1xtcyYct9XPvBWvKIk6/DSDCc5XcYKT4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "63de88ed5f65084bb5cde3bdcb716e28cc03a933",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1726871744,
"narHash": "sha256-V5LpfdHyQkUF7RfOaDPrZDP+oqz88lTJrMT1+stXNwo=",
"lastModified": 1726481836,
"narHash": "sha256-MWTBH4dd5zIz2iatDb8IkqSjIeFum9jAqkFxgHLdzO4=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a1d92660c6b3b7c26fb883500a80ea9d33321be2",
"rev": "20f9370d5f588fb8c72e844c54511cab054b5f40",
"type": "github"
},
"original": {
@ -84,28 +33,11 @@
},
"root": {
"inputs": {
"nixos-asahi": "nixos-asahi",
"nixpkgs": "nixpkgs_2",
"nixpkgs": "nixpkgs",
"treefmt-nix": "treefmt-nix",
"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": {
"locked": {
"lastModified": 1681028828,
@ -123,14 +55,14 @@
},
"treefmt-nix": {
"inputs": {
"nixpkgs": "nixpkgs_3"
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1730321837,
"narHash": "sha256-vK+a09qq19QNu2MlLcvN4qcRctJbqWkX7ahgPZ/+maI=",
"lastModified": 1726734507,
"narHash": "sha256-VUH5O5AcOSxb0uL/m34dDkxFKP6WLQ6y4I1B4+N3L2w=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "746901bb8dba96d154b66492a29f5db0693dbfcc",
"rev": "ee41a466c2255a3abe6bc50fc6be927cdee57a9f",
"type": "github"
},
"original": {
@ -144,11 +76,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {

View file

@ -2,7 +2,6 @@
description = "C/C++ environment";
inputs = {
nixos-asahi.url = "github:zzywysm/nixos-asahi";
nixpkgs.url = "github:NixOS/nixpkgs";
treefmt-nix.url = "github:numtide/treefmt-nix";
utils.url = "github:numtide/flake-utils";
@ -11,20 +10,13 @@
outputs = {
self,
nixpkgs,
nixos-asahi,
treefmt-nix,
utils,
...
}:
utils.lib.eachDefaultSystem (
system: let
pkgs = import nixpkgs {
inherit system;
config = {
allowUnfree = true;
allowUnsupportedSystem = true;
};
};
pkgs = import nixpkgs {inherit system;};
stdenv =
if pkgs.hostPlatform.isLinux
@ -40,20 +32,16 @@
inherit (sources.${name}) pname version src;
};
imgui = (mkPkg "imgui").override {
IMGUI_BUILD_GLFW_BINDING = true;
IMGUI_BUILD_VULKAN_BINDING = true;
};
fmt = mkPkg "fmt";
deps = with pkgs; [
fmt
glfw
glm
imgui
shaderc.dev
shaderc.lib
vulkan-extension-layer
vulkan-memory-allocator
vulkan-utility-libraries
vulkan-headers
vulkan-loader
vulkan-tools
];
@ -94,6 +82,7 @@
projectRootFile = "flake.nix";
programs = {
alejandra.enable = true;
deadnix.enable = true;
clang-format = {
enable = true;
@ -103,15 +92,13 @@
};
devShell = mkShell.override {inherit stdenv;} {
buildInputs =
packages =
[
alejandra
bear
cmake
(llvmPackages_18.clang-tools.override {enableLibcxx = true;})
lldb
meson
nil
ninja
nvfetcher
pkg-config
@ -126,20 +113,6 @@
VULKAN_SDK = "${vulkan-headers}";
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 = ''
export PATH="${llvmPackages_18.clang-tools.override {enableLibcxx = true;}}/bin:$PATH"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@ project(
'graphics-test',
'cpp',
version: '0.1.0',
default_options: ['cpp_std=c++26', 'warning_level=everything', 'buildtype=debugoptimized'],
default_options: ['cpp_std=c++20', 'warning_level=everything', 'buildtype=debugoptimized'],
)
cpp = meson.get_compiler('cpp')
@ -12,40 +12,37 @@ common_cpp_args = [
'-Wno-c++20-extensions',
'-Wno-c++98-compat',
'-Wno-c++98-compat-pedantic',
'-Wno-pre-c++20-compat-pedantic',
'-Wno-disabled-macro-expansion',
'-Wno-missing-prototypes',
'-Wno-padded',
'-Wno-pre-c++20-compat-pedantic',
'-Wno-switch-default',
'-mavx2',
'-Wno-unsafe-buffer-usage',
'-Wunused-function',
'-fvisibility=hidden',
]
add_project_arguments(cpp.get_supported_arguments(common_cpp_args), language: 'cpp')
deps = [
dependency('glfw3', include_type: 'system'),
dependency('glm', include_type: 'system'),
dependency('vulkan', include_type: 'system'),
dependency('shaderc', include_type: 'system'),
source_file_names = [
'src/main.cpp',
]
imgui_dep = dependency('imgui', required: false, include_type: 'system')
sources = []
if not imgui_dep.found()
imgui_dep = cpp.find_library('imgui', required: true)
endif
foreach file : source_file_names
sources += files(file)
endforeach
deps += imgui_dep
deps = [
dependency('fmt', static: true),
dependency('glfw3'),
dependency('glm'),
dependency('vulkan'),
]
executable(
'graphics-test',
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),
sources,
dependencies: deps,
)

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
[imgui]
src.git = "https://github.com/ocornut/imgui.git"
src.branch = "docking"
fetch.github = "ocornut/imgui"
[fmt]
src.github = "fmtlib/fmt"
fetch.github = "fmtlib/fmt"

View file

@ -1,8 +0,0 @@
#version 450
layout(location = 0) in vec3 fragColor;
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(fragColor, 1.0);
}

View file

@ -1,11 +0,0 @@
#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;
}

View file

@ -1,47 +0,0 @@
#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);
}

View file

@ -1,28 +0,0 @@
#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;
}

View file

@ -1,98 +0,0 @@
#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));
}

View file

@ -1,38 +0,0 @@
#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;
};

View file

@ -1,202 +0,0 @@
#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);
}

View file

@ -1,61 +0,0 @@
#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;
};

View file

@ -1,105 +0,0 @@
#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
);
}

View file

@ -1,72 +0,0 @@
#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;
};

View file

@ -1,204 +0,0 @@
#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;
});
});
}

View file

@ -1,106 +0,0 @@
#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;
};

View file

@ -1,97 +0,0 @@
#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;
}

View file

@ -1,25 +0,0 @@
#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;
};

File diff suppressed because it is too large Load diff

View file

@ -1,10 +0,0 @@
#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
};

View file

@ -1,13 +0,0 @@
#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
};

View file

@ -1,23 +0,0 @@
#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();
}
};

View file

@ -1,17 +0,0 @@
#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
};

View file

@ -1,14 +0,0 @@
#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
};

View file

@ -1,40 +0,0 @@
#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
}

View file

@ -1,49 +0,0 @@
#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
};

1709
src/util/magic_enum.hpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,208 +0,0 @@
/**
* @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 Normal file
View file

@ -0,0 +1,128 @@
#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;

View file

@ -1,152 +0,0 @@
/**
* @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;

View file

@ -1,140 +0,0 @@
/**
* @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
};
}

View file

@ -1,124 +0,0 @@
/**
* @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);
}
};
}

View file

@ -1,76 +0,0 @@
#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);
}

View file

@ -1,72 +0,0 @@
#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;
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 940 KiB