├── .clang-format ├── .clang-tidy ├── .git-blame-ignore-revs ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ └── feature_request.yaml ├── PULL_REQUEST_TEMPLATE │ └── default.md └── workflows │ ├── add_labels.yaml │ ├── build.yml │ ├── build_documentation.yml │ ├── code_style.yml │ ├── commit_naming.yml │ ├── release.yml │ ├── remove_labels.yaml │ └── static_analysis.yml ├── .gitignore ├── .readthedocs.yml ├── CHANGELOG.rst ├── CMakeLists.txt ├── CODE_OF_CONDUCT.rst ├── CONTRIBUTING.rst ├── LICENSE ├── README.rst ├── SECURITY.rst ├── assets ├── fonts │ ├── LICENSE.txt │ ├── NotoSans-Bold.ttf │ ├── NotoSans-BoldItalic.ttf │ ├── NotoSans-Italic.ttf │ └── NotoSans-Regular.ttf ├── models │ └── inexor │ │ ├── 5_objects.gltf │ │ ├── inexor.blend │ │ ├── inexor.gltf │ │ ├── inexor_2.gltf │ │ └── two_cubes.gltf └── textures │ ├── logo_rendered.png │ ├── texture_A_1024.jpg │ ├── texture_B_1024.jpg │ ├── texture_C_1024.jpg │ ├── texture_D_1024.jpg │ ├── texture_E_1024.jpg │ ├── texture_F_1024.jpg │ └── texture_G_1024.jpg ├── benchmarks ├── CMakeLists.txt ├── engine_benchmark_main.cpp └── world │ └── cube_collision.cpp ├── cmake └── dependencies.cmake ├── configuration └── renderer.toml ├── documentation ├── CMakeLists.txt ├── cmake │ └── sphinx-config.cmake ├── helper │ └── generate_radar.py ├── requirements.txt └── source │ ├── _static │ ├── css │ │ └── style.css │ └── js │ │ └── svg-highlight.js │ ├── changelog │ └── main.rst │ ├── code │ └── main.rst │ ├── conf.py │ ├── contact │ └── main.rst │ ├── contributing │ ├── code-of-conduct.rst │ ├── contribute-art.rst │ ├── contribute-code.rst │ ├── contributors.rst │ ├── licenses.rst │ └── main.rst │ ├── development │ ├── benchmarking.rst │ ├── building.rst │ ├── ci.rst │ ├── clang-format-and-ci-example.jpg │ ├── clang-format.rst │ ├── debugging │ │ ├── cla.rst │ │ ├── images │ │ │ ├── log_console.jpg │ │ │ ├── renderdoc │ │ │ │ ├── RenderDoc_step_1.jpg │ │ │ │ ├── RenderDoc_step_2.jpg │ │ │ │ ├── RenderDoc_step_3.jpg │ │ │ │ ├── RenderDoc_step_4.jpg │ │ │ │ ├── RenderDoc_step_5.jpg │ │ │ │ ├── RenderDoc_step_6.jpg │ │ │ │ ├── RenderDoc_step_7.jpg │ │ │ │ ├── RenderDoc_step_8.jpg │ │ │ │ ├── RenderDoc_step_9.jpg │ │ │ │ ├── VisualStudioBreakpoint.jpg │ │ │ │ └── VisualStudioDebugging.jpg │ │ │ ├── vma_dump_example.png │ │ │ └── vma_saves_the_day.png │ │ ├── logfiles.rst │ │ ├── main.rst │ │ ├── renderdoc.rst │ │ └── vma-dumps.rst │ ├── engine-design │ │ └── main.rst │ ├── getting-started.rst │ ├── labeling.rst │ ├── main.rst │ ├── platforms.rst │ ├── reference │ │ ├── binary-format-specification.rst │ │ ├── command-buffers-and-command-pools.rst │ │ ├── gpu-selection.rst │ │ ├── keyboard-mouse-input.rst │ │ ├── main.rst │ │ ├── octree-collision.rst │ │ ├── octree-file-format.rst │ │ ├── octree.svg │ │ ├── octree_collision_boundin_sphere_false_positive.jpg │ │ ├── octree_collision_camera_view_blocked.jpg │ │ ├── octree_collision_cases.jpg │ │ ├── octree_collision_cube_facing_camera.jpg │ │ ├── octree_collision_filled.jpg │ │ ├── octree_collision_multiple_octrees.jpg │ │ ├── octree_collision_nearest_corner.jpg │ │ ├── octree_collision_octant.jpg │ │ ├── octree_collision_only_front_collisions.jpg │ │ ├── octree_collision_real_face.jpg │ │ ├── octree_collision_sizes.jpg │ │ ├── octree_corner.svg │ │ ├── octree_edge.svg │ │ └── octree_indentation.svg │ ├── static-code-analysis.rst │ └── test-automation.rst │ ├── faq │ └── main.rst │ ├── images │ ├── icon_CLion.svg │ ├── inexor-banner.svg │ ├── inexor.png │ └── vulkan.png │ ├── index.rst │ ├── license │ └── main.rst │ └── links │ └── main.rst ├── example ├── CMakeLists.txt └── main.cpp ├── helper ├── commit_validator.mjs └── req_check.py ├── include └── inexor │ └── vulkan-renderer │ ├── application.hpp │ ├── camera.hpp │ ├── exception.hpp │ ├── fps_counter.hpp │ ├── imgui.hpp │ ├── input │ └── keyboard_mouse_data.hpp │ ├── io │ ├── byte_stream.hpp │ ├── exception.hpp │ ├── nxoc_parser.hpp │ └── octree_parser.hpp │ ├── meta.hpp.in │ ├── octree_gpu_vertex.hpp │ ├── render_graph.hpp │ ├── renderer.hpp │ ├── standard_ubo.hpp │ ├── time_step.hpp │ ├── tools │ ├── cla_parser.hpp │ └── file.hpp │ ├── vk_tools │ ├── device_info.hpp │ ├── enumerate.hpp │ └── representation.hpp │ ├── world │ ├── collision.hpp │ ├── collision_query.hpp │ ├── cube.hpp │ └── indentation.hpp │ └── wrapper │ ├── command_buffer.hpp │ ├── command_pool.hpp │ ├── cpu_texture.hpp │ ├── descriptor.hpp │ ├── descriptor_builder.hpp │ ├── device.hpp │ ├── fence.hpp │ ├── framebuffer.hpp │ ├── gpu_memory_buffer.hpp │ ├── gpu_texture.hpp │ ├── image.hpp │ ├── instance.hpp │ ├── make_info.hpp │ ├── semaphore.hpp │ ├── shader.hpp │ ├── swapchain.hpp │ ├── uniform_buffer.hpp │ ├── window.hpp │ └── window_surface.hpp ├── shaders ├── CMakeLists.txt ├── main.frag ├── main.vert ├── ui.frag └── ui.vert ├── src ├── CMakeLists.txt └── vulkan-renderer │ ├── application.cpp │ ├── camera.cpp │ ├── exception.cpp │ ├── fps_counter.cpp │ ├── imgui.cpp │ ├── input │ └── keyboard_mouse_data.cpp │ ├── io │ ├── byte_stream.cpp │ └── nxoc_parser.cpp │ ├── render_graph.cpp │ ├── renderer.cpp │ ├── time_step.cpp │ ├── tools │ ├── cla_parser.cpp │ └── file.cpp │ ├── vk_tools │ ├── device_info.cpp │ ├── enumerate.cpp │ └── representation.cpp │ ├── world │ ├── collision.cpp │ ├── collision_query.cpp │ ├── cube.cpp │ └── indentation.cpp │ └── wrapper │ ├── command_buffer.cpp │ ├── command_pool.cpp │ ├── cpu_texture.cpp │ ├── descriptor.cpp │ ├── descriptor_builder.cpp │ ├── device.cpp │ ├── fence.cpp │ ├── framebuffer.cpp │ ├── gpu_memory_buffer.cpp │ ├── gpu_texture.cpp │ ├── image.cpp │ ├── instance.cpp │ ├── make_info.cpp │ ├── semaphore.cpp │ ├── shader.cpp │ ├── swapchain.cpp │ ├── uniform_buffer.cpp │ ├── window.cpp │ └── window_surface.cpp └── tests ├── CMakeLists.txt ├── gpu-selection └── selection.cpp ├── swapchain └── choose_settings.cpp ├── unit_tests_main.cpp └── world ├── cube.cpp └── cube_collision.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AllowShortBlocksOnASingleLine: Empty 5 | AllowShortCaseLabelsOnASingleLine: false 6 | AllowShortFunctionsOnASingleLine: Empty 7 | AllowShortIfStatementsOnASingleLine: Never 8 | AllowShortLoopsOnASingleLine: false 9 | AlwaysBreakTemplateDeclarations: Yes 10 | ColumnLimit: 120 11 | IndentWidth: 4 12 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: 2 | - '*' 3 | - '-altera-unroll-loops' 4 | - '-boost-use-ranges' 5 | - '-clang-diagnostic-note' 6 | - '-clang-diagnostic-error' 7 | - '-cppcoreguidelines-avoid-do-while' 8 | - '-cppcoreguidelines-pro-type-vararg' 9 | - '-fuchsia-default-arguments-calls' 10 | - '-fuchsia-default-arguments-declarations' 11 | - '-fuchsia-overloaded-operator' 12 | - '-google-readability-todo' 13 | - '-hicpp-uppercase-literal-suffix' 14 | - '-hicpp-vararg' 15 | - '-llvmlibc-*' 16 | - '-misc-no-recursion' 17 | - '-modernize-use-trailing-return-type' 18 | - '-readability-*' 19 | 20 | FormatStyle: 'file' 21 | HeaderFilterRegex: '^(?!.*vulkan-renderer/build).*' 22 | 23 | CheckOptions: 24 | - key: 'bugprone-argument-comment.CommentBoolLiterals' 25 | value: '0' 26 | - key: 'bugprone-assert-side-effect.AssertMacros' 27 | value: 'assert' 28 | - key: 'bugprone-dangling-handle.HandleClasses' 29 | value: 'std::basic_string_view;std::experimental::basic_string_view' 30 | - key: 'bugprone-dynamic-static-initializers.HeaderFileExtensions' 31 | value: ',h,hh,hpp,hxx' 32 | - key: 'bugprone-suspicious-string-compare.WarnOnImplicitComparison' 33 | value: '1' 34 | - key: 'cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors' 35 | value: '1' 36 | - key: 'cppcoreguidelines-no-malloc.Allocations' 37 | value: '::malloc;::calloc' 38 | - key: 'google-readability-function-size.StatementThreshold' 39 | value: '800' 40 | - key: 'readability-identifier-naming.FunctionCase' 41 | value: 'lower_case' 42 | - key: 'readability-static-accessed-through-instance.NameSpecifierNestingThreshold' 43 | value: '3' 44 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # [clang-format] Tested clang-format file. 2 | eed81253b402cc456b885edb990f66ed00311e74 3 | 4 | # [clang-format] Applied clang-format to all files. 5 | 714528c9197c77c5cfac08abefad03e41271cc88 6 | 7 | # [code] Apply code style on missing files. 8 | fe3440a2a7d23552169d03040078c3502f9676db 9 | 10 | # [clang-format] Apply to inexor::world::* 11 | d2d9eaebbf13ef52a8716967b593f4b7c1136953 12 | 13 | # [*] Format all 14 | 701a42dbca4511cd6f53c17456fe45d085d3834a 15 | 16 | # [clang-format] Lower ColumnLimit to 120 17 | 30a029d234e6b864c941ff8ddbbe0f797cd37484 18 | 19 | # [*] Run clang-format 20 | 618454b80cfc6d0d759227ab4f3b4956915eb699 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | labels: ["cat:bug", "org:triage"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thanks for taking the time to fill out this bug report! 9 | - type: textarea 10 | id: description 11 | attributes: 12 | label: Describe The Bug 13 | description: A clear and concise description of what the bug is. 14 | validations: 15 | required: true 16 | - type: textarea 17 | id: reproduction 18 | attributes: 19 | label: Steps To Reproduce 20 | description: Steps to reproduce the behavior. 21 | placeholder: | 22 | 1. Go to '...' 23 | 2. Click on '....' 24 | 3. Scroll down to '....' 25 | 4. See error 26 | validations: 27 | required: true 28 | - type: textarea 29 | id: expectation 30 | attributes: 31 | label: Expected Behavior 32 | description: A clear and concise description of what you expected to happen. 33 | validations: 34 | required: true 35 | - type: textarea 36 | id: code-link 37 | attributes: 38 | label: Affected Code 39 | description: Please link the code where it happens, if available. 40 | placeholder: | 41 | https://github.com/inexorgame/vulkan-renderer/blob/main/src/CMakeLists.txt#L1-L6 42 | https://github.com/inexorgame/vulkan-renderer/blob/main/src/CMakeLists.txt#L25 43 | - type: textarea 44 | id: os-information 45 | attributes: 46 | label: Operating System 47 | description: Which operating system is affected? 48 | placeholder: | 49 | Windows 10 (21H2) 50 | Archlinux 2022.03.01 51 | validations: 52 | required: true 53 | - type: input 54 | id: app-information 55 | attributes: 56 | label: Application Version 57 | description: Which application version/ commmit SHA is affected? 58 | placeholder: | 59 | 1.2.3 (c1e2d69) 60 | validations: 61 | required: true 62 | - type: textarea 63 | id: additional-information 64 | attributes: 65 | label: Additional Context 66 | description: Add any other context about the problem or screenshots. 67 | - type: textarea 68 | id: logs 69 | attributes: 70 | label: Relevant Log Output 71 | description: | 72 | Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 73 | Make sure to remove any personal information before! 74 | render: shell 75 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest an idea or enhancment for this project 3 | labels: ["org:triage"] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thanks for taking the time to fill out this feature request! 9 | - type: textarea 10 | id: problem 11 | attributes: 12 | label: Is your feature request related to a problem? 13 | description: A clear and concise description of what the problem is. 14 | placeholder: I'm always frustrated when ... 15 | - type: textarea 16 | id: description 17 | attributes: 18 | label: Description 19 | description: A clear and concise description of what you want to happen. 20 | validations: 21 | required: true 22 | - type: textarea 23 | id: alternatives 24 | attributes: 25 | label: Alternatives 26 | description: A clear and concise description of any alternative solutions or features you've considered. 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: code-link 31 | attributes: 32 | label: Affected Code 33 | description: Please link the code which might be edited, if applicable. 34 | placeholder: | 35 | https://github.com/inexorgame/vulkan-renderer/blob/main/src/CMakeLists.txt#L1-L6 36 | https://github.com/inexorgame/vulkan-renderer/blob/main/src/CMakeLists.txt#L25 37 | - type: textarea 38 | id: os-information 39 | attributes: 40 | label: Operating System 41 | description: Is only a specific operation system affected? 42 | placeholder: | 43 | Windows 10 (21H2) 44 | Archlinux 2022.03.01 45 | - type: textarea 46 | id: additional-information 47 | attributes: 48 | label: Additional Context 49 | description: Add any other context or screenshots about the feature request here. 50 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/default.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | ## Related Issue 7 | 8 | 9 | 10 | ## How Has This Been Tested? 11 | 12 | 13 | 14 | 15 | ## Screenshots (if appropriate): 16 | 17 | --- 18 | 19 | Merge reminder: **Add `[merge]` to merge commit** 20 | -------------------------------------------------------------------------------- /.github/workflows/add_labels.yaml: -------------------------------------------------------------------------------- 1 | name: Add Labels 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | pull_request: 7 | types: [opened] 8 | 9 | jobs: 10 | add_labels: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Add labels 14 | uses: andymckay/labeler@master 15 | with: 16 | add-labels: "org:triage" 17 | ignore-if-labeled: true 18 | -------------------------------------------------------------------------------- /.github/workflows/build_documentation.yml: -------------------------------------------------------------------------------- 1 | name: Build Documentation 2 | 3 | on: 4 | push: 5 | pull_request: 6 | types: [opened] 7 | 8 | jobs: 9 | build_documentation: 10 | name: Build Documentation 11 | runs-on: ubuntu-latest 12 | if: ${{ github.event_name == 'pull_request' && github.event.action == 'opened' && !github.event.pull_request.merged || github.event_name == 'push' }} 13 | container: ubuntu:rolling 14 | env: 15 | DEBIAN_FRONTEND: "noninteractive" 16 | steps: 17 | - name: Update environment 18 | run: | 19 | # Update package lists 20 | apt update -qq 21 | # Install build tools 22 | apt install -y cmake doxygen git python3 python3-pip python3-venv wget 23 | 24 | - name: Checkout 25 | uses: actions/checkout@v3 26 | 27 | - name: Configure CMake 28 | working-directory: ${{ github.workspace }}/documentation 29 | shell: bash 30 | run: | 31 | cmake . -Bbuild 32 | 33 | - name: Build 34 | working-directory: ${{ github.workspace }}/documentation 35 | shell: bash 36 | run: | 37 | cmake --build build 38 | 39 | - name: Linkcheck 40 | working-directory: ${{ github.workspace }}/documentation 41 | shell: bash 42 | # TODO: return true as long GitHub does not allow specific steps to fail 43 | run: | 44 | cmake --build build --target inexor-vulkan-renderer-documentation-linkcheck || true 45 | 46 | - name: Prepare artifacts 47 | working-directory: ${{ github.workspace }}/documentation 48 | run: | 49 | tar cfz documentation.tar.xz build/html/* 50 | 51 | - name: Upload artifacts 52 | uses: actions/upload-artifact@v4 53 | with: 54 | path: ${{ github.workspace }}/documentation/documentation.tar.xz 55 | name: documentation.tar.xz 56 | -------------------------------------------------------------------------------- /.github/workflows/code_style.yml: -------------------------------------------------------------------------------- 1 | name: Code Style 2 | on: pull_request 3 | 4 | jobs: 5 | clang-format: 6 | name: Clang Format 7 | runs-on: ubuntu-latest 8 | container: ubuntu:rolling 9 | env: 10 | DEBIAN_FRONTEND: "noninteractive" 11 | steps: 12 | - name: Update environment 13 | shell: bash 14 | run: | 15 | # Update package lists 16 | apt update -qq 17 | 18 | # Install tools 19 | apt install -y \ 20 | clang-format \ 21 | git 22 | 23 | - name: Checkout 24 | uses: actions/checkout@v4 25 | 26 | - name: Fetch ${{ github.base_ref }} 27 | shell: bash 28 | run: | 29 | git config --global --add safe.directory $(pwd) 30 | git fetch --progress --depth=1 origin ${{ github.base_ref }} 31 | git log --pretty=oneline 32 | 33 | - name: Style check 34 | shell: bash 35 | run: | 36 | git-clang-format origin/${{ github.base_ref }} 37 | git diff | tee format-diff 38 | if [ -s format-diff ]; then exit 1; fi 39 | -------------------------------------------------------------------------------- /.github/workflows/commit_naming.yml: -------------------------------------------------------------------------------- 1 | name: Commit Naming 2 | on: 3 | push: 4 | pull_request: 5 | types: [opened] 6 | 7 | jobs: 8 | naming: 9 | name: Commit Naming 10 | runs-on: ubuntu-latest 11 | if: ${{ github.event_name == 'pull_request' && github.event.action == 'opened' && !github.event.pull_request.merged || github.event_name == 'push' }} 12 | steps: 13 | - uses: IceflowRE/gitcc@v2 14 | with: 15 | validator_file: helper/commit_validator.mjs 16 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | workflow_run: 4 | workflows: 5 | - Build Code 6 | branches: 7 | - main 8 | types: 9 | - completed 10 | 11 | jobs: 12 | nightly-release: 13 | name: Nightly Release 14 | runs-on: ubuntu-latest 15 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 16 | steps: 17 | - name: Cancel Previous Runs 18 | uses: styfle/cancel-workflow-action@0.11.0 19 | 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | 23 | - name: Download artifacts 24 | uses: actions/github-script@v6 25 | with: 26 | script: | 27 | let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ 28 | owner: context.repo.owner, 29 | repo: context.repo.repo, 30 | run_id: context.payload.workflow_run.id, 31 | }); 32 | let matchArtifacts = allArtifacts.data.artifacts.filter((artifact) => { 33 | return artifact.name.startsWith("nightly_"); 34 | }); 35 | let fs = require('fs'); 36 | for (const artifact of matchArtifacts) { 37 | let download = await github.rest.actions.downloadArtifact({ 38 | owner: context.repo.owner, 39 | repo: context.repo.repo, 40 | artifact_id: artifact.id, 41 | archive_format: 'zip', 42 | }); 43 | fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/`+artifact.name+`.zip`, Buffer.from(download.data)); 44 | } 45 | 46 | - name: Unzip files 47 | shell: bash 48 | run: | 49 | mkdir archives 50 | unzip '*.zip' -d archives 51 | 52 | - name: Prepare Release 53 | run: | 54 | git config user.name github-actions 55 | git config user.email github-actions@github.com 56 | git tag nightly 57 | git push -f origin tag nightly 58 | 59 | - name: Release 60 | shell: bash 61 | env: 62 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 63 | NOTES: | 64 | Latest development release, ready to install. 65 | 66 | This release tag is continuously updated. 67 | run: | 68 | output=$(gh release delete nightly -y 2>&1) || [[ "${output}" == "release not found" ]] 69 | gh release create nightly ./archives/* --title "Nightly Release" --notes "${{ env.NOTES }}" --prerelease --target ${{ github.sha }} 70 | -------------------------------------------------------------------------------- /.github/workflows/remove_labels.yaml: -------------------------------------------------------------------------------- 1 | name: Remove Labels 2 | 3 | on: 4 | issues: 5 | types: [closed] 6 | pull_request: 7 | types: [closed] 8 | 9 | jobs: 10 | add_labels: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Remove labels 14 | uses: andymckay/labeler@master 15 | with: 16 | remove-labels: "org:awaiting information, org:discussion, org:help wanted, org:in progress, org:on hold, org:planned, org:ready to merge, org:review" 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/c++ 2 | # Edit at https://www.gitignore.io/?templates=c++ 3 | 4 | ### C++ ### 5 | # Prerequisites 6 | *.d 7 | 8 | # Compiled Object files 9 | *.slo 10 | *.lo 11 | *.o 12 | *.obj 13 | 14 | # Precompiled Headers 15 | *.gch 16 | *.pch 17 | 18 | # Compiled Dynamic libraries 19 | *.so 20 | *.dylib 21 | *.dll 22 | 23 | # Fortran module files 24 | *.mod 25 | *.smod 26 | 27 | # Compiled Static libraries 28 | *.lai 29 | *.la 30 | *.a 31 | *.lib 32 | 33 | # Executables 34 | *.exe 35 | *.out 36 | *.app 37 | 38 | # End of https://www.gitignore.io/api/c++ 39 | 40 | # custom ignores 41 | .idea/ 42 | cmake-build-*/ 43 | build/ 44 | *.spv 45 | vma-dumps/*.json 46 | *.ini 47 | *.csv 48 | *__pycache__* 49 | 50 | # auto generated documentations paths 51 | documentation/doxygen-output/ 52 | documentation/source/auto-generated/ 53 | documentation/source/exhale-generated/ 54 | 55 | # logfiles 56 | *.log 57 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | build: 4 | os: "ubuntu-22.04" 5 | tools: 6 | python: "3.8" 7 | 8 | python: 9 | install: 10 | - requirements: documentation/requirements.txt 11 | 12 | sphinx: 13 | configuration: documentation/source/conf.py 14 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | ********* 2 | Changelog 3 | ********* 4 | 5 | All notable changes to this project will be documented in this file. 6 | 7 | The format is based on `Keep a Changelog `__ and this project adheres to `Semantic Versioning `__. 8 | 9 | You can find all releases in our `GitHub repository `__. 10 | 11 | v0.1-alpha.3 (17 May 2020) 12 | ========================== 13 | 14 | Changed 15 | ------- 16 | 17 | - RAII in shader code 18 | - RAII in shaders, gpu memory buffers, staging buffers, mesh buffers and textures 19 | - RAII in descriptors 20 | - RAII VkInstance 21 | - RAII Swapchain 22 | - Removed manager classes entirely. 23 | 24 | v0.1-alpha.2 (26 Apr 2020) 25 | ========================== 26 | 27 | Added 28 | ----- 29 | 30 | - Create a `threadpool `__ using C++17. 31 | - Added a simple C++17 implementation of an octree. 32 | - Added event system using `boost::signals2 `__. 33 | - Use `boost::bitstream `__ for data processing. 34 | - Convert octree data structure to vertex geometry (a mesh buffer). 35 | - Support arbitrary indentations of octree geometry. 36 | - Added a descriptor set layout for simple octree geometry. 37 | - Ported `Vulkan Memory Allocator library (VMA) `__ to Linux. 38 | - Added a simple camera movement class. 39 | - Write `spdlog `__ console output to a logfile. 40 | 41 | Changed 42 | ------- 43 | 44 | - Improvements considering C++ code quality standards. 45 | - Logging format and logger usage. 46 | 47 | Fixed 48 | ----- 49 | 50 | - Fixed a bug that would render every model twice. 51 | 52 | v0.1-alpha.1 (12 Apr 2020) 53 | ========================== 54 | 55 | Added 56 | ----- 57 | 58 | - Create a `CMake `__ file with `conan package manager `__ setup. 59 | - Integrate `Vulkan Memory Allocator library (VMA) `__. 60 | - Integrate `RenderDoc `__ support. 61 | - Use `spdlog `__ as logger library. 62 | - Integrate `tiny_gltf `__ library. 63 | - Mesh buffer manager for vertex and index buffers based on VMA. 64 | - Texture manager based on stb_image and VMA. 65 | - Uniform buffer manager based on VMA. 66 | - Shader manager for loading SPIR-V shaders. 67 | - Load TOML configuration files using `toml11 `__. We deliberately won't use JSON for this. 68 | - Vulkan fence manager. 69 | - Vulkan semaphore manager. 70 | - GPU info query functions. 71 | - Vulkan debug callbacks. 72 | - Vulkan standard validation layers. 73 | - C++11 `std::chrono `__ class. 74 | - Use `glm `__. 75 | - Depth buffer. 76 | - Let VMA generate memory debug logs. 77 | - Associate internal resource names with memory regions to improve debugging. 78 | - Use separate data transfer queue for cpu to gpu memory copies if available. 79 | - Availability checks for Vulkan features. 80 | - Settings decision maker for Vulkan initialization. 81 | - Simple command line argument parser. 82 | - Automatic GPU selection mechanism and -gpu command line argument for preferential GPU. 83 | - Create windows using `glfw3 `__. 84 | - Keyboard input based on glfw3. 85 | - Load geometry of glTF 2.0 files using tiny_gltf library. 86 | - Basic camera class. 87 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.24) 2 | project(inexor-vulkan-renderer CXX) 3 | 4 | # Stop in source builds 5 | set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 6 | 7 | # Options 8 | option(INEXOR_BUILD_BENCHMARKS "Build benchmarks" OFF) 9 | option(INEXOR_BUILD_DOC "Build documentation" OFF) 10 | option(INEXOR_BUILD_EXAMPLE "Build example" ON) 11 | option(INEXOR_BUILD_TESTS "Build tests" OFF) 12 | option(INEXOR_FORCE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." TRUE) 13 | 14 | message(STATUS "INEXOR_BUILD_BENCHMARKS = ${INEXOR_BUILD_BENCHMARKS}") 15 | message(STATUS "INEXOR_BUILD_DOC = ${INEXOR_BUILD_DOC}") 16 | message(STATUS "INEXOR_BUILD_EXAMPLE = ${INEXOR_BUILD_EXAMPLE}") 17 | message(STATUS "INEXOR_BUILD_TESTS= ${INEXOR_BUILD_TESTS}") 18 | 19 | message(STATUS "CMAKE_VERSION = ${CMAKE_VERSION}") 20 | message(STATUS "CMAKE_GENERATOR = ${CMAKE_GENERATOR}") 21 | message(STATUS "C Compiler executable: ${CMAKE_C_COMPILER}") 22 | message(STATUS "CXX Compiler executable: ${CMAKE_CXX_COMPILER}") 23 | message(STATUS "Linker executable: ${CMAKE_LINKER}") 24 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 25 | 26 | # The marked constants in application.hpp will be replaced with the following values 27 | set(INEXOR_ENGINE_NAME "Inexor Engine") 28 | set(INEXOR_APP_NAME "Inexor Vulkan-renderer example") 29 | 30 | set(INEXOR_ENGINE_VERSION_MAJOR 0) 31 | set(INEXOR_ENGINE_VERSION_MINOR 1) 32 | set(INEXOR_ENGINE_VERSION_PATCH 0) 33 | 34 | set(INEXOR_APP_VERSION_MAJOR 0) 35 | set(INEXOR_APP_VERSION_MINOR 1) 36 | set(INEXOR_APP_VERSION_PATCH 0) 37 | 38 | # Download dependencies through CMake 39 | include(cmake/dependencies.cmake) 40 | 41 | # Enable GCC/clang ANSI-colored terminal output using Ninja build tool 42 | # TODO: Switch to `CMAKE_COLOR_DIAGNOSTICS` with cmake 3.24 in the future 43 | if (FORCE_COLORED_OUTPUT) 44 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 45 | add_compile_options(-fdiagnostics-color=always) 46 | elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 47 | add_compile_options(-fcolor-diagnostics) 48 | endif() 49 | endif() 50 | 51 | add_subdirectory(shaders) 52 | add_subdirectory(src) 53 | 54 | if(INEXOR_BUILD_BENCHMARKS) 55 | add_subdirectory(benchmarks) 56 | endif() 57 | 58 | if(INEXOR_BUILD_DOC) 59 | add_subdirectory(documentation) 60 | endif() 61 | 62 | if(INEXOR_BUILD_EXAMPLE) 63 | add_subdirectory(example) 64 | endif() 65 | 66 | if(INEXOR_BUILD_TESTS) 67 | add_subdirectory(tests) 68 | endif() 69 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.rst: -------------------------------------------------------------------------------- 1 | Code of Conduct 2 | =============== 3 | 4 | Our Pledge 5 | ---------- 6 | 7 | In the interest of fostering an open and welcoming environment, we as 8 | contributors and maintainers pledge to making participation in our project and 9 | our community a harassment-free experience for everyone, regardless of age, body 10 | size, disability, ethnicity, sex characteristics, gender identity and expression, 11 | level of experience, education, socio-economic status, nationality, personal 12 | appearance, race, religion, or sexual identity and orientation. 13 | 14 | Our Standards 15 | -------------- 16 | 17 | Examples of behavior that contributes to creating a positive environment 18 | include: 19 | 20 | * Using welcoming and inclusive language 21 | * Being respectful of differing viewpoints and experiences 22 | * Gracefully accepting constructive criticism 23 | * Focusing on what is best for the community 24 | * Showing empathy towards other community members 25 | 26 | Examples of unacceptable behavior by participants include: 27 | 28 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 29 | * Trolling, insulting or derogatory comments, and personal or political attacks 30 | * Public or private harassment 31 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 32 | * Other conduct which could reasonably be considered inappropriate in a professional setting 33 | 34 | Our Responsibilities 35 | -------------------- 36 | 37 | Project maintainers are responsible for clarifying the standards of acceptable 38 | behavior and are expected to take appropriate and fair corrective action in 39 | response to any instances of unacceptable behavior. 40 | 41 | Project maintainers have the right and responsibility to remove, edit, or 42 | reject comments, commits, code, wiki edits, issues, and other contributions 43 | that are not aligned to this Code of Conduct, or to ban temporarily or 44 | permanently any contributor for other behaviors that they deem inappropriate, 45 | threatening, offensive, or harmful. 46 | 47 | Scope 48 | ----- 49 | 50 | This Code of Conduct applies both within project spaces and in public spaces 51 | when an individual is representing the project or its community. Examples of 52 | representing a project or community include using an official project e-mail 53 | address, posting via an official social media account, or acting as an appointed 54 | representative at an online or offline event. Representation of a project may be 55 | further defined and clarified by project maintainers. 56 | 57 | Enforcement 58 | ----------- 59 | 60 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 61 | reported by contacting the project team at ``info@inexor.org``. All 62 | complaints will be reviewed and investigated and will result in a response that 63 | is deemed necessary and appropriate to the circumstances. The project team is 64 | obligated to maintain confidentiality with regard to the reporter of an incident. 65 | Further details of specific enforcement policies may be posted separately. 66 | 67 | Project maintainers who do not follow or enforce the Code of Conduct in good 68 | faith may face temporary or permanent repercussions as determined by other 69 | members of the project's leadership. 70 | 71 | Attribution 72 | ----------- 73 | 74 | This Code of Conduct is adapted from the `Contributor Covenant `__, version 1.4, 75 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 76 | 77 | For answers to common questions about this code of conduct, see 78 | https://www.contributor-covenant.org/faq 79 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | We are always open for suggestions or pull requests. You can search after ``diff:first issue`` for good issues to get in touch with this project. 2 | 3 | Join our `Discord server `__. 4 | 5 | `IAmNotHanni `__ 6 |   - Project and community management. 7 |   - Large portion of Vulkan renderer. 8 | 9 | `Iceflower `__ 10 | - Threadpool improvements. 11 | - Advice on thread safety and code design. 12 | - CMake improvements and feedback. 13 | - Feedback on Travis CI and Github actions. 14 | - Support for `Exhale `__. 15 | - Overall contributions to CI (Travis/Github actions). 16 | - Replaced unscoped enums with scoped enums. 17 | - Replaced macros with constexpr's. 18 | - Improvement of overall project structure. 19 | - Overall code cleanup. 20 | - Read the docs support. 21 | 22 | `movabo `__ 23 | - First generation of octree engine code. 24 | 25 | `authenticate `__ 26 | - Refactoring of texture loading code. 27 | - Error texture generation. 28 | 29 | `Shikijo `__ 30 | - Pointed out broken glsl compiler batch script on Windows. 31 | 32 | `Croydon `__ 33 | - Advice on `conan package manager `__. 34 | 35 | `westernheld `__ 36 | - Testing and debugging. 37 | 38 | `uilianries `__ 39 | - `Travis CI setup `__ 40 | 41 | `yeetari `__ 42 | - Building and testing vulkan-renderer on Linux. 43 | - Added USE_VMA_RECORDING CMake option so vulkan-renderer can be build on Linux until VMA recording has been ported. 44 | - Overall contributions to CI (Travis/Github actions). 45 | - Add build instructions for gentoo. 46 | - Replace ``_DEBUG`` with NDEBUG. 47 | - std::vector size check improvement. 48 | - Help with git. 49 | - Overall code cleanup. 50 | - Getting vulkan-renderer compile and run on Linux. 51 | - Overall CMake expertise. 52 | - Compiling SPIR-V shaders through CMake setup. 53 | 54 | `azkoon `__ 55 |   - Help with Discord server. 56 |   - Help with wiki. 57 | 58 | `joetoth `__ 59 | - Help with Discord server. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019-present Inexor Collective 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | *************** 2 | vulkan-renderer 3 | *************** 4 | 5 | |language| |platforms| |github actions| |readthedocs| |discord| |license| 6 | 7 | .. image:: documentation/source/images/inexor-banner.svg 8 | 9 | 10 | FAQ and documentation 11 | ##################### 12 | 13 | Quickstart: `Building Instructions`_ (`Windows`_/`Linux`_) & `Getting started`_ 14 | 15 | .. _Building Instructions: https://inexor-vulkan-renderer.readthedocs.io/en/latest/development/building.html 16 | .. _Windows: https://inexor-vulkan-renderer.readthedocs.io/en/latest/development/building.html#building-windows 17 | .. _Linux: https://inexor-vulkan-renderer.readthedocs.io/en/latest/development/building.html#building-linux 18 | .. _Getting started: https://inexor-vulkan-renderer.readthedocs.io/en/latest/development/getting-started.html 19 | 20 | 21 | Inexor is an open-source project which combines modern C++ with Vulkan API. 22 | 23 | Our current main objective is the development of a new 3d octree game engine. 24 | 25 | `Click here `__ to read our faq and documentation. 26 | 27 | Inexor is licensed under the `MIT license `__. 28 | 29 | 30 | Sponsors 31 | ######## 32 | 33 | Special thanks to `JetBrains `__ for providing us with CLion licenses! 34 | 35 | 36 | .. image:: documentation/source/images/icon_CLion.svg 37 | :width: 150px 38 | 39 | 40 | .. Badges. 41 | 42 | .. |language| image:: https://img.shields.io/badge/language-C%2B%2B20-brightgreen 43 | 44 | .. |platforms| image:: https://img.shields.io/badge/platforms-Linux%20%26%20Windows-brightgreen 45 | 46 | .. |github actions| image:: https://img.shields.io/github/actions/workflow/status/inexorgame/vulkan-renderer/build.yml?branch=main 47 | :target: https://github.com/inexorgame/vulkan-renderer/actions?query=build.yml 48 | 49 | .. |discord| image:: https://img.shields.io/discord/698219248954376256?logo=discord 50 | :target: https://discord.com/invite/acUW8k7 51 | 52 | .. |license| image:: https://img.shields.io/github/license/inexorgame/vulkan-renderer?color=brightgreen 53 | :target: https://inexor-vulkan-renderer.readthedocs.io/en/latest/license/main.html 54 | 55 | .. |downloads| image:: https://img.shields.io/github/downloads/inexorgame/vulkan-renderer/total?color=brightgreen 56 | 57 | .. |readthedocs| image:: https://readthedocs.org/projects/inexor-vulkan-renderer/badge/?version=latest 58 | :target: https://inexor-vulkan-renderer.readthedocs.io 59 | -------------------------------------------------------------------------------- /SECURITY.rst: -------------------------------------------------------------------------------- 1 | *************** 2 | Security Policy 3 | *************** 4 | 5 | Supported Versions 6 | ################## 7 | 8 | We support bug fixes for the latest and LTS versions of Inexor. 9 | 10 | Reporting a Vulnerability 11 | ######################### 12 | 13 | The fastest way to get in contact and a fast response is our `Discord server `__. 14 | Just direct message any member with the `organization` role or ping the role and we will contact you. 15 | 16 | We will create a `security advisory `__ and add you as a collaborator (if you have GitHub account). 17 | Everything else will be discussed there. 18 | If the incident is resolved, the advisory will be published. 19 | 20 | What is considered as a Vulnerability? 21 | ###################################### 22 | 23 | Every unwanted behaviour like 24 | - leaking personal data to third parties 25 | - possibility to take over your system 26 | - remote executions 27 | - ... 28 | -------------------------------------------------------------------------------- /assets/fonts/NotoSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/fonts/NotoSans-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/NotoSans-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/fonts/NotoSans-BoldItalic.ttf -------------------------------------------------------------------------------- /assets/fonts/NotoSans-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/fonts/NotoSans-Italic.ttf -------------------------------------------------------------------------------- /assets/fonts/NotoSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/fonts/NotoSans-Regular.ttf -------------------------------------------------------------------------------- /assets/models/inexor/inexor.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/models/inexor/inexor.blend -------------------------------------------------------------------------------- /assets/textures/logo_rendered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/textures/logo_rendered.png -------------------------------------------------------------------------------- /assets/textures/texture_A_1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/textures/texture_A_1024.jpg -------------------------------------------------------------------------------- /assets/textures/texture_B_1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/textures/texture_B_1024.jpg -------------------------------------------------------------------------------- /assets/textures/texture_C_1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/textures/texture_C_1024.jpg -------------------------------------------------------------------------------- /assets/textures/texture_D_1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/textures/texture_D_1024.jpg -------------------------------------------------------------------------------- /assets/textures/texture_E_1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/textures/texture_E_1024.jpg -------------------------------------------------------------------------------- /assets/textures/texture_F_1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/textures/texture_F_1024.jpg -------------------------------------------------------------------------------- /assets/textures/texture_G_1024.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/assets/textures/texture_G_1024.jpg -------------------------------------------------------------------------------- /benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | FetchContent_MakeAvailable(gtest) 2 | FetchContent_MakeAvailable(benchmark) 3 | 4 | set(INEXOR_BENCHMARKING_SOURCE_FILES 5 | engine_benchmark_main.cpp 6 | world/cube_collision.cpp 7 | ) 8 | 9 | add_executable(inexor-vulkan-renderer-benchmarks ${INEXOR_BENCHMARKING_SOURCE_FILES}) 10 | 11 | set_target_properties( 12 | inexor-vulkan-renderer-benchmarks PROPERTIES 13 | 14 | CXX_EXTENSIONS OFF 15 | CXX_STANDARD 20 16 | CXX_STANDARD_REQUIRED ON 17 | ) 18 | 19 | target_link_libraries( 20 | inexor-vulkan-renderer-benchmarks 21 | 22 | PRIVATE 23 | inexor-vulkan-renderer 24 | 25 | PUBLIC 26 | benchmark::benchmark 27 | ) 28 | -------------------------------------------------------------------------------- /benchmarks/engine_benchmark_main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "inexor/vulkan-renderer/meta.hpp" 4 | 5 | #include 6 | 7 | int main(int argc, char **argv) { 8 | using namespace inexor::vulkan_renderer; 9 | 10 | // Print engine and application metadata. 11 | std::cout << ENGINE_NAME << ", version " << ENGINE_VERSION_STR << std::endl; 12 | std::cout << APP_NAME << ", version " << APP_VERSION_STR << std::endl; 13 | std::cout << "Configuration: " << BUILD_TYPE << ", Git SHA " << BUILD_GIT << std::endl; 14 | 15 | benchmark::Initialize(&argc, argv); 16 | if (benchmark::ReportUnrecognizedArguments(argc, argv)) { 17 | return 1; 18 | } 19 | benchmark::RunSpecifiedBenchmarks(); 20 | 21 | std::cout << "Press Enter to close" << std::endl; 22 | std::cin.get(); 23 | } 24 | -------------------------------------------------------------------------------- /benchmarks/world/cube_collision.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace inexor::vulkan_renderer { 7 | 8 | void CubeCollision(benchmark::State &state) { 9 | for (auto _ : state) { 10 | const glm::vec3 world_pos{0, 0, 0}; 11 | world::Cube world(1.0f, world_pos); 12 | world.set_type(world::Cube::Type::SOLID); 13 | 14 | glm::vec3 cam_pos{0.0f, 0.0f, 10.0f}; 15 | glm::vec3 cam_direction{0.0f, 0.0f, -1.0f}; 16 | 17 | benchmark::DoNotOptimize(ray_cube_collision_check(world, cam_pos, cam_direction)); 18 | } 19 | } 20 | 21 | BENCHMARK(CubeCollision); 22 | 23 | } // namespace inexor::vulkan_renderer 24 | -------------------------------------------------------------------------------- /cmake/dependencies.cmake: -------------------------------------------------------------------------------- 1 | # Download dependencies by using FetchContent_Declare 2 | # Use FetchContent_MakeAvailable only in those code parts where the dependency is actually needed 3 | 4 | include(FetchContent) 5 | set(FETCHCONTENT_QUIET OFF) 6 | 7 | FetchContent_Declare(benchmark 8 | GIT_REPOSITORY https://github.com/google/benchmark 9 | GIT_TAG v1.8.5 10 | GIT_SHALLOW ON 11 | GIT_PROGRESS ON 12 | FIND_PACKAGE_ARGS 1.8.5) 13 | 14 | FetchContent_Declare(fmt 15 | GIT_REPOSITORY https://github.com/fmtlib/fmt.git 16 | GIT_TAG 11.0.1 17 | GIT_SHALLOW ON 18 | GIT_PROGRESS ON 19 | FIND_PACKAGE_ARGS 11.0.1) 20 | 21 | set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) 22 | set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) 23 | set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) 24 | FetchContent_Declare(glfw 25 | GIT_REPOSITORY https://github.com/glfw/glfw.git 26 | GIT_TAG 3.4 27 | GIT_SHALLOW ON 28 | GIT_PROGRESS ON 29 | FIND_PACKAGE_ARGS 3.4) 30 | 31 | FetchContent_Declare(glm 32 | GIT_REPOSITORY https://github.com/g-truc/glm.git 33 | GIT_TAG 1.0.1 34 | GIT_SHALLOW ON 35 | GIT_PROGRESS ON) 36 | 37 | FetchContent_Declare(gtest 38 | GIT_REPOSITORY https://github.com/google/googletest 39 | GIT_TAG v1.15.0 40 | GIT_SHALLOW ON 41 | GIT_PROGRESS ON 42 | FIND_PACKAGE_ARGS 1.15.0) 43 | 44 | FetchContent_Declare(imgui 45 | GIT_REPOSITORY https://github.com/ocornut/imgui.git 46 | GIT_TAG v1.90.9 47 | GIT_SHALLOW ON 48 | GIT_PROGRESS ON 49 | FIND_PACKAGE_ARGS 1.90.9) 50 | 51 | set(SPDLOG_FMT_EXTERNAL ON CACHE BOOL "" FORCE) 52 | FetchContent_Declare(spdlog 53 | GIT_REPOSITORY https://github.com/gabime/spdlog.git 54 | GIT_TAG v1.14.1 55 | GIT_SHALLOW ON 56 | GIT_PROGRESS ON 57 | FIND_PACKAGE_ARGS 1.14.1) 58 | 59 | FetchContent_Declare(stb 60 | GIT_REPOSITORY https://github.com/nothings/stb.git 61 | GIT_TAG f7f20f39fe4f206c6f19e26ebfef7b261ee59ee4 62 | GIT_PROGRESS ON) 63 | 64 | FetchContent_Declare(tinygltf 65 | GIT_REPOSITORY https://github.com/syoyo/tinygltf.git 66 | GIT_TAG v2.9.2 67 | GIT_PROGRESS ON 68 | FIND_PACKAGE_ARGS 2.9.2) 69 | 70 | FetchContent_Declare(toml 71 | GIT_REPOSITORY https://github.com/ToruNiina/toml11.git 72 | GIT_TAG v4.0.3 73 | GIT_SHALLOW ON 74 | GIT_PROGRESS ON 75 | FIND_PACKAGE_ARGS 4.0.3) 76 | 77 | FetchContent_Declare(vma 78 | GIT_REPOSITORY https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git 79 | GIT_TAG v3.1.0 80 | GIT_PROGRESS ON 81 | FIND_PACKAGE_ARGS 3.1.0) 82 | 83 | FetchContent_Declare(volk 84 | GIT_REPOSITORY https://github.com/zeux/volk 85 | GIT_TAG 1.3.270 86 | GIT_PROGRESS ON 87 | FIND_PACKAGE_ARGS 1.3.270) 88 | 89 | # is not be used because we install the whole Vulkan SDK, but stays here for fallback 90 | FetchContent_Declare(Vulkan 91 | GIT_REPOSITORY https://github.com/KhronosGroup/Vulkan-Headers 92 | GIT_TAG v1.3.283 93 | GIT_PROGRESS ON 94 | FIND_PACKAGE_ARGS 1.3.283) 95 | -------------------------------------------------------------------------------- /configuration/renderer.toml: -------------------------------------------------------------------------------- 1 | # This configuration file contains all options for the vulkan-renderer. 2 | # Do not change any values unless you know exactly what you are doing! 3 | 4 | title = "vulkan-renderer-configuration" 5 | 6 | #TODO: Declare further TOML configuration files here? 7 | 8 | [application] 9 | name = "Inexor-Application" 10 | 11 | [application.engine] 12 | name = "Inexor-Engine" 13 | 14 | [application.window] 15 | mode = "windowed" 16 | width = 1280 17 | height = 720 18 | name = "Inexor-Vulkan-Renderer" 19 | 20 | [shaders] 21 | [shaders.vertex] 22 | files = [ 23 | "shaders/main.vert.spv", 24 | ] 25 | 26 | [shaders.fragment] 27 | files = [ 28 | "shaders/main.frag.spv", 29 | ] 30 | 31 | # TODO: Use key/value pairs and give textures user friendly names. 32 | [textures] 33 | files = [ 34 | "assets/textures/texture_A_1024.jpg", 35 | "assets/textures/texture_B_1024.jpg", 36 | "assets/textures/texture_C_1024.jpg", 37 | "assets/textures/texture_D_1024.jpg", 38 | "assets/textures/texture_E_1024.jpg", 39 | "assets/textures/texture_F_1024.jpg", 40 | "assets/textures/texture_G_1024.jpg", 41 | "assets/textures/logo_rendered.png", 42 | ] 43 | 44 | # glTF 2.0 is the new standard 3D model format. 45 | # https://www.khronos.org/gltf/ 46 | [glTFmodels] 47 | files = [ 48 | "assets/models/inexor-logo/inexor_logo.gltf", 49 | ] 50 | -------------------------------------------------------------------------------- /documentation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | 3 | option(INEXOR_BUILD_DOCUMENTATION_USE_VENV "Generate Python virtual environment" ON) 4 | 5 | find_package(Doxygen REQUIRED) 6 | message(STATUS "Found Doxygen: ${DOXYGEN_EXECUTABLE}") 7 | 8 | find_package(Python COMPONENTS Interpreter REQUIRED) 9 | if (INEXOR_BUILD_DOCUMENTATION_USE_VENV) 10 | set(inexor_venv "${CMAKE_CURRENT_BINARY_DIR}/venv") 11 | message(STATUS "Creating Python venv at ${inexor_venv}") 12 | execute_process(COMMAND ${Python_EXECUTABLE} -m venv ${inexor_venv}) 13 | set(ENV{VIRTUAL_ENV} ${inexor_venv}) 14 | set(Python_FIND_VIRTUALENV FIRST) 15 | unset(Python_EXECUTABLE) 16 | find_package(Python COMPONENTS Interpreter REQUIRED) 17 | 18 | execute_process( 19 | COMMAND ${Python_EXECUTABLE} -m pip install --no-cache wheel 20 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 21 | COMMAND_ERROR_IS_FATAL ANY 22 | ) 23 | execute_process( 24 | COMMAND ${Python_EXECUTABLE} -m pip install --no-cache -r requirements.txt 25 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 26 | COMMAND_ERROR_IS_FATAL ANY 27 | ) 28 | endif() 29 | 30 | execute_process( 31 | COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../helper/req_check.py requirements.txt 32 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 33 | COMMAND_ERROR_IS_FATAL ANY 34 | ) 35 | 36 | find_program(SPHINX_EXECUTABLE sphinx-build HINTS ${inexor_venv}/Scripts ${inexor_venv}/bin REQUIRED) 37 | message(STATUS "Found Sphinx: ${SPHINX_EXECUTABLE}") 38 | 39 | # Sphinx cache with pickled ReST documents 40 | set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees") 41 | add_custom_target( 42 | inexor-vulkan-renderer-documentation ALL 43 | COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/_doctrees" 44 | COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/html" 45 | COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_SOURCE_DIR}/source/auto-generated" 46 | COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_SOURCE_DIR}/source/exhale-generated" 47 | COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_SOURCE_DIR}/doxygen-output" 48 | COMMAND ${SPHINX_EXECUTABLE} -j auto -T -E -a -b html -d "${SPHINX_CACHE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/source" "${CMAKE_CURRENT_BINARY_DIR}/html" 49 | COMMENT "Building HTML documentation with Sphinx" 50 | ) 51 | add_custom_target( 52 | inexor-vulkan-renderer-documentation-linkcheck 53 | COMMAND ${SPHINX_EXECUTABLE} -j auto -T -b linkcheck -d "${SPHINX_CACHE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/source" "${CMAKE_CURRENT_BINARY_DIR}/html" 54 | COMMENT "Building linkcheck documentation with Sphinx" 55 | ) 56 | -------------------------------------------------------------------------------- /documentation/cmake/sphinx-config.cmake: -------------------------------------------------------------------------------- 1 | # https://eb2.co/blog/2012/03/sphinx-and-cmake-beautiful-documentation-for-c---projects/ 2 | find_program( 3 | SPHINX_EXECUTABLE NAMES sphinx-build 4 | HINTS 5 | $ENV{SPHINX_DIR} 6 | PATH_SUFFIXES bin 7 | DOC "Sphinx documentation generator" 8 | ) 9 | 10 | include(FindPackageHandleStandardArgs) 11 | 12 | find_package_handle_standard_args( 13 | Sphinx DEFAULT_MSG 14 | SPHINX_EXECUTABLE 15 | ) 16 | 17 | mark_as_advanced(SPHINX_EXECUTABLE) 18 | -------------------------------------------------------------------------------- /documentation/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx>=4.5.0 2 | sphinx_rtd_theme>=1.0.0 3 | exhale>=0.3.1 4 | sphinxcontrib-mermaid>=0.7.1 5 | plotly>=5.7.0 6 | pandas>=1.4.2 7 | recommonmark>=0.7.1 -------------------------------------------------------------------------------- /documentation/source/_static/css/style.css: -------------------------------------------------------------------------------- 1 | @import url("theme.css"); 2 | 3 | /* use the whole width of the screen */ 4 | html { 5 | overflow-x: visible; 6 | } 7 | 8 | body { 9 | overflow-x: visible; 10 | } 11 | 12 | .wy-nav-content { 13 | max-width: 100%; 14 | } 15 | 16 | /* stronger red .. warning:: directive */ 17 | .admonition.warning { 18 | background: #ffd4cc; 19 | } 20 | .wy-alert.wy-alert-warning .wy-alert-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .attention .wy-alert-title, .rst-content .caution .wy-alert-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .attention .admonition-title, .rst-content .caution .admonition-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .warning .admonition-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .admonition-todo .admonition-title, .rst-content .wy-alert-warning.admonition .admonition-title { 21 | background: #ff7e82; 22 | } 23 | 24 | /* mermaid path highlighting on hover and click support */ 25 | .svg-highlight.path { 26 | stroke: red !important; 27 | stroke-width: 2.5px !important; 28 | } 29 | 30 | .svg-highlight.arrowheadPath { 31 | fill: red !important; 32 | } 33 | 34 | .svg-highlight-hover.path { 35 | stroke: orange !important; 36 | stroke-width: 3px !important; 37 | } 38 | 39 | .svg-highlight-hover.arrowheadPath { 40 | fill: orange !important; 41 | } 42 | -------------------------------------------------------------------------------- /documentation/source/_static/js/svg-highlight.js: -------------------------------------------------------------------------------- 1 | /* support to highlight mermaid paths useful if you present a big image to others */ 2 | $(function () { 3 | let allPaths = $("path.path"); 4 | let allArrows = $("path.arrowheadPath"); 5 | 6 | allPaths.click(function (event) { 7 | if (!event.shiftKey) { 8 | allPaths.removeClass("svg-highlight"); 9 | allArrows.removeClass("svg-highlight"); 10 | } 11 | if ($(this).hasClass("svg-highlight")) { 12 | $(this).removeClass("svg-highlight"); 13 | $(this).find("+ defs > marker > path").removeClass("svg-highlight"); 14 | } else { 15 | $(this).addClass("svg-highlight"); 16 | $(this).find("+ defs > marker > path").addClass("svg-highlight"); 17 | } 18 | }); 19 | 20 | allPaths.hover( 21 | function () { 22 | $(this).addClass("svg-highlight-hover"); 23 | $(this).find("+ defs > marker > path").addClass("svg-highlight-hover"); 24 | }, 25 | function () { 26 | $(this).removeClass("svg-highlight-hover"); 27 | $(this).find("+ defs > marker > path").removeClass("svg-highlight-hover"); 28 | } 29 | ); 30 | }); 31 | -------------------------------------------------------------------------------- /documentation/source/changelog/main.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../../CHANGELOG.rst 2 | -------------------------------------------------------------------------------- /documentation/source/code/main.rst: -------------------------------------------------------------------------------- 1 | *********** 2 | Source Code 3 | *********** 4 | 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | ../exhale-generated/class_view_hierarchy.rst 10 | ../exhale-generated/file_view_hierarchy.rst 11 | ../exhale-generated/unabridged_api.rst 12 | -------------------------------------------------------------------------------- /documentation/source/conf.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from pathlib import Path 3 | 4 | import sphinx_rtd_theme 5 | 6 | sys.path.insert(0, str(Path('../../').resolve())) 7 | sys.path.insert(0, str(Path('../').resolve())) 8 | 9 | from helper import generate_radar 10 | # generate additional source stuff 11 | generate_radar.generate(Path("./auto-generated/")) 12 | 13 | extensions = [ 14 | 'breathe', 15 | 'exhale', 16 | 'recommonmark', 17 | 'sphinxcontrib.mermaid' 18 | ] 19 | source_suffix = ['.rst'] 20 | master_doc = 'index' 21 | 22 | project = 'Inexor Vulkan Renderer' 23 | author = 'Inexor Collective' 24 | copyright = '2020-present ' + author + '. The page content is licensed under CC ' \ 25 | + 'BY 4.0 unless otherwise noted' 26 | title = project + ' Documentation' 27 | version = 'v0.1-alpha.3' 28 | release = 'v0.1-alpha.3' 29 | 30 | language = 'english' 31 | pygments_style = 'sphinx' 32 | html_theme = 'sphinx_rtd_theme' 33 | html_logo = 'images/inexor.png' 34 | html_theme_options = { 35 | 'logo_only': False, 36 | 'display_version': True, 37 | } 38 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 39 | html_static_path = ['_static'] 40 | html_css_files = [ 41 | 'css/style.css', 42 | ] 43 | html_js_files = [ 44 | 'js/svg-highlight.js', 45 | ] 46 | html_favicon = "../../assets/textures/logo_rendered.png" 47 | 48 | linkcheck_ignore = [ 49 | r"https://github.com/.*#" # do not check anchors from GitHub, JS magic 50 | ] 51 | 52 | mermaid_version = "11.4.1" 53 | 54 | # Setup the breathe extension 55 | breathe_projects = { 56 | "vulkan-renderer": "../doxygen-output/xml" 57 | } 58 | breathe_default_project = "vulkan-renderer" 59 | breathe_default_members = ('private-members', 'members', 'undoc-members') 60 | 61 | # Setup the exhale extension 62 | header_path = "../../include/" 63 | exhale_args = { 64 | # These arguments are required 65 | "containmentFolder": "./exhale-generated", 66 | "rootFileName": "main.rst", 67 | "rootFileTitle": "Source Code", 68 | "doxygenStripFromPath": header_path, 69 | # Suggested optional arguments 70 | "createTreeView": True, 71 | # TIP: if using the sphinx-bootstrap-theme, you need 72 | # "treeViewIsBootstrap": True, 73 | "exhaleExecutesDoxygen": True, 74 | "exhaleDoxygenStdin": f"""INPUT = {header_path} 75 | EXTRACT_PRIVATE = YES 76 | EXTRACT_ALL = YES""", 77 | "verboseBuild": True, 78 | } 79 | 80 | # Tell sphinx what the primary language being documented is. 81 | primary_domain = 'cpp' 82 | # Tell sphinx what the pygments highlight language should be. 83 | highlight_language = 'cpp' 84 | -------------------------------------------------------------------------------- /documentation/source/contact/main.rst: -------------------------------------------------------------------------------- 1 | Contact us 2 | ========== 3 | 4 | Please join our `Discord server `__ and visit our website at `www.inexor.org `__. 5 | -------------------------------------------------------------------------------- /documentation/source/contributing/code-of-conduct.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. include:: ../../../CODE_OF_CONDUCT.rst 4 | -------------------------------------------------------------------------------- /documentation/source/contributing/contribute-art.rst: -------------------------------------------------------------------------------- 1 | Contribute art 2 | ============== 3 | 4 | If you want to contribute textures, sounds or models, check out our `website `__ or join our `Discord server `__ to find more information about supported formats etc. 5 | -------------------------------------------------------------------------------- /documentation/source/contributing/contribute-code.rst: -------------------------------------------------------------------------------- 1 | Contribute code 2 | =============== 3 | 4 | - If you want to contribute code, join our `Discord `__ and have a look at our `vulkan-renderer repository `__. 5 | - Try to find a `first good issue `__ in our issue tracker. 6 | - Open a `pull request `__. 7 | - We want to keep commit as small in size as possible. 8 | 9 | Signing commits 10 | --------------- 11 | 12 | - We encourage you to sign your commits, although this is not a strict requirement from our side. 13 | - You can find help on how to sign commits in `GitHub's docs `__. 14 | 15 | Commit naming convention 16 | ------------------------ 17 | 18 | The commit naming convention will be checked by our continuous integration. In order to be valid, the followin rules must all be fulfilled: 19 | 20 | - The commit message must begin with a category in square brackets which describes the code part that was changed 21 | - The commit category must not be empty 22 | - A commit category must contain at least two characters. Allowed characters are: letters ``a-z``, numbers ``0-9``, and ``-``. For example ``[gpu-texture]`` 23 | - If two code parts are affected, separate the categories using ``|``, for example ``[gpu-texture|gpu-info]`` 24 | - If three or more code parts are affected, use ``[*]`` as category 25 | - Leave one space after the commit category 26 | - The commit message itself must consist of the following characters: letters ``a-z``, numbers ``0-9`` 27 | - The commit message must begin with a capital letter 28 | - The commit message must exist and it must not be empty 29 | - The commit message must not end with ``.``, ``!`` or ``?`` 30 | 31 | **Examples** 32 | 33 | - ``[docs] Explain commit naming convention`` 34 | - ``[gpu-info] Don't display empty gpu info queries as error`` 35 | - ``[gpu-info|representation] Cleanup`` 36 | - ``[ci] Add commit naming check`` 37 | - ``[*] Move GPU info to vk tools`` 38 | 39 | Additional information 40 | ---------------------- 41 | 42 | The regex pattern for the commit category is ``\*|(?:[a-z0-9]{2,}[\s|-]?)+``, the pattern for the message is ``[A-Z0-9].+[^.!?,\s]`` 43 | -------------------------------------------------------------------------------- /documentation/source/contributing/contributors.rst: -------------------------------------------------------------------------------- 1 | List of Contributors 2 | ==================== 3 | 4 | .. include:: ../../../CONTRIBUTING.rst 5 | -------------------------------------------------------------------------------- /documentation/source/contributing/licenses.rst: -------------------------------------------------------------------------------- 1 | .. _LICENSES: 2 | 3 | Licenses 4 | ======== 5 | 6 | In general we accept every widely acknowledged license which allows to share, modify, share the modified work, make commercial use or any combination of these. The licenses we accept are listed here, and below are the ones we do not. If you are not sure about something or the license doesn't appear in these lists, don't hesitate to ask us about it on our `Discord `__. 7 | 8 | List of accepted licenses 9 | ------------------------- 10 | 11 | * `CC0 1.0 `__ or any later version 12 | * `CC BY 3.0 `__ or any later version 13 | * `CC BY-SA 3.0 `__ or any later version 14 | * `ZLIB `__ 15 | * `MIT `__ 16 | 17 | List of licenses we don't accept: 18 | --------------------------------- 19 | 20 | The following licenses either have a non-derivative or non-commercial section: 21 | 22 | * `CC BY-ND `__ any version 23 | * `CC BY-NC `__ any version 24 | * `CC BY-NC-ND `__ any version 25 | * `CC BY-NC-SA `__ any version 26 | * No license at all 27 | 28 | Special notes 29 | ------------- 30 | 31 | We reject content which is licensed under the terms of a license which aims at one special jurisdiction. We consider ourselves as an international community and we define freedom as the freedom for everyone, everywhere. Please, don't use licenses which could cause trouble, e.g. all Creative Commons licenses before the 4.0 versions have `local derivations `__ for a lot of countries (e.g. `CC BY 3.0 DE `__). Starting with CC v4.0 there is only one international license to address this issue. 32 | 33 | We also don't accept Public Domain. The problem with Public Domain is that the definition is different from jurisdiction to jurisdiction, there isn't an international declaration. Also in some jurisdiction it's very complicated till impossible to make your work Public Domain before your rights expire after the ordinary time. 34 | 35 | Instead of Public Domain we recommend using `CC0 (Creative Commons Zero) `__. CC0 is basically a license which gives the creator a way to waive all their copyright and related rights in their works to the fullest extent allowed by law + a Public Domain fallback if the waiving of the rights isn't possible under special circumstances. 36 | 37 | Common mistakes: 38 | ---------------- 39 | 40 | - Missing version number of the license (if exists), e.g. "Creative Commons BY". 41 | - Missing full name of the license, e.g. "licensed under a Creative Commons license". 42 | - Mix between the short form and the complete name, e.g. "Creative Commons BY Attribution 4.0". 43 | -------------------------------------------------------------------------------- /documentation/source/contributing/main.rst: -------------------------------------------------------------------------------- 1 | ***************** 2 | How to contribute 3 | ***************** 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | 8 | code-of-conduct 9 | licenses 10 | contribute-code 11 | contribute-art 12 | contributors 13 | -------------------------------------------------------------------------------- /documentation/source/development/benchmarking.rst: -------------------------------------------------------------------------------- 1 | Benchmarking 2 | ============ 3 | 4 | - Inexor will use `Google Benchmark `__ in the future. 5 | - Benchmarks can also not run in GitHub actions since testing Vulkan features would require a graphics card. 6 | - The tests will run locally on the developer's machine along with the tests. 7 | -------------------------------------------------------------------------------- /documentation/source/development/ci.rst: -------------------------------------------------------------------------------- 1 | Continuous integration 2 | ====================== 3 | 4 | - The main branch and the build system must stay stable at all time. 5 | 6 | - You can see the current status of the main branch in the build batch: 7 | 8 | |github actions| 9 | 10 | - Currently we are using `GitHub Actions `__ for building with `gcc `__, `clang `__ and `Microsoft Visual Studio `__ on every push or pull request. 11 | 12 | - This `Continuous Integration (CI) `__ allows for automatic building and testing of our software. 13 | 14 | - We also have a `webhook `__ which directly dispatches the build status into our `Discord `__. This allows us to spot and fix broken code easily. 15 | 16 | - `Our CI setup `__ is inspired by a `blog entry `__ by `Adam Sawicki `__. 17 | 18 | .. Badges. 19 | 20 | .. |github actions| image:: https://img.shields.io/github/workflow/status/inexorgame/vulkan-renderer/Build 21 | :target: https://github.com/inexorgame/vulkan-renderer/actions?query=workflow%3A%22Build%22 22 | -------------------------------------------------------------------------------- /documentation/source/development/clang-format-and-ci-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/clang-format-and-ci-example.jpg -------------------------------------------------------------------------------- /documentation/source/development/clang-format.rst: -------------------------------------------------------------------------------- 1 | Clang format 2 | ============ 3 | 4 | - In order to have one unified code formatting style, we use `clang-format `__. 5 | - Clang-format automatically formats source code according to a set of rules which a project needs to agree on. 6 | - Our current style can be found in the `clang-format file `__ file in the root folder of the `repository `__. 7 | - We recommend to install plugins which auto format the code when the file is being saved. 8 | - Instructions for how to enable clang-format in `Microsoft Visual Studio `__ can be found `here `__. 9 | - Other editors like `Visual Studio Code `__, `Atom.io `__, `Notepad++ `__ and `Sublime Text `__ support this as well. 10 | - Part of our `Continuous Integration (CI) `__ are automated clang-format checks using `GitHub actions `__. 11 | - Our setup of clang-format with GitHub actions can be `here `__. 12 | - A pull request will only be accepted if it follows those code formatting rules. 13 | 14 | **Example of clang-format checking a pull request along with gcc/clang/msvc build**: 15 | 16 | .. image:: clang-format-and-ci-example.jpg 17 | :alt: Example of Continuous Integration (CI) at work. 18 | -------------------------------------------------------------------------------- /documentation/source/development/debugging/cla.rst: -------------------------------------------------------------------------------- 1 | Command Line Arguments 2 | ====================== 3 | 4 | You can start vulkan-renderer with the following command line arguments: 5 | 6 | .. option:: --gpu 7 | 8 | Specifies which GPU to use by array index, **starting from 0**. 9 | 10 | .. note:: The engine checks if this index is valid. If the index is invalid, automatic GPU selection rules apply. 11 | 12 | .. option:: --no-separate-data-queue 13 | 14 | Disables the use of the special `data transfer queue `__ (forces use of the graphics queue). 15 | 16 | .. warning:: Enabling this option could decrease the overall performance. Don't enable this option unless you have to. 17 | 18 | .. option:: --no-validation 19 | 20 | Disables `Vulkan validation layers `__. 21 | 22 | .. warning:: You should never disable validation layers because they offer extensive error checks for debugging. 23 | 24 | .. option:: --no-vk-debug-markers 25 | 26 | Disables `Vulkan debug markers `__ (even if ``--renderdoc`` is specified). 27 | 28 | .. option:: --renderdoc 29 | 30 | Enables the `RenderDoc `__ debug layer. 31 | 32 | .. option:: --vsync 33 | 34 | .. warning:: Vsync is currently not implemented. The command line argument will be ignored. 35 | 36 | Enables `vertical synchronization `__ (limits FPS to monitor refresh rate). 37 | -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/log_console.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/log_console.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/RenderDoc_step_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/RenderDoc_step_1.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/RenderDoc_step_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/RenderDoc_step_2.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/RenderDoc_step_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/RenderDoc_step_3.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/RenderDoc_step_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/RenderDoc_step_4.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/RenderDoc_step_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/RenderDoc_step_5.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/RenderDoc_step_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/RenderDoc_step_6.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/RenderDoc_step_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/RenderDoc_step_7.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/RenderDoc_step_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/RenderDoc_step_8.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/RenderDoc_step_9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/RenderDoc_step_9.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/VisualStudioBreakpoint.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/VisualStudioBreakpoint.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/renderdoc/VisualStudioDebugging.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/renderdoc/VisualStudioDebugging.jpg -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/vma_dump_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/vma_dump_example.png -------------------------------------------------------------------------------- /documentation/source/development/debugging/images/vma_saves_the_day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/debugging/images/vma_saves_the_day.png -------------------------------------------------------------------------------- /documentation/source/development/debugging/logfiles.rst: -------------------------------------------------------------------------------- 1 | Logfiles 2 | ======== 3 | 4 | Inexor uses `spdlog `__ for both console logging and logfiles. 5 | 6 | .. image:: images/log_console.jpg 7 | :width: 600 8 | :alt: Example of Inexor engine console output. 9 | 10 | The log output which can be seen in the console will also be written to ``vulkan-renderer.log`` in the root directory. 11 | 12 | You can open and read this logfile with a text editor of your choice. 13 | 14 | We are using the following log entry format ``%Y-%m-%d %T.%f %^%l%$ %5t [%-10n] %v``. 15 | 16 | - ``%Y`` is the year. 17 | - ``%m`` is the month (01 to 12). 18 | - ``%d`` is the day of month (01 to 31). 19 | - ``%T`` is `ISO 8601 `__ time format (HH:MM:SS). 20 | - ``%f`` is the microsecond part of the current second. 21 | - ``%^%l%$`` is the `color-coded `__ log level. 22 | - ``%5t`` is the thread id formatted to a string of length 5. 23 | - ``[%-10n]`` is the name of the logger, limited to 10 characters. 24 | - ``%v`` is the log message. 25 | 26 | For more information, check out spdlog's documentation about `custom formatting `__. 27 | 28 | **Use the following rules for logging**: 29 | 30 | - Don't use ``std::cout`` or ``printf`` or similar. Just use spdlog instead. 31 | - Place as many log messages to your code as possible. 32 | - End log messages with a ``.`` to show that the message is finished. 33 | - Use all log levels as you need it: ``spdlog::trace``, ``spdlog::info``, ``spdlog::debug``, ``spdlog::error``, ``spdlog::critical``. 34 | - You can print variables with spdlog (see `this reference `__) because it is based on `fmt library `__. 35 | - Use direct API calls like ``spdlog::debug("Example text here");`` instead of creating your own logger name for now. We will come up with a strategy for logger hierarchy later. 36 | -------------------------------------------------------------------------------- /documentation/source/development/debugging/main.rst: -------------------------------------------------------------------------------- 1 | ********* 2 | Debugging 3 | ********* 4 | 5 | .. toctree:: 6 | :maxdepth: 1 7 | 8 | logfiles 9 | cla 10 | renderdoc 11 | vma-dumps 12 | -------------------------------------------------------------------------------- /documentation/source/development/debugging/vma-dumps.rst: -------------------------------------------------------------------------------- 1 | VMA dumps 2 | ========= 3 | 4 | - For memory management, Inexor uses `AMD's Vulkan Memory Allocator library (VMA) `__. 5 | - VMA can export an overview of the current GPU memory allocations into a JSON file which can be converted into an image using `VMA's VmaDumpVis `__. 6 | - This way we can see which memory pools exist, which memory blocks are allocated, and what they are used for. 7 | - The example image provided here might look very simple, but with increasing complexity of our engine this will turn out very helpful. 8 | 9 | This is a very simple example of such an image generated with VmaDumpVis: 10 | 11 | .. image:: images/vma_dump_example.png 12 | :width: 600 13 | :alt: Example of a memory allocation overview generated by VmaDumpVis. 14 | 15 | **Example: march 2020 texture memory corruption bug** 16 | 17 | - In march 2020, a `bug in Inexor's early graphics memory management `__ caused textures to corrupt on window resize. 18 | - VmaDumpVis helped to resolve the issue by proving the memory consumption increased after each resize, which means the texture memory was simply not freed when the swapchain was recreated. 19 | - This is an example of how VMA and VmaDumpVis make debugging graphics memory easier. 20 | 21 | .. image:: images/vma_saves_the_day.png 22 | :width: 600 23 | :alt: Example of a VmaDumpVis being used to detect memory leaks. 24 | -------------------------------------------------------------------------------- /documentation/source/development/getting-started.rst: -------------------------------------------------------------------------------- 1 | .. _GETTING_STARTED: 2 | 3 | Getting started 4 | =============== 5 | 6 | Also see the :ref:`building instructions` (:ref:`BUILDING Windows`/:ref:`BUILDING Linux`). 7 | 8 | Required Software 9 | ----------------- 10 | 11 | `Git `__ 12 | Git for cloning (downloading) the source code. 13 | 14 | `Python `__ with `pip `__ 15 | Required for generating the documentation and the C++ package manager. 16 | 17 | `CMake `__ 18 | The build generator which generates project files for various IDEs. 19 | 20 | `Vulkan SDK `__ 21 | Vulkan SDK contains the libraries and tools which are necessary to work with Vulkan API. 22 | 23 | Update your Vulkan SDK as often as possible, because new versions will be released frequently which contains new features and bug fixes. 24 | 25 | Make sure you add the ``glslangValidator`` in the Vulkan SDK's bin folder to your path variable. 26 | 27 | Optional Software 28 | ----------------- 29 | 30 | `GitKraken Git GUI `__. 31 | A Git user interface with many features which is easy to use. 32 | 33 | `GitHub Desktop `__ 34 | An open source Git user interface which is easy to use. 35 | 36 | `Ninja Build System `__ 37 | Improve your build times with ninja. 38 | 39 | `RenderDoc `__ 40 | Powerful open source graphics debugger. Inexor has full RenderDoc integration. 41 | 42 | `Doxygen `__ 43 | Required for generating the documentation. 44 | 45 | `Notepad++ `__ 46 | Free and open source text editor. 47 | 48 | `Atom.io `__ 49 | Free and open source text editor. 50 | 51 | `Visual Studio Code `__ 52 | Free and open source text editor. 53 | 54 | 55 | Does my graphics card support Vulkan? 56 | ------------------------------------- 57 | 58 | - You can look up your graphics card in `Sascha Willem's Vulkan hardware database `__. 59 | - Every new graphics card which is coming out these days supports Vulkan API. 60 | - Vulkan is also supported on older graphics cards going back to `Radeon HD 7000 series `__ and `Nvidia Geforce 6 series `__. 61 | 62 | 63 | Update your graphics drivers! 64 | ----------------------------- 65 | 66 | - Update your graphics drivers as often as possible. 67 | - New drivers contain new features, bug fixes, and performance improvements. 68 | -------------------------------------------------------------------------------- /documentation/source/development/main.rst: -------------------------------------------------------------------------------- 1 | *********** 2 | Development 3 | *********** 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | 8 | platforms 9 | getting-started 10 | building 11 | debugging/main 12 | engine-design/main 13 | ci 14 | clang-format 15 | test-automation 16 | benchmarking 17 | static-code-analysis 18 | reference/main 19 | labeling 20 | -------------------------------------------------------------------------------- /documentation/source/development/platforms.rst: -------------------------------------------------------------------------------- 1 | Supported platforms 2 | =================== 3 | 4 | - Vulkan API is completely platform-agnostic, which allows it to run on various operating systems. 5 | - The required drivers for Vulkan are usually part of your graphic card's drivers. 6 | - Update your graphics drivers as often as possible since new drivers with Vulkan updates are released frequently. 7 | - Driver updates contain new features, bug fixes, and performance improvements. 8 | - Check out `Khronos website `__ for more information. 9 | 10 | Microsoft Windows 11 | ----------------- 12 | 13 | - We support x64 Microsoft Windows 8, 8.1 and 10. 14 | - We have :ref:`build instructions for Windows`. 15 | 16 | Linux 17 | ------ 18 | 19 | - We support every x64 Linux distribution for which Vulkan drivers exist. 20 | - We have specific :ref:`build instructions for Gentoo, Ubuntu, Debian, and Arch. `. 21 | - If you have found a way to set it up for other Linux distributions, please `open a pull request `__ and let us know! 22 | 23 | macOS and iOS 24 | ------------- 25 | 26 | - We do not support macOS or iOS because it would require us to use `MoltenVK `__ to get Vulkan running on Mac OS. 27 | - Additionally, this would require some changes in the engines as not all of Inexor's dependencies are available on macOS or iOS. 28 | 29 | Android 30 | ------- 31 | 32 | - We also do not support Android because this would require some changes in the engines as not all of Inexor's dependencies are available on Android. 33 | -------------------------------------------------------------------------------- /documentation/source/development/reference/gpu-selection.rst: -------------------------------------------------------------------------------- 1 | GPU selection mechanism 2 | ======================= 3 | 4 | - In Vulkan API, the word physical device is a more general word for all types of graphics cards, integrated gpus and more 5 | - If multiple physical devices are available on the system, Inexor engine is able to pick the most suitable one automatically 6 | - The user can specify a preferred graphics card index with the command line argument ``--gpu `` (starting with index ``0``!) 7 | - If a preferred index is specified, the engine will verify if the index is valid and pick the physical device if it is suitable 8 | - If the physical device specified by the user is not suitable because of technical reasons, automatic selection rules apply 9 | - The engine calculates a score for every available physical device based on the device type and total video memory size 10 | - If no physical devices are available or no suitable physical device could be chosen, an exception is thrown 11 | -------------------------------------------------------------------------------- /documentation/source/development/reference/keyboard-mouse-input.rst: -------------------------------------------------------------------------------- 1 | Keyboard and mouse input 2 | ======================== 3 | 4 | Inexor engine uses `glfw3 `__ for window management and for keyboard and mouse input. Inexor does not use `manual polling `__ of keyboard and mouse input data, but uses `callbacks `__ instead. This way, we ensure we are not missing a key event. For more information check out `glfw's input guide `__. Inexor uses a wrapper class for keyboard and mouse input data, called ``KeyboardMouseInputData``. This class offers an easy-to-use interface for setting and getting keyboard and mouse input. ``KeyboardMouseInputData`` is thread safe since `pull request 401. `__ 5 | 6 | .. note:: 7 | 8 | Inexor redirects keyboard and mouse input events to class methods which handle it. Because glfw is a C-style API, it is not possible to use class methods directly as callbacks for keyboard and mouse input data. To fix this, we set the glfw window user pointer to the class instance which contains the input callback methods. Then, we use a lambda to set up the class method as callback. All setups are done in ``Application::setup_window_and_input_callbacks``. For more information about this workaround, check out this `Stackoverflow issue `__. 9 | 10 | .. note:: 11 | 12 | It's not possible handle glfw input data in a thread which is separate from the thread which created the corresponding window. For more information, check out this `glfw forum post `__. 13 | 14 | Keyboard input 15 | -------------- 16 | 17 | * We store the pressed keys as a ``std::array`` member in ``KeyboardMouseInputData`` 18 | * The maximum number of keys is defined by ``GLFW_KEY_LAST`` 19 | * If a key is pressed or released, we notify ``KeyboardMouseInputData`` by calling method ``press_key`` and ``release_key``, respectively 20 | * Check if a key is currently pressed by calling method ``is_key_pressed`` 21 | * Check if a key was pressed once by calling method ``was_key_pressed_once`` 22 | 23 | Mouse input 24 | ----------- 25 | 26 | * We store the pressed mouse buttons as a ``std::array`` member in ``KeyboardMouseInputData`` 27 | * The maximum number of mouse buttons is defined by ``GLFW_MOUSE_BUTTON_LAST``. 28 | * If a mouse button is pressed or released, we notify ``KeyboardMouseInputData`` by calling method ``press_mouse_button`` and ``release_mouse_button``, respectively 29 | * To update the current cursor position, we call ``set_cursor_pos`` 30 | * To get the current cursor position, we call ``get_cursor_pos`` 31 | * The change in cursor position can be queried with ``calculate_cursor_position_delta`` 32 | * Check if a mouse button is pressed by calling method ``is_mouse_button_pressed`` 33 | * Check if a mouse button was pressed once by calling method ``was_mouse_button_pressed_once`` 34 | 35 | Joysticks 36 | --------- 37 | 38 | Inexor does not support `joysticks `__ yet. 39 | -------------------------------------------------------------------------------- /documentation/source/development/reference/main.rst: -------------------------------------------------------------------------------- 1 | ********* 2 | Reference 3 | ********* 4 | 5 | .. toctree:: 6 | :maxdepth: 1 7 | 8 | gpu-selection 9 | binary-format-specification 10 | keyboard-mouse-input 11 | octree-file-format 12 | octree-collision 13 | command-buffers-and-command-pools 14 | -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_boundin_sphere_false_positive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_boundin_sphere_false_positive.jpg -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_camera_view_blocked.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_camera_view_blocked.jpg -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_cases.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_cases.jpg -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_cube_facing_camera.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_cube_facing_camera.jpg -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_filled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_filled.jpg -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_multiple_octrees.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_multiple_octrees.jpg -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_nearest_corner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_nearest_corner.jpg -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_octant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_octant.jpg -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_only_front_collisions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_only_front_collisions.jpg -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_real_face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_real_face.jpg -------------------------------------------------------------------------------- /documentation/source/development/reference/octree_collision_sizes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/development/reference/octree_collision_sizes.jpg -------------------------------------------------------------------------------- /documentation/source/development/static-code-analysis.rst: -------------------------------------------------------------------------------- 1 | Static code analysis 2 | ==================== 3 | 4 | We analyze our source code regularly using `static code analysis `__. 5 | 6 | The following tools are used: 7 | 8 | - `Clang-tidy `__. 9 | - `Microsoft Visual Studio code analysis `__. 10 | - `Valgrind `__, `Callgrind `__ and `Cachegrind `__. 11 | -------------------------------------------------------------------------------- /documentation/source/development/test-automation.rst: -------------------------------------------------------------------------------- 1 | Test automation 2 | =============== 3 | 4 | - Inexor will use `Google Test `__ for `automated software testing `__ in the future. 5 | - Running automatic tests using GitHub actions is not possible for Vulkan features since this requires a graphics card to be present. 6 | - There are some services which offer test automation for rendering, but they are not free. 7 | - The tests would have to run on the developer's machine locally. 8 | -------------------------------------------------------------------------------- /documentation/source/images/icon_CLion.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | icon_CLion 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /documentation/source/images/inexor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/images/inexor.png -------------------------------------------------------------------------------- /documentation/source/images/vulkan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inexorgame/vulkan-renderer/61343bb14107bf90f50b26eb29685d22c7c9fc65/documentation/source/images/vulkan.png -------------------------------------------------------------------------------- /documentation/source/index.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Vulkan-Renderer 3 | =============== 4 | 5 | |language| |platforms| |github actions| |readthedocs| |discord| |license| 6 | 7 | .. image:: /images/inexor-banner.svg 8 | 9 | **Inexor is a MIT-licensed open-source project which develops a new 3D octree game engine by combining modern C++ with Vulkan API.** 10 | 11 | 12 | Documentation 13 | ############# 14 | 15 | Quickstart: :ref:`Building Instructions` (:ref:`BUILDING Windows`/:ref:`BUILDING Linux`) & :ref:`Getting started` 16 | 17 | .. toctree:: 18 | :maxdepth: 2 19 | 20 | development/main 21 | code/main 22 | contributing/main 23 | faq/main 24 | changelog/main 25 | links/main 26 | license/main 27 | contact/main 28 | 29 | .. include:: /faq/main.rst 30 | 31 | .. Badges. 32 | 33 | .. |language| image:: https://img.shields.io/badge/language-C%2B%2B17-brightgreen 34 | 35 | .. |platforms| image:: https://img.shields.io/badge/platforms-Linux%20%26%20Windows-brightgreen 36 | 37 | .. |github actions| image:: https://img.shields.io/github/workflow/status/inexorgame/vulkan-renderer/Build 38 | :target: https://github.com/inexorgame/vulkan-renderer/actions?query=workflow%3A%22Build%22 39 | 40 | .. |discord| image:: https://img.shields.io/discord/698219248954376256?logo=discord 41 | :target: https://discord.com/invite/acUW8k7 42 | 43 | .. |license| image:: https://img.shields.io/github/license/inexorgame/vulkan-renderer?color=brightgreen 44 | :target: https://inexor-vulkan-renderer.readthedocs.io/en/latest/license/main.html 45 | 46 | .. |contributors| image:: https://img.shields.io/github/contributors/inexorgame/vulkan-renderer 47 | :target: https://inexor-vulkan-renderer.readthedocs.io/en/latest/contributing/contributors.html 48 | 49 | .. |downloads| image:: https://img.shields.io/github/downloads/inexorgame/vulkan-renderer/total?color=brightgreen 50 | 51 | .. |readthedocs| image:: https://readthedocs.org/projects/inexor-vulkan-renderer/badge/?version=latest 52 | :target: https://inexor-vulkan-renderer.readthedocs.io 53 | 54 | .. |last commit| image:: https://img.shields.io/github/last-commit/inexorgame/vulkan-renderer 55 | 56 | .. |issues| image:: https://img.shields.io/github/issues/inexorgame/vulkan-renderer 57 | :target: https://github.com/inexorgame/vulkan-renderer/issues 58 | 59 | .. |code size| image:: https://img.shields.io/github/languages/code-size/inexorgame/vulkan-renderer 60 | -------------------------------------------------------------------------------- /documentation/source/license/main.rst: -------------------------------------------------------------------------------- 1 | ******************* 2 | Source Code License 3 | ******************* 4 | 5 | 6 | 7 | .. include:: ../../../LICENSE 8 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(inexor-vulkan-renderer-example main.cpp) 2 | 3 | target_compile_features(inexor-vulkan-renderer-example PRIVATE cxx_std_20) 4 | target_link_libraries(inexor-vulkan-renderer-example PRIVATE inexor-vulkan-renderer) 5 | 6 | if(${CMAKE_GENERATOR} MATCHES "Visual Studio.*") 7 | set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT "inexor-vulkan-renderer-example") 8 | target_compile_options(inexor-vulkan-renderer-example PRIVATE "/MP") 9 | set_target_properties( 10 | inexor-vulkan-renderer-example 11 | PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" 12 | ) 13 | # Ignore MSVC linker warning LNK4099 14 | set_target_properties(inexor-vulkan-renderer-example PROPERTIES LINK_FLAGS "/ignore:4099") 15 | endif() 16 | 17 | # enable exceptions when using MSVC toolchain, makes Clang on windows possible 18 | if(MSVC) 19 | target_compile_options(inexor-vulkan-renderer-example PRIVATE "-EHs") 20 | endif() 21 | -------------------------------------------------------------------------------- /example/main.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/application.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | int main(int argc, char *argv[]) { 11 | spdlog::init_thread_pool(8192, 2); 12 | 13 | auto console_sink = std::make_shared(); 14 | auto file_sink = std::make_shared("vulkan-renderer.log", true); 15 | auto vulkan_renderer_log = 16 | std::make_shared("vulkan-renderer", spdlog::sinks_init_list{console_sink, file_sink}, 17 | spdlog::thread_pool(), spdlog::async_overflow_policy::block); 18 | vulkan_renderer_log->set_level(spdlog::level::trace); 19 | vulkan_renderer_log->set_pattern("%Y-%m-%d %T.%f %^%l%$ %5t [%-10n] %v"); 20 | vulkan_renderer_log->flush_on(spdlog::level::debug); // TODO: as long as we don't have a flush on crash 21 | 22 | spdlog::set_default_logger(vulkan_renderer_log); 23 | 24 | spdlog::trace("Inexor vulkan-renderer, BUILD " + std::string(__DATE__) + ", " + __TIME__); 25 | spdlog::trace("Parsing command line arguments"); 26 | 27 | std::unique_ptr renderer; 28 | 29 | try { 30 | renderer = std::make_unique(argc, argv); 31 | } catch (const std::runtime_error &exception) { 32 | spdlog::critical(exception.what()); 33 | return 1; 34 | } catch (const std::exception &exception) { 35 | spdlog::critical(exception.what()); 36 | return 1; 37 | } 38 | 39 | renderer->run(); 40 | spdlog::trace("Window closed"); 41 | } 42 | -------------------------------------------------------------------------------- /helper/commit_validator.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | Used in GitHub Actions to validate commits. 3 | */ 4 | let Commit 5 | let CommitValidator 6 | let Result 7 | let Status 8 | 9 | export function import_types(commitValidatorCls, commitCls, resultCls, statusCls) { 10 | CommitValidator = commitValidatorCls 11 | Commit = commitCls 12 | Result = resultCls 13 | Status = statusCls 14 | } 15 | 16 | export function createValidator() { 17 | return class Validator extends CommitValidator { 18 | static rx_parser = new RegExp('^\\[(.*)] (.*)$') 19 | static rx_category = new RegExp('^\\*|(?:[a-z0-9]{2,}[ |-]?)+$') 20 | static rx_description = new RegExp('^[A-Z0-9]\\S*(?:\\s\\S*)+[^.!?,\\s]$') 21 | 22 | validate_message(summary, _description) { 23 | const match = Validator.rx_parser.exec(summary) 24 | if (match === null) { 25 | return new Result( 26 | Status.Failure, 27 | 'Summary has invalid format. It should be \'[] \'' 28 | ) 29 | } 30 | if (!Validator.rx_category.test(match[1])) { 31 | return new Result( 32 | Status.Failure, 33 | "Invalid category tag. It should be either a single '*' or completely lowercase " + 34 | "letters or numbers, at least 2 characters long, other allowed characters are: '|', '-' and spaces." 35 | ) 36 | } 37 | if (!Validator.rx_description.test(match[2])) { 38 | return new Result( 39 | Status.Failure, 40 | 'Invalid description. It should start with an uppercase letter or number, ' + 41 | 'should be not to short and should not end with a punctuation.' 42 | ) 43 | } 44 | return new Result(Status.Ok) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /helper/req_check.py: -------------------------------------------------------------------------------- 1 | """ 2 | Check if all packages of a python requirement file are satisfied. 3 | 4 | Copyright 2021-present Iceflower - iceflower@gmx.de 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | """ 12 | 13 | from argparse import ArgumentParser 14 | from pathlib import Path 15 | 16 | import importlib.metadata as im 17 | import packaging.version as pv 18 | import re 19 | import sys 20 | 21 | 22 | def cmd_parser() -> ArgumentParser: 23 | parser = ArgumentParser(prog="req_check", 24 | description="Check if a python installation matches a requirements.txt file") 25 | 26 | parser.add_argument(dest='req_file', type=str, help='path to requirements.txt') 27 | parser.add_argument('--quiet', dest='quiet', action='store_true', default=False, help='output nothing') 28 | 29 | return parser 30 | 31 | 32 | def main(): 33 | args = cmd_parser().parse_args(sys.argv[1:]) 34 | 35 | with Path(args.req_file).open(mode='r', encoding='UTF-8') as reader: 36 | dependencies = reader.read() 37 | 38 | success: bool = True 39 | rx_pkg: re.Pattern = re.compile(r"(.+)(==|<=|>=)(.+)") 40 | for pkg in dependencies.split('\n'): 41 | match: re.Match = rx_pkg.match(pkg) 42 | pkg_name: str = match.group(1) 43 | pkg_req: str = match.group(2) 44 | pkg_version: pv.Version = pv.parse(match.group(3)) 45 | try: 46 | installed_version: pv.Version = pv.parse(im.version(pkg_name)) 47 | if ( 48 | pkg_req == "==" and installed_version != pkg_version 49 | or pkg_req == "<=" and installed_version > pkg_version 50 | or pkg_req == ">=" and installed_version < pkg_version 51 | ): 52 | success = False 53 | if not args.quiet: 54 | print(f"Found: '{installed_version}', but '{pkg_req}{pkg_version}' is required.") 55 | elif not args.quiet: 56 | print(f"Found: '{pkg}'.") 57 | except im.PackageNotFoundError: 58 | success = False 59 | if not args.quiet: 60 | print(f"Did not found '{pkg}', but is required.") 61 | exit(0) if success else exit(1) 62 | 63 | 64 | if __name__ == '__main__': 65 | main() 66 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/application.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inexor/vulkan-renderer/input/keyboard_mouse_data.hpp" 4 | #include "inexor/vulkan-renderer/renderer.hpp" 5 | #include "inexor/vulkan-renderer/world/collision_query.hpp" 6 | #include "inexor/vulkan-renderer/world/cube.hpp" 7 | 8 | // Forward declarations 9 | namespace inexor::vulkan_renderer::input { 10 | class KeyboardMouseInputData; 11 | } // namespace inexor::vulkan_renderer::input 12 | 13 | namespace inexor::vulkan_renderer { 14 | 15 | class Application : public VulkanRenderer { 16 | std::vector m_vertex_shader_files; 17 | std::vector m_fragment_shader_files; 18 | std::vector m_texture_files; 19 | std::vector m_gltf_model_files; 20 | 21 | std::unique_ptr m_input_data; 22 | 23 | bool m_enable_validation_layers{true}; 24 | /// Inexor engine supports a variable number of octrees. 25 | std::vector> m_worlds; 26 | 27 | // If the user specified command line argument "--stop-on-validation-message", the program will call 28 | // std::abort(); after reporting a validation layer (error) message. 29 | bool m_stop_on_validation_message{false}; 30 | 31 | /// @brief Load the configuration of the renderer from a TOML configuration file. 32 | /// @brief file_name The TOML configuration file. 33 | /// @note It was collectively decided not to use JSON for configuration files. 34 | void load_toml_configuration_file(const std::string &file_name); 35 | void load_textures(); 36 | void load_shaders(); 37 | /// @param initialize Initialize worlds with a fixed seed, which is useful for benchmarking and testing 38 | void load_octree_geometry(bool initialize); 39 | void setup_vulkan_debug_callback(); 40 | void setup_window_and_input_callbacks(); 41 | void update_imgui_overlay(); 42 | void update_uniform_buffers(); 43 | /// Use the camera's position and view direction vector to check for ray-octree collisions with all octrees. 44 | void check_octree_collisions(); 45 | void process_mouse_input(); 46 | 47 | public: 48 | Application(int argc, char **argv); 49 | 50 | /// @brief Call glfwSetKeyCallback. 51 | /// @param window The window that received the event. 52 | /// @param key The keyboard key that was pressed or released. 53 | /// @param scancode The system-specific scancode of the key. 54 | /// @param action GLFW_PRESS, GLFW_RELEASE or GLFW_REPEAT. 55 | /// @param mods Bit field describing which modifier keys were held down. 56 | void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods); 57 | 58 | /// @brief Call glfwSetCursorPosCallback. 59 | /// @param window The window that received the event. 60 | /// @param x_pos The new x-coordinate, in screen coordinates, of the cursor. 61 | /// @param y_pos The new y-coordinate, in screen coordinates, of the cursor. 62 | void cursor_position_callback(GLFWwindow *window, double x_pos, double y_pos); 63 | 64 | /// @brief Call glfwSetMouseButtonCallback. 65 | /// @param window The window that received the event. 66 | /// @param button The mouse button that was pressed or released. 67 | /// @param action One of GLFW_PRESS or GLFW_RELEASE. 68 | /// @param mods Bit field describing which modifier keys were held down. 69 | void mouse_button_callback(GLFWwindow *window, int button, int action, int mods); 70 | 71 | /// @brief Call camera's process_mouse_scroll method. 72 | /// @param window The window that received the event. 73 | /// @param x_offset The change of x-offset of the mouse wheel. 74 | /// @param y_offset The change of y-offset of the mouse wheel. 75 | void mouse_scroll_callback(GLFWwindow *window, double x_offset, double y_offset); 76 | 77 | void run(); 78 | }; 79 | 80 | } // namespace inexor::vulkan_renderer 81 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/exception.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace inexor::vulkan_renderer { 9 | 10 | /// @brief A custom base class for exceptions 11 | class InexorException : public std::runtime_error { 12 | public: 13 | // No need to define own constructors. 14 | using std::runtime_error::runtime_error; 15 | }; 16 | 17 | /// @brief InexorException for Vulkan specific things. 18 | class VulkanException final : public InexorException { 19 | public: 20 | /// @param message The exception message. 21 | /// @param result The VkResult value of the Vulkan API call which failed. 22 | VulkanException(std::string message, VkResult result); 23 | }; 24 | 25 | } // namespace inexor::vulkan_renderer 26 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/fps_counter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace inexor::vulkan_renderer { 8 | 9 | /// @brief A class for counting frames per seconds. 10 | class FPSCounter { 11 | std::uint32_t m_frames{0}; 12 | 13 | std::chrono::time_point m_last_time; 14 | 15 | float m_fps_update_interval{1.0f}; 16 | 17 | public: 18 | std::optional update(); 19 | }; 20 | 21 | } // namespace inexor::vulkan_renderer 22 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/imgui.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inexor/vulkan-renderer/render_graph.hpp" 4 | #include "inexor/vulkan-renderer/wrapper/descriptor.hpp" 5 | #include "inexor/vulkan-renderer/wrapper/gpu_texture.hpp" 6 | #include "inexor/vulkan-renderer/wrapper/shader.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | // Forward declarations 16 | namespace inexor::vulkan_renderer::wrapper { 17 | class Device; 18 | class Swapchain; 19 | } // namespace inexor::vulkan_renderer::wrapper 20 | 21 | namespace inexor::vulkan_renderer { 22 | 23 | class ImGUIOverlay { 24 | const wrapper::Device &m_device; 25 | const wrapper::Swapchain &m_swapchain; 26 | float m_scale{1.0f}; 27 | 28 | BufferResource *m_index_buffer{nullptr}; 29 | BufferResource *m_vertex_buffer{nullptr}; 30 | GraphicsStage *m_stage{nullptr}; 31 | 32 | std::unique_ptr m_imgui_texture; 33 | std::unique_ptr m_vertex_shader; 34 | std::unique_ptr m_fragment_shader; 35 | std::unique_ptr m_descriptor; 36 | std::vector m_index_data; 37 | std::vector m_vertex_data; 38 | 39 | struct PushConstBlock { 40 | glm::vec2 scale; 41 | glm::vec2 translate; 42 | } m_push_const_block{}; 43 | 44 | public: 45 | /// @brief Construct a new ImGUI overlay. 46 | /// @param device A reference to the device wrapper 47 | /// @param swapchain A reference to the swapchain 48 | /// @param render_graph A pointer to the render graph 49 | /// @param back_buffer A pointer to the target of the ImGUI rendering 50 | ImGUIOverlay(const wrapper::Device &device, const wrapper::Swapchain &swapchain, RenderGraph *render_graph, 51 | TextureResource *back_buffer); 52 | ImGUIOverlay(const ImGUIOverlay &) = delete; 53 | ImGUIOverlay(ImGUIOverlay &&) = delete; 54 | ~ImGUIOverlay(); 55 | 56 | ImGUIOverlay &operator=(const ImGUIOverlay &) = delete; 57 | ImGUIOverlay &operator=(ImGUIOverlay &&) = delete; 58 | 59 | void update(); 60 | 61 | [[nodiscard]] float scale() const { 62 | return m_scale; 63 | } 64 | }; 65 | 66 | } // namespace inexor::vulkan_renderer 67 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/io/byte_stream.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace inexor::vulkan_renderer::io { 7 | 8 | class ByteStream { 9 | protected: 10 | std::vector m_buffer; 11 | 12 | /// Read from file. 13 | [[nodiscard]] static std::vector read_file(const std::filesystem::path &path); 14 | 15 | public: 16 | ByteStream() = default; 17 | explicit ByteStream(std::vector buffer); 18 | /// Read from file. 19 | explicit ByteStream(const std::filesystem::path &path); 20 | 21 | [[nodiscard]] std::size_t size() const; 22 | [[nodiscard]] const std::vector &buffer() const; 23 | }; 24 | 25 | class ByteStreamReader { 26 | private: 27 | const ByteStream &m_stream; 28 | /// Stream iterator. 29 | std::vector::const_iterator m_iter; 30 | 31 | void check_end(std::size_t size) const; 32 | 33 | public: 34 | explicit ByteStreamReader(const ByteStream &stream); 35 | 36 | [[nodiscard]] std::size_t remaining() const; 37 | /// Skip 'size' bytes (std::uint8_t). 38 | void skip(std::size_t size); 39 | 40 | /// Generic read method. 41 | template 42 | [[nodiscard]] T read(const Args &...); 43 | }; 44 | 45 | class ByteStreamWriter : public ByteStream { 46 | public: 47 | using ByteStream::ByteStream; 48 | 49 | /// Generic write method. 50 | template 51 | void write(const T &value); 52 | }; 53 | 54 | } // namespace inexor::vulkan_renderer::io 55 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/io/exception.hpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/exception.hpp" 2 | 3 | namespace inexor::vulkan_renderer::io { 4 | 5 | class IoException : public InexorException { 6 | using InexorException::InexorException; 7 | }; 8 | 9 | } // namespace inexor::vulkan_renderer::io 10 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/io/nxoc_parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inexor/vulkan-renderer/io/octree_parser.hpp" 4 | 5 | #include 6 | 7 | // Forward declaration 8 | namespace inexor::vulkan_renderer::world { 9 | class Cube; 10 | } // namespace inexor::vulkan_renderer::world 11 | 12 | // Forward declaration 13 | namespace inexor::vulkan_renderer::io { 14 | class ByteStream; 15 | } // namespace inexor::vulkan_renderer::io 16 | 17 | namespace inexor::vulkan_renderer::io { 18 | 19 | class NXOCParser : public OctreeParser { 20 | private: 21 | static constexpr std::uint32_t LATEST_VERSION{0}; 22 | 23 | /// Specific version serialization. 24 | template 25 | [[nodiscard]] ByteStream serialize_impl(std::shared_ptr cube); 26 | /// Specific version deserialization. 27 | template 28 | [[nodiscard]] std::shared_ptr deserialize_impl(const ByteStream &stream); 29 | 30 | public: 31 | /// Serialization of an octree. 32 | [[nodiscard]] ByteStream serialize(std::shared_ptr cube, std::uint32_t version) final; 33 | /// Deserialization of an octree. 34 | [[nodiscard]] std::shared_ptr deserialize(const ByteStream &stream) final; 35 | }; 36 | } // namespace inexor::vulkan_renderer::io 37 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/io/octree_parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // Forward declaration 7 | namespace inexor::vulkan_renderer::world { 8 | class Cube; 9 | } // namespace inexor::vulkan_renderer::world 10 | 11 | namespace inexor::vulkan_renderer::io { 12 | 13 | // Forward declaration 14 | class ByteStream; 15 | 16 | class OctreeParser { 17 | public: 18 | /// Serialization of an octree. 19 | [[nodiscard]] virtual ByteStream serialize(std::shared_ptr cube, std::uint32_t version) = 0; 20 | /// Deserialization of an octree. 21 | [[nodiscard]] virtual std::shared_ptr deserialize(const ByteStream &stream) = 0; 22 | }; 23 | 24 | } // namespace inexor::vulkan_renderer::io 25 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/meta.hpp.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace inexor::vulkan_renderer { 6 | 7 | /// The following data will be replaced by CMake setup. 8 | constexpr const char *APP_NAME{"${INEXOR_APP_NAME}"}; 9 | constexpr std::array APP_VERSION{${INEXOR_APP_VERSION_MAJOR}, ${INEXOR_APP_VERSION_MINOR}, 10 | ${INEXOR_APP_VERSION_PATCH}}; 11 | constexpr const char *APP_VERSION_STR{"${INEXOR_APP_VERSION_MAJOR}.${INEXOR_APP_VERSION_MINOR}.${INEXOR_APP_VERSION_PATCH}"}; 12 | constexpr const char* ENGINE_NAME{"${INEXOR_ENGINE_NAME}"}; 13 | constexpr std::array ENGINE_VERSION{${INEXOR_ENGINE_VERSION_MAJOR}, ${INEXOR_ENGINE_VERSION_MINOR}, 14 | ${INEXOR_ENGINE_VERSION_PATCH}}; 15 | constexpr const char *ENGINE_VERSION_STR{"${INEXOR_ENGINE_VERSION_MAJOR}.${INEXOR_ENGINE_VERSION_MINOR}.${INEXOR_ENGINE_VERSION_PATCH}"}; 16 | constexpr const char *BUILD_GIT = "${INEXOR_GIT_SHA}"; 17 | constexpr const char *BUILD_TYPE = "${CMAKE_BUILD_TYPE}"; 18 | 19 | } // namespace inexor::vulkan_renderer 20 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/octree_gpu_vertex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace inexor::vulkan_renderer { 7 | 8 | struct OctreeGpuVertex { 9 | glm::vec3 position; 10 | glm::vec3 color; 11 | 12 | OctreeGpuVertex(glm::vec3 position, glm::vec3 color) : position(position), color(color) {} 13 | }; 14 | 15 | // inline to suppress clang-tidy warning. 16 | inline bool operator==(const OctreeGpuVertex &lhs, const OctreeGpuVertex &rhs) { 17 | return lhs.position == rhs.position && lhs.color == rhs.color; 18 | } 19 | 20 | } // namespace inexor::vulkan_renderer 21 | 22 | namespace std { 23 | 24 | template <> 25 | struct hash { 26 | std::size_t operator()(const inexor::vulkan_renderer::OctreeGpuVertex &vertex) const { 27 | const auto h1 = std::hash{}(vertex.position); 28 | const auto h2 = std::hash{}(vertex.color); 29 | return h1 ^ h2; 30 | } 31 | }; 32 | 33 | } // namespace std 34 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/renderer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inexor/vulkan-renderer/camera.hpp" 4 | #include "inexor/vulkan-renderer/fps_counter.hpp" 5 | #include "inexor/vulkan-renderer/imgui.hpp" 6 | #include "inexor/vulkan-renderer/octree_gpu_vertex.hpp" 7 | #include "inexor/vulkan-renderer/time_step.hpp" 8 | #include "inexor/vulkan-renderer/wrapper/instance.hpp" 9 | #include "inexor/vulkan-renderer/wrapper/uniform_buffer.hpp" 10 | #include "inexor/vulkan-renderer/wrapper/window.hpp" 11 | #include "inexor/vulkan-renderer/wrapper/window_surface.hpp" 12 | 13 | namespace inexor::vulkan_renderer { 14 | 15 | class VulkanRenderer { 16 | protected: 17 | std::vector m_shader_stages; 18 | 19 | VkDebugReportCallbackEXT m_debug_report_callback{VK_NULL_HANDLE}; 20 | 21 | bool m_debug_report_callback_initialised{false}; 22 | 23 | TimeStep m_time_step; 24 | 25 | std::uint32_t m_window_width{0}; 26 | std::uint32_t m_window_height{0}; 27 | wrapper::Window::Mode m_window_mode{wrapper::Window::Mode::WINDOWED}; 28 | 29 | std::string m_window_title; 30 | 31 | FPSCounter m_fps_counter; 32 | 33 | bool m_vsync_enabled{false}; 34 | 35 | std::unique_ptr m_camera; 36 | 37 | std::unique_ptr m_window; 38 | std::unique_ptr m_instance; 39 | std::unique_ptr m_device; 40 | std::unique_ptr m_surface; 41 | std::unique_ptr m_swapchain; 42 | std::unique_ptr m_imgui_overlay; 43 | std::unique_ptr m_render_graph; 44 | 45 | std::vector m_shaders; 46 | std::vector m_textures; 47 | std::vector m_uniform_buffers; 48 | std::vector m_descriptors; 49 | std::vector m_octree_vertices; 50 | std::vector m_octree_indices; 51 | 52 | TextureResource *m_back_buffer{nullptr}; 53 | 54 | // Render graph buffers for octree geometry. 55 | BufferResource *m_index_buffer{nullptr}; 56 | BufferResource *m_vertex_buffer{nullptr}; 57 | 58 | void setup_render_graph(); 59 | void generate_octree_indices(); 60 | void recreate_swapchain(); 61 | void render_frame(); 62 | 63 | public: 64 | VulkanRenderer() = default; 65 | VulkanRenderer(const VulkanRenderer &) = delete; 66 | VulkanRenderer(VulkanRenderer &&) = delete; 67 | ~VulkanRenderer(); 68 | 69 | VulkanRenderer &operator=(const VulkanRenderer &) = delete; 70 | VulkanRenderer &operator=(VulkanRenderer &&) = delete; 71 | 72 | bool m_window_resized{false}; 73 | 74 | /// Necessary for taking into account the relative speed of the system's CPU. 75 | float m_time_passed{0.0f}; 76 | 77 | /// 78 | TimeStep m_stopwatch; 79 | }; 80 | 81 | } // namespace inexor::vulkan_renderer 82 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/standard_ubo.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace inexor::vulkan_renderer { 6 | 7 | /// @note We can exactly match the definition in the shader using data types in GLM. 8 | /// The data in the matrices is binary compatible with the way the shader expects 9 | /// it, so we can later just memcpy a UniformBufferObject to a VkBuffer. 10 | struct UniformBufferObject { 11 | glm::mat4 model; 12 | glm::mat4 view; 13 | glm::mat4 proj; 14 | }; 15 | 16 | } // namespace inexor::vulkan_renderer 17 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/time_step.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace inexor::vulkan_renderer { 6 | 7 | /// @brief Responsible for calculating the amount of time which has passed between rendering two frames. 8 | /// Since every machine has slightly different speed, it is necessary to the timestep when animating something. 9 | /// @todo Implement time step for every thread? 10 | class TimeStep { 11 | // The time point of the last render call. 12 | std::chrono::time_point m_last_time; 13 | 14 | // The time point of initialisation. 15 | std::chrono::time_point m_initialisation_time; 16 | 17 | public: 18 | TimeStep(); 19 | 20 | /// @brief Return a scaling factor which corresponds to the 21 | /// time which has passed since last render call and now. 22 | [[nodiscard]] float time_step(); 23 | 24 | /// @brief Return a scaling factor which corresponds to the 25 | /// time which has passed since initialisation and now. 26 | [[nodiscard]] float time_step_since_initialisation(); 27 | }; 28 | 29 | } // namespace inexor::vulkan_renderer 30 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/tools/file.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace inexor::vulkan_renderer::tools { 7 | 8 | /// @brief Extract the extension of a file as lowercase string. 9 | /// @param file_name the name of the file. This is allowed to include the relative or complete path 10 | /// @return The extension of the file as lowercase 11 | [[nodiscard]] std::string get_file_extension_lowercase(const std::string &file_name); 12 | 13 | /// @brief Read the data of a file into memory 14 | /// @param file_name The name of the file 15 | /// @return A std::vector of type char which contains the binary data of the file 16 | [[nodiscard]] std::vector read_file_binary_data(const std::string &file_name); 17 | 18 | } // namespace inexor::vulkan_renderer::tools 19 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/vk_tools/device_info.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace inexor::vulkan_renderer::vk_tools { 9 | 10 | /// Transform a ``VkPhysicalDeviceFeatures`` into a ``std::vector`` 11 | /// @note The size of the vector will be determined by the number of ``VkBool32`` variables in the 12 | /// ``VkPhysicalDeviceFeatures`` struct 13 | /// @param features The physical device features 14 | /// @return A ``std::vector`` The transformed data 15 | [[nodiscard]] std::vector get_device_features_as_vector(const VkPhysicalDeviceFeatures &features); 16 | 17 | /// Get the name of a physical device 18 | /// @param physical_device The physical device 19 | /// @return The name of the physical device 20 | [[nodiscard]] std::string get_physical_device_name(VkPhysicalDevice physical_device); 21 | 22 | } // namespace inexor::vulkan_renderer::vk_tools 23 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/vk_tools/enumerate.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace inexor::vulkan_renderer::vk_tools { 8 | 9 | /// All functions which contain the word "all" in it, call some vkEnumerate.. function, 10 | /// while all functions without it call vkGet.. 11 | 12 | /// Call vkEnumerateDeviceExtensionProperties 13 | /// @note Because device layers are deprecated in Vulkan, we are not exposing the ``pLayerName`` parameter of 14 | /// ``vkEnumerateDeviceExtensionProperties`` as a parameter here 15 | /// @param physical_device The physical device to get all extension properties form 16 | /// @exception VulkanException vkEnumerateDeviceExtensionProperties call failed 17 | /// @return A std::vector of all device extension properties of a physical device (this can be empty!) 18 | [[nodiscard]] std::vector get_extension_properties(VkPhysicalDevice physical_device); 19 | 20 | /// Call vkEnumeratePhysicalDevices 21 | /// @param inst The Vulkan instance 22 | /// @exception VulkanException vkEnumeratePhysicalDevices call failed 23 | /// @return A std::vector of all physical devices which are available on the system (this can be empty!) 24 | [[nodiscard]] std::vector get_physical_devices(VkInstance inst); 25 | 26 | /// Call vkGetPhysicalDeviceQueueFamilyProperties 27 | /// @param physical_device The physical device to get all extension properties form 28 | /// @exception VulkanException vkGetPhysicalDeviceQueueFamilyProperties call failed 29 | /// @return A std::vector of all queue families which are available on the system (this can be empty!) 30 | [[nodiscard]] std::vector get_queue_family_properties(VkPhysicalDevice physical_device); 31 | 32 | /// Call vkGetPhysicalDeviceSurfacePresentModesKHR 33 | /// @param physical_device The physical device 34 | /// @param surface The surface 35 | /// @exception VulkanException vkGetPhysicalDeviceSurfaceFormatsKHR call failed 36 | /// @return A std::vector of surface formats 37 | [[nodiscard]] std::vector get_surface_formats(VkPhysicalDevice physical_device, 38 | VkSurfaceKHR surface); 39 | 40 | /// Call vkGetPhysicalDeviceSurfacePresentModesKHR 41 | /// @param physical_device The physical device 42 | /// @param surface The surface 43 | /// @exception VulkanException vkGetPhysicalDeviceSurfacePresentModesKHR call failed 44 | /// @return A std::vector of present modes 45 | [[nodiscard]] std::vector get_surface_present_modes(VkPhysicalDevice physical_device, 46 | VkSurfaceKHR surface); 47 | 48 | } // namespace inexor::vulkan_renderer::vk_tools 49 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/vk_tools/representation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace inexor::vulkan_renderer::vk_tools { 8 | 9 | /// @brief This function returns a textual representation of the vulkan object T. 10 | template 11 | [[nodiscard]] std::string_view as_string(T); 12 | 13 | /// Get a feature description of a ``VkBool32`` value in the ``VkPhysicalDeviceFeatures`` struct by index. 14 | /// @param index The index of the ``VkBool32`` value in the ``VkPhysicalDeviceFeatures`` struct. 15 | /// @note If the index is out of bounds, no exception will be thrown, but an empty description will be returned instead. 16 | /// @return A feature description 17 | [[nodiscard]] std::string_view get_device_feature_description(std::size_t index); 18 | 19 | /// @brief Convert a VkResult value into the corresponding error description as std::string_view 20 | /// @param result The VkResult to convert 21 | /// @return A std::string_view which contains an error description text of the VkResult 22 | /// @note This function converts the VkResult into the corresponding error description text 23 | /// If you want to convert it into an std::string_view, see the matching ```as_string``` template 24 | [[nodiscard]] std::string_view result_to_description(VkResult result); 25 | 26 | } // namespace inexor::vulkan_renderer::vk_tools 27 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/world/collision.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace inexor::vulkan_renderer::world { 9 | 10 | /// @brief A wrapper for collisions between a ray and octree geometry. 11 | /// This class is used for octree collision, but it can be used for every cube-like data structure 12 | /// @tparam T A template type which offers a size() and center() method. 13 | template 14 | class RayCubeCollision { 15 | const T &m_cube; 16 | 17 | glm::vec3 m_intersection; 18 | glm::vec3 m_selected_face; 19 | glm::vec3 m_nearest_corner; 20 | glm::vec3 m_nearest_edge; 21 | 22 | public: 23 | /// @brief Calculate point of intersection, selected face, 24 | /// nearest corner on that face, and nearest edge on that face. 25 | /// @param cube The cube to check for collision. 26 | /// @param ray_pos The start point of the ray. 27 | /// @param ray_dir The direction of the ray. 28 | RayCubeCollision(const T &cube, glm::vec3 ray_pos, glm::vec3 ray_dir); 29 | 30 | RayCubeCollision(const RayCubeCollision &) = delete; 31 | 32 | RayCubeCollision(RayCubeCollision &&other) noexcept; 33 | 34 | ~RayCubeCollision() = default; 35 | 36 | RayCubeCollision &operator=(const RayCubeCollision &) = delete; 37 | RayCubeCollision &operator=(RayCubeCollision &&) = delete; 38 | 39 | [[nodiscard]] const T &cube() const noexcept { 40 | return m_cube; 41 | } 42 | 43 | [[nodiscard]] const glm::vec3 &intersection() const noexcept { 44 | return m_intersection; 45 | } 46 | 47 | [[nodiscard]] const glm::vec3 &face() const noexcept { 48 | return m_selected_face; 49 | } 50 | 51 | [[nodiscard]] const glm::vec3 &corner() const noexcept { 52 | return m_nearest_corner; 53 | } 54 | 55 | [[nodiscard]] const glm::vec3 &edge() const noexcept { 56 | return m_nearest_edge; 57 | } 58 | }; 59 | 60 | } // namespace inexor::vulkan_renderer::world 61 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/world/collision_query.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inexor/vulkan-renderer/world/collision.hpp" 4 | 5 | #include 6 | 7 | #include 8 | 9 | // Forward declaration 10 | namespace inexor::vulkan_renderer::world { 11 | class Cube; 12 | } // namespace inexor::vulkan_renderer::world 13 | 14 | namespace inexor::vulkan_renderer::world { 15 | 16 | // TODO: Implement PointCubeCollision 17 | 18 | /// @brief ``True`` of the ray build from the two vectors collides with the cube's bounding box. 19 | /// @note There is no such function as glm::intersectRayBox. 20 | /// @param box_bounds An array of two vectors which represent the edges of the bounding box. 21 | /// @param pos The start position of the ray. 22 | /// @param dir The direction of the ray. 23 | /// @return ``True`` if the ray collides with the octree cube's bounding box. 24 | [[nodiscard]] bool ray_box_collision(std::array &box_bounds, glm::vec3 &pos, glm::vec3 &dir); 25 | 26 | /// @brief Check for a collision between a camera ray and octree geometry. 27 | /// @param cube The cube to check collisions with. 28 | /// @param pos The camera position. 29 | /// @param dir The camera view direction. 30 | /// @param max_depth The maximum subcube iteration depth. If this depth is reached and the cube is an octant, it 31 | /// will be treated as if it was a solid cube. This is the foundation for the implementation of grid size in octree 32 | /// editor. 33 | /// @note This does not account yet for octree indentation! 34 | /// @return A std::optional which contains the collision data (if any found). 35 | [[nodiscard]] std::optional> 36 | ray_cube_collision_check(const Cube &cube, glm::vec3 pos, glm::vec3 dir, 37 | std::optional max_depth = std::nullopt); 38 | 39 | } // namespace inexor::vulkan_renderer::world 40 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/world/indentation.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace inexor::vulkan_renderer::world { 6 | 7 | class Indentation { 8 | public: 9 | static constexpr std::uint8_t MAX{8}; 10 | 11 | private: 12 | std::uint8_t m_start{0}; 13 | std::uint8_t m_end{Indentation::MAX}; 14 | 15 | public: 16 | Indentation() = default; 17 | Indentation(std::uint8_t start, std::uint8_t end) noexcept; 18 | explicit Indentation(std::uint8_t uid) noexcept; 19 | bool operator==(const Indentation &rhs) const; 20 | bool operator!=(const Indentation &rhs) const; 21 | 22 | /// Set absolute value of start. 23 | void set_start(std::uint8_t position) noexcept; 24 | /// Set absolute value of end. 25 | void set_end(std::uint8_t position) noexcept; 26 | 27 | /// Absolute value of start. 28 | [[nodiscard]] std::uint8_t start_abs() const noexcept; 29 | /// Absolute value of end. 30 | [[nodiscard]] std::uint8_t end_abs() const noexcept; 31 | /// Positive indent, relative from start's point. 32 | [[nodiscard]] std::uint8_t start() const noexcept; 33 | /// Positive indent, relative from end's point. 34 | [[nodiscard]] std::uint8_t end() const noexcept; 35 | /// Difference between start and end. 36 | [[nodiscard]] std::uint8_t offset() const noexcept; 37 | 38 | /// Positive steps into the direction of end. 39 | void indent_start(std::uint8_t steps) noexcept; 40 | /// Positive steps into the direction of start. 41 | void indent_end(std::uint8_t steps) noexcept; 42 | /// Mirror the indentation, such that the distance from 0 to start and distance from end to max switches 43 | void mirror() noexcept; 44 | 45 | [[nodiscard]] std::uint8_t uid() const; 46 | }; 47 | 48 | } // namespace inexor::vulkan_renderer::world 49 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/command_pool.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "inexor/vulkan-renderer/wrapper/command_buffer.hpp" 7 | 8 | #include 9 | 10 | namespace inexor::vulkan_renderer::wrapper { 11 | 12 | // Forward declaration 13 | class Device; 14 | 15 | /// @brief RAII wrapper class for VkCommandPool. 16 | class CommandPool { 17 | std::string m_name; 18 | const Device &m_device; 19 | VkCommandPool m_cmd_pool{VK_NULL_HANDLE}; 20 | 21 | /// The command buffers which can be requested by the current thread 22 | std::vector> m_cmd_bufs; 23 | 24 | public: 25 | /// Default constructor 26 | /// @param device The device wrapper instance 27 | /// @param name The internal debug marker name which will be assigned to this command pool 28 | CommandPool(const Device &device, std::string name); 29 | 30 | CommandPool(const CommandPool &) = delete; 31 | CommandPool(CommandPool &&) noexcept; 32 | 33 | ~CommandPool(); 34 | 35 | CommandPool &operator=(const CommandPool &) = delete; 36 | CommandPool &operator=(CommandPool &&) = delete; 37 | 38 | [[nodiscard]] VkCommandPool get() const { 39 | return m_cmd_pool; 40 | } 41 | 42 | [[nodiscard]] const VkCommandPool *ptr() const { 43 | return &m_cmd_pool; 44 | } 45 | 46 | /// Request a command buffer 47 | /// @param name The internal debug name which will be assigned to this command buffer (must not be empty) 48 | /// @return A command buffer handle instance which allows access to the requested command buffer 49 | [[nodiscard]] const CommandBuffer &request_command_buffer(const std::string &name); 50 | }; 51 | 52 | } // namespace inexor::vulkan_renderer::wrapper 53 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/cpu_texture.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace inexor::vulkan_renderer::wrapper { 8 | 9 | /// @brief RAII wrapper class for texture data. 10 | /// @todo Scan asset directory automatically. 11 | class CpuTexture { 12 | std::string m_name; 13 | 14 | int m_texture_width{0}; 15 | int m_texture_height{0}; 16 | int m_texture_channels{0}; 17 | int m_mip_levels{0}; 18 | 19 | stbi_uc *m_texture_data{nullptr}; 20 | 21 | /// @brief Generate a chessboard color pattern which will be used as error texture. 22 | void generate_error_texture_data(); 23 | 24 | public: 25 | /// @brief Create a CpuTexture instance with a default texture. 26 | CpuTexture(); 27 | 28 | /// @brief Read a texture from a file. 29 | /// @param file_name The file name of the texture. 30 | /// @param name The internal debug marker name of the command buffer. This must not be an empty string. 31 | CpuTexture(const std::string &file_name, std::string name); 32 | 33 | CpuTexture(const CpuTexture &) = delete; 34 | CpuTexture(CpuTexture &&) noexcept; 35 | 36 | ~CpuTexture(); 37 | 38 | CpuTexture &operator=(const CpuTexture &) = delete; 39 | CpuTexture &operator=(CpuTexture &&) = default; 40 | 41 | [[nodiscard]] const std::string &name() const { 42 | return m_name; 43 | } 44 | 45 | [[nodiscard]] int width() const { 46 | return m_texture_width; 47 | } 48 | 49 | [[nodiscard]] int height() const { 50 | return m_texture_height; 51 | } 52 | 53 | [[nodiscard]] int channels() const { 54 | return m_texture_channels; 55 | } 56 | 57 | [[nodiscard]] int mip_levels() const { 58 | return m_mip_levels; 59 | } 60 | 61 | [[nodiscard]] stbi_uc *data() const { 62 | return m_texture_data; 63 | } 64 | 65 | [[nodiscard]] std::size_t data_size() const { 66 | // TODO: We will need to update this once we fully support mip levels. 67 | return static_cast(m_texture_width) * static_cast(m_texture_height) * 68 | static_cast(m_texture_channels); 69 | } 70 | }; 71 | 72 | } // namespace inexor::vulkan_renderer::wrapper 73 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/descriptor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace inexor::vulkan_renderer::wrapper { 9 | 10 | // Forward declaration 11 | class Device; 12 | 13 | /// @brief RAII wrapper class for resource descriptors. 14 | class ResourceDescriptor { 15 | std::string m_name; 16 | const Device &m_device; 17 | VkDescriptorPool m_descriptor_pool{VK_NULL_HANDLE}; 18 | VkDescriptorSetLayout m_descriptor_set_layout{VK_NULL_HANDLE}; 19 | std::vector m_descriptor_set_layout_bindings; 20 | std::vector m_write_descriptor_sets; 21 | std::vector m_descriptor_sets; 22 | 23 | public: 24 | /// @brief Default constructor. 25 | /// @param device The const reference to a device RAII wrapper instance. 26 | /// @param layout_bindings The descriptor layout bindings. 27 | /// @param descriptor_writes The write descriptor sets. 28 | /// @param name The internal debug marker name of the resource descriptor. 29 | ResourceDescriptor(const Device &device, std::vector &&layout_bindings, 30 | std::vector &&descriptor_writes, std::string &&name); 31 | 32 | ResourceDescriptor(const ResourceDescriptor &) = delete; 33 | ResourceDescriptor(ResourceDescriptor &&) noexcept; 34 | ~ResourceDescriptor(); 35 | 36 | ResourceDescriptor &operator=(const ResourceDescriptor &) = delete; 37 | ResourceDescriptor &operator=(ResourceDescriptor &&) = delete; 38 | 39 | [[nodiscard]] const auto &descriptor_sets() const { 40 | return m_descriptor_sets; 41 | } 42 | 43 | [[nodiscard]] auto descriptor_set_layout() const { 44 | return m_descriptor_set_layout; 45 | } 46 | 47 | [[nodiscard]] const auto &descriptor_set_layout_bindings() const { 48 | return m_descriptor_set_layout_bindings; 49 | } 50 | }; 51 | 52 | } // namespace inexor::vulkan_renderer::wrapper 53 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/fence.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace inexor::vulkan_renderer::wrapper { 10 | 11 | // Forward declaration 12 | class Device; 13 | 14 | /// @brief A RAII wrapper for VkFences. 15 | class Fence { 16 | const Device &m_device; 17 | std::string m_name; 18 | VkFence m_fence{VK_NULL_HANDLE}; 19 | 20 | public: 21 | /// @brief Default constructor. 22 | /// @param device The const reference to a device RAII wrapper instance. 23 | /// @param name The internal debug marker name of the VkFence. 24 | /// @param in_signaled_state True if the VkFence will be constructed in signaled state, false otherwise. 25 | /// @warning Make sure to specify in_signaled_state correctly as needed, otherwise synchronization problems occur. 26 | Fence(const Device &device, const std::string &name, bool in_signaled_state); 27 | 28 | Fence(const Fence &) = delete; 29 | Fence(Fence &&) noexcept; 30 | 31 | ~Fence(); 32 | 33 | Fence &operator=(const Fence &) = delete; 34 | Fence &operator=(Fence &&) = delete; 35 | 36 | [[nodiscard]] VkFence get() const { 37 | return m_fence; 38 | } 39 | 40 | /// @brief Block fence by calling vkWaitForFences and wait until fence condition is fulfilled. 41 | /// @param timeout_limit The time to wait in milliseconds. If no time is specified, the numeric maximum value 42 | /// is used. 43 | void block(std::uint64_t timeout_limit = std::numeric_limits::max()) const; 44 | 45 | /// @brief Call vkResetFences. 46 | void reset() const; 47 | 48 | /// Call vkGetFenceStatus 49 | [[nodiscard]] VkResult status() const; 50 | }; 51 | 52 | } // namespace inexor::vulkan_renderer::wrapper 53 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/framebuffer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace inexor::vulkan_renderer::wrapper { 9 | 10 | // Forward declarations 11 | class Device; 12 | class Swapchain; 13 | 14 | /// @brief RAII wrapper class for VkFramebuffer. 15 | class Framebuffer { 16 | const Device &m_device; 17 | VkFramebuffer m_framebuffer{VK_NULL_HANDLE}; 18 | std::string m_name; 19 | 20 | public: 21 | /// @brief Default constructor. 22 | /// @param device The const reference to a device RAII wrapper instance. 23 | /// @param render_pass The renderpass which is associated with the framebuffer. 24 | /// @param attachments The attachments to use. 25 | /// @param swapchain The associated swapchain. 26 | /// @param name The internal debug marker name of the VkFramebuffer. 27 | Framebuffer(const Device &device, VkRenderPass render_pass, const std::vector &attachments, 28 | const Swapchain &swapchain, std::string name); 29 | 30 | Framebuffer(const Framebuffer &) = delete; 31 | Framebuffer(Framebuffer &&) noexcept; 32 | 33 | ~Framebuffer(); 34 | 35 | Framebuffer &operator=(const Framebuffer &) = delete; 36 | Framebuffer &operator=(Framebuffer &&) = delete; 37 | 38 | [[nodiscard]] VkFramebuffer get() const { 39 | return m_framebuffer; 40 | } 41 | }; 42 | 43 | } // namespace inexor::vulkan_renderer::wrapper 44 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/gpu_memory_buffer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace inexor::vulkan_renderer::wrapper { 8 | 9 | // Forward declaration 10 | class Device; 11 | 12 | /// @brief RAII wrapper class for GPU Memory buffers. 13 | /// Uniform buffers or vertex/index buffers use this as a base class. 14 | /// @note The core of Inexor's memory management is Vulkan Memory Allocator library (VMA). 15 | class GPUMemoryBuffer { 16 | protected: 17 | std::string m_name; 18 | const Device &m_device; 19 | VkBuffer m_buffer{VK_NULL_HANDLE}; 20 | VkDeviceSize m_buffer_size{0}; 21 | VmaAllocation m_allocation{VK_NULL_HANDLE}; 22 | VmaAllocationInfo m_allocation_info{}; 23 | 24 | public: 25 | /// @brief Construct the GPU memory buffer without specifying the actual data to fill in, only the memory size. 26 | /// @param device The const reference to a device RAII wrapper instance. 27 | /// @param name The internal debug marker name of the GPU memory buffer. 28 | /// @param buffer_size The size of the memory buffer in bytes. 29 | /// @param buffer_usage The buffer usage flags. 30 | /// @param memory_usage The VMA memory usage flags which specify the required memory allocation. 31 | GPUMemoryBuffer(const Device &device, const std::string &name, const VkDeviceSize &size, 32 | const VkBufferUsageFlags &buffer_usage, const VmaMemoryUsage &memory_usage); 33 | 34 | /// @brief Construct the GPU memory buffer and specifies the actual data to fill it in. 35 | /// @param device The const reference to a device RAII wrapper instance. 36 | /// @param name The internal debug marker name of the GPU memory buffer. 37 | /// @param buffer_size The size of the memory buffer in bytes. 38 | /// @param data A pointer to the data to fill the GPU memory buffer with. 39 | /// @param data_size The size of the memory to copy from data pointer. 40 | /// @param buffer_usage The buffer usage flags. 41 | /// @param memory_usage The VMA memory usage flags which specify the required memory allocation. 42 | GPUMemoryBuffer(const Device &device, const std::string &name, const VkDeviceSize &buffer_size, const void *data, 43 | std::size_t data_size, const VkBufferUsageFlags &buffer_usage, const VmaMemoryUsage &memory_usage); 44 | 45 | GPUMemoryBuffer(const GPUMemoryBuffer &) = delete; 46 | GPUMemoryBuffer(GPUMemoryBuffer &&) noexcept; 47 | 48 | virtual ~GPUMemoryBuffer(); 49 | 50 | GPUMemoryBuffer &operator=(const GPUMemoryBuffer &) = delete; 51 | GPUMemoryBuffer &operator=(GPUMemoryBuffer &&) = delete; 52 | 53 | [[nodiscard]] const std::string &name() const { 54 | return m_name; 55 | } 56 | 57 | [[nodiscard]] VkBuffer buffer() const { 58 | return m_buffer; 59 | } 60 | 61 | [[nodiscard]] VmaAllocation allocation() const { 62 | return m_allocation; 63 | } 64 | 65 | [[nodiscard]] VmaAllocationInfo allocation_info() const { 66 | return m_allocation_info; 67 | } 68 | }; 69 | 70 | } // namespace inexor::vulkan_renderer::wrapper 71 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/gpu_texture.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inexor/vulkan-renderer/wrapper/cpu_texture.hpp" 4 | #include "inexor/vulkan-renderer/wrapper/device.hpp" 5 | #include "inexor/vulkan-renderer/wrapper/gpu_memory_buffer.hpp" 6 | #include "inexor/vulkan-renderer/wrapper/image.hpp" 7 | 8 | #include 9 | 10 | namespace inexor::vulkan_renderer::wrapper { 11 | 12 | // Forward declarations 13 | class Device; 14 | class GPUMemoryBuffer; 15 | 16 | /// @note The code which loads textures from files is wrapped in CpuTexture. 17 | /// @brief RAII wrapper class for textures which are stored in GPU memory. 18 | /// @todo Support 3D textures and cube maps (implement new and separate wrappers though). 19 | class GpuTexture { 20 | std::unique_ptr m_texture_image; 21 | VkSampler m_sampler{VK_NULL_HANDLE}; 22 | 23 | int m_texture_width{0}; 24 | int m_texture_height{0}; 25 | int m_texture_channels{0}; 26 | int m_mip_levels{0}; 27 | 28 | std::string m_name; 29 | const Device &m_device; 30 | const VkFormat m_texture_image_format{VK_FORMAT_R8G8B8A8_UNORM}; 31 | 32 | /// @brief Create the texture. 33 | /// @param texture_data A pointer to the texture data. 34 | /// @param texture_size The size of the texture. 35 | void create_texture(void *texture_data, std::size_t texture_size); 36 | 37 | /// @brief Transform the image layout. 38 | /// @param image The image. 39 | /// @param old_layout The old image layout. 40 | /// @param new_layout The new image layout. 41 | void transition_image_layout(VkImage image, VkImageLayout old_layout, VkImageLayout new_layout); 42 | 43 | /// @brief Create the texture sampler. 44 | void create_texture_sampler(); 45 | 46 | public: 47 | /// @brief Construct a texture from a file. 48 | /// @param device The const reference to a device RAII wrapper instance. 49 | /// @param file_name The name of the texture file. 50 | /// @param name The internal debug marker name of the texture. 51 | GpuTexture(const Device &device, const CpuTexture &cpu_texture); 52 | 53 | /// @brief Construct a texture from a block of memory. 54 | /// @param device The const reference to a device RAII wrapper instance. 55 | /// @param device The const reference to a device RAII wrapper instance. 56 | /// @param texture_data A pointer to the texture data. 57 | /// @param texture_width The width of the texture. 58 | /// @param texture_height The height of the texture. 59 | /// @param texture_size The size of the texture. 60 | /// @param name The internal debug marker name of the texture. 61 | GpuTexture(const Device &device, void *data, std::size_t data_size, int texture_width, int texture_height, 62 | int texture_channels, int mip_levels, std::string name); 63 | 64 | GpuTexture(const GpuTexture &) = delete; 65 | GpuTexture(GpuTexture &&) noexcept; 66 | 67 | ~GpuTexture(); 68 | 69 | GpuTexture &operator=(const GpuTexture &) = delete; 70 | GpuTexture &operator=(GpuTexture &&) = delete; 71 | 72 | [[nodiscard]] const std::string &name() const { 73 | return m_name; 74 | } 75 | 76 | [[nodiscard]] VkImage image() const { 77 | return m_texture_image->get(); 78 | } 79 | 80 | [[nodiscard]] VkImageView image_view() const { 81 | return m_texture_image->image_view(); 82 | } 83 | 84 | [[nodiscard]] VkSampler sampler() const { 85 | return m_sampler; 86 | } 87 | }; 88 | 89 | } // namespace inexor::vulkan_renderer::wrapper 90 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/image.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace inexor::vulkan_renderer::wrapper { 8 | 9 | // Forward declaration 10 | class Device; 11 | 12 | /// @brief RAII wrapper class for VkImage. 13 | class Image { 14 | const Device &m_device; 15 | VmaAllocation m_allocation{VK_NULL_HANDLE}; 16 | VmaAllocationInfo m_allocation_info{}; 17 | VkImage m_image{VK_NULL_HANDLE}; 18 | VkFormat m_format{VK_FORMAT_UNDEFINED}; 19 | VkImageView m_image_view{VK_NULL_HANDLE}; 20 | std::string m_name; 21 | 22 | public: 23 | /// @brief Default constructor. 24 | /// @param device The const reference to a device RAII wrapper instance. 25 | /// @param format The color format. 26 | /// @param image_usage The image usage flags. 27 | /// @param aspect_flags The aspect flags. 28 | /// @param sample_count The sample count. 29 | /// @param name The internal debug marker name of the VkImage. 30 | /// @param image_extent The width and height of the image. 31 | Image(const Device &device, VkFormat format, VkImageUsageFlags image_usage, VkImageAspectFlags aspect_flags, 32 | VkSampleCountFlagBits sample_count, const std::string &name, VkExtent2D image_extent); 33 | 34 | Image(const Image &) = delete; 35 | Image(Image &&) noexcept; 36 | 37 | ~Image(); 38 | 39 | Image &operator=(const Image &) = delete; 40 | Image &operator=(Image &&) = delete; 41 | 42 | [[nodiscard]] VkFormat image_format() const { 43 | return m_format; 44 | } 45 | 46 | [[nodiscard]] VkImageView image_view() const { 47 | return m_image_view; 48 | } 49 | 50 | [[nodiscard]] VkImage get() const { 51 | return m_image; 52 | } 53 | }; 54 | 55 | } // namespace inexor::vulkan_renderer::wrapper 56 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/instance.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace inexor::vulkan_renderer::wrapper { 10 | 11 | /// @brief RAII wrapper class for VkInstances. 12 | class Instance { 13 | private: 14 | VkInstance m_instance{VK_NULL_HANDLE}; 15 | static constexpr std::uint32_t REQUIRED_VK_API_VERSION{VK_API_VERSION_1_2}; 16 | 17 | public: 18 | /// @brief Check if a certain instance layer is available on the system. 19 | /// @param layer_name The name of the instance layer. 20 | /// @return ``true`` if the instance layer is supported. 21 | [[nodiscard]] static bool is_layer_supported(const std::string &layer_name); 22 | 23 | /// @brief Check if a certain instance extension is supported on the system. 24 | /// @param extension_name The name of the instance extension. 25 | /// @return ``true`` if the instance extension is supported. 26 | [[nodiscard]] static bool is_extension_supported(const std::string &extension_name); 27 | 28 | /// @brief Construct the Vulkan instance and specify the requested instance layers and instance extensions. 29 | /// @param application_name The Vulkan application's internal application name 30 | /// @param engine_name The Vulkan application's internal engine name 31 | /// @param application_version The Vulkan application's internal version 32 | /// @param engine_version The Vulkan application's internal engine version 33 | /// @param enable_validation_layers True if validation layers should be enabled 34 | /// @param enable_renderdoc_layer True if renderdoc layer should be enabled 35 | /// @param requested_instance_extensions The instance extensions which are requested 36 | /// @param requested_instance_layers The instance layers which are requested 37 | Instance(const std::string &application_name, const std::string &engine_name, std::uint32_t application_version, 38 | std::uint32_t engine_version, bool enable_validation_layers, bool enable_renderdoc_layer, 39 | const std::vector &requested_instance_extensions, 40 | const std::vector &requested_instance_layers); 41 | 42 | /// @brief Construct the Vulkan instance without the requested instance layers and instance extensions. 43 | /// @param application_name The Vulkan application's internal application name 44 | /// @param engine_name The Vulkan application's internal engine name 45 | /// @param application_version The Vulkan application's internal version 46 | /// @param engine_version The Vulkan application's internal engine version 47 | /// @param enable_validation_layers True if validation layers should be enabled, false otherwise 48 | /// @param enable_renderdoc_layer True if renderdoc layer should be enabled, false otherwise 49 | Instance(const std::string &application_name, const std::string &engine_name, std::uint32_t application_version, 50 | std::uint32_t engine_version, bool enable_validation_layers, bool enable_renderdoc_layer); 51 | 52 | Instance(const Instance &) = delete; 53 | Instance(Instance &&) noexcept; 54 | 55 | ~Instance(); 56 | 57 | Instance &operator=(const Instance &) = delete; 58 | Instance &operator=(Instance &&) = default; 59 | 60 | [[nodiscard]] VkInstance instance() const { 61 | return m_instance; 62 | } 63 | }; 64 | 65 | } // namespace inexor::vulkan_renderer::wrapper 66 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/make_info.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace inexor::vulkan_renderer::wrapper { 4 | 5 | /// @brief A small helper function that return vulkan create infos with sType already set 6 | /// @code{.cpp} 7 | /// auto render_pass_ci = make_info(); 8 | /// @endcode 9 | /// @note Also zeros the returned struct 10 | template 11 | [[nodiscard]] T make_info(T = {}); 12 | 13 | } // namespace inexor::vulkan_renderer::wrapper 14 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/semaphore.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace inexor::vulkan_renderer::wrapper { 8 | 9 | // Forward declaration 10 | class Device; 11 | 12 | /// RAII wrapper class for VkSemaphore 13 | class Semaphore { 14 | const Device &m_device; 15 | VkSemaphore m_semaphore{VK_NULL_HANDLE}; 16 | std::string m_name; 17 | 18 | public: 19 | /// Default constructor 20 | /// @param device The const reference to a device RAII wrapper instance. 21 | /// @param name The internal debug marker name of the VkSemaphore. 22 | Semaphore(const Device &device, const std::string &name); 23 | Semaphore(const Semaphore &) = delete; 24 | Semaphore(Semaphore &&) noexcept; 25 | ~Semaphore(); 26 | 27 | Semaphore &operator=(const Semaphore &) = delete; 28 | Semaphore &operator=(Semaphore &&) = delete; 29 | 30 | [[nodiscard]] const VkSemaphore *semaphore() const { 31 | return &m_semaphore; 32 | } 33 | }; 34 | 35 | } // namespace inexor::vulkan_renderer::wrapper 36 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/shader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace inexor::vulkan_renderer::wrapper { 9 | 10 | // Forward declaration 11 | class Device; 12 | 13 | /// @brief RAII wrapper class for VkShaderModules. 14 | class Shader { 15 | const Device &m_device; 16 | std::string m_name; 17 | std::string m_entry_point; 18 | VkShaderStageFlagBits m_type; 19 | VkShaderModule m_shader_module{VK_NULL_HANDLE}; 20 | 21 | public: 22 | /// @brief Construct a shader module from a block of SPIR-V memory. 23 | /// @param device The const reference to a device RAII wrapper instance. 24 | /// @param type The shader type. 25 | /// @param name The internal debug marker name of the VkShaderModule. 26 | /// @param code The memory block of the SPIR-V shader. 27 | /// @param entry_point The name of the entry point, "main" by default. 28 | Shader(const Device &m_device, VkShaderStageFlagBits type, const std::string &name, const std::vector &code, 29 | const std::string &entry_point = "main"); 30 | 31 | /// @brief Construct a shader module from a SPIR-V file. 32 | /// This constructor loads the file content and just calls the other constructor. 33 | /// @param device The const reference to a device RAII wrapper instance. 34 | /// @param type The shader type. 35 | /// @param name The internal debug marker name of the VkShaderModule. 36 | /// @param file_name The name of the SPIR-V shader file to load. 37 | /// @param entry_point The name of the entry point, "main" by default. 38 | Shader(const Device &m_device, VkShaderStageFlagBits type, const std::string &name, const std::string &file_name, 39 | const std::string &entry_point = "main"); 40 | 41 | Shader(const Shader &) = delete; 42 | Shader(Shader &&) noexcept; 43 | 44 | ~Shader(); 45 | 46 | Shader &operator=(const Shader &) = delete; 47 | Shader &operator=(Shader &&) = delete; 48 | 49 | [[nodiscard]] const std::string &name() const { 50 | return m_name; 51 | } 52 | 53 | [[nodiscard]] const std::string &entry_point() const { 54 | return m_entry_point; 55 | } 56 | 57 | [[nodiscard]] VkShaderStageFlagBits type() const { 58 | return m_type; 59 | } 60 | 61 | [[nodiscard]] VkShaderModule module() const { 62 | return m_shader_module; 63 | } 64 | }; 65 | 66 | } // namespace inexor::vulkan_renderer::wrapper 67 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/uniform_buffer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "inexor/vulkan-renderer/wrapper/gpu_memory_buffer.hpp" 4 | 5 | namespace inexor::vulkan_renderer::wrapper { 6 | 7 | // Forward declaration 8 | class Device; 9 | 10 | /// @brief RAII wrapper class for uniform buffers. 11 | class UniformBuffer : public GPUMemoryBuffer { 12 | public: 13 | /// @brief Default constructor. 14 | /// @param device The const reference to a device RAII wrapper instance. 15 | /// @param name The internal debug marker name of the uniform buffer. 16 | /// @param size The size of the uniform buffer. 17 | /// @todo Add overloaded constructor which directly accepts the uniform buffer data. 18 | UniformBuffer(const Device &device, const std::string &name, const VkDeviceSize &size); 19 | 20 | UniformBuffer(const UniformBuffer &) = delete; 21 | UniformBuffer(UniformBuffer &&) noexcept; 22 | 23 | ~UniformBuffer() override = default; 24 | 25 | UniformBuffer &operator=(const UniformBuffer &) = delete; 26 | UniformBuffer &operator=(UniformBuffer &&) = delete; 27 | 28 | /// @brief Update uniform buffer data. 29 | /// @param data A pointer to the uniform buffer data. 30 | /// @param size The size of the uniform buffer memory to copy. 31 | void update(void *data, std::size_t size); 32 | }; 33 | 34 | } // namespace inexor::vulkan_renderer::wrapper 35 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/window.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace inexor::vulkan_renderer::wrapper { 9 | 10 | /// @brief RAII wrapper class for GLFW windows. 11 | class Window { 12 | public: 13 | enum class Mode { WINDOWED, FULLSCREEN, WINDOWED_FULLSCREEN }; 14 | 15 | private: 16 | std::uint32_t m_width; 17 | std::uint32_t m_height; 18 | Mode m_mode; 19 | GLFWwindow *m_window{nullptr}; 20 | 21 | public: 22 | /// @brief Default constructor. 23 | /// @param title The title of the window. This will be displayed in the window bar. 24 | /// @param width The width of the window. 25 | /// @param height The height of the window. 26 | /// @param visible True if the window is visible after creation, false otherwise. 27 | /// @param resizable True if the window should be resizable, false otherwise. 28 | Window(const std::string &title, std::uint32_t width, std::uint32_t height, bool visible, bool resizable, 29 | Mode mode); 30 | Window(const Window &) = delete; 31 | Window(Window &&) = delete; 32 | ~Window(); 33 | 34 | Window &operator=(const Window &) = delete; 35 | Window &operator=(Window &&) = delete; 36 | 37 | /// @brief In case the window has been minimized, process events until it has been restored. 38 | void wait_for_focus(); 39 | 40 | /// @brief Change the window title. 41 | /// @param title The new title of the window. 42 | void set_title(const std::string &title); 43 | 44 | /// @brief Set the GLFW window user pointer. 45 | /// @param user_ptr The window user pointer. 46 | // @note Since GLFW is a C-style API, we can't use a class method as callback for window resize. 47 | void set_user_ptr(void *user_ptr); 48 | 49 | /// @brief Set up the window resize callback. 50 | /// @param frame_buffer_resize_callback The window resize callback. 51 | void set_resize_callback(GLFWframebuffersizefun frame_buffer_resize_callback); 52 | 53 | /// @brief Call glfwSetKeyCallback. 54 | /// @param key_input_callback The keyboard input callback. 55 | void set_keyboard_button_callback(GLFWkeyfun keyboard_button_callback); 56 | 57 | /// @brief Call glfwSetCursorPosCallback. 58 | /// @param cursor_pos_callback They cursor position callback. 59 | void set_cursor_position_callback(GLFWcursorposfun cursor_pos_callback); 60 | 61 | /// @brief Call glfwSetMouseButtonCallback. 62 | /// @param mouse_button_callback The mouse button callback. 63 | void set_mouse_button_callback(GLFWmousebuttonfun mouse_button_callback); 64 | 65 | /// @brief Call glfwSetScrollCallback. 66 | /// @param mouse_scroll_callback The mouse scroll callback. 67 | void set_mouse_scroll_callback(GLFWscrollfun mouse_scroll_callback); 68 | 69 | /// @brief Call glfwShowWindow. 70 | void show(); 71 | 72 | /// @brief Call glfwPollEvents. 73 | static void poll(); 74 | 75 | /// @brief Check if the window is about to close. 76 | /// @return ``true`` if the window will be closed. 77 | bool should_close(); 78 | 79 | [[nodiscard]] GLFWwindow *get() const { 80 | return m_window; 81 | } 82 | 83 | [[nodiscard]] std::uint32_t width() const { 84 | return m_width; 85 | } 86 | 87 | [[nodiscard]] std::uint32_t height() const { 88 | return m_height; 89 | } 90 | 91 | [[nodiscard]] Mode mode() const { 92 | return m_mode; 93 | } 94 | }; 95 | 96 | } // namespace inexor::vulkan_renderer::wrapper 97 | -------------------------------------------------------------------------------- /include/inexor/vulkan-renderer/wrapper/window_surface.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace inexor::vulkan_renderer::wrapper { 7 | 8 | /// @brief RAII wrapper class for VkSurfaceKHR. 9 | class WindowSurface { 10 | VkInstance m_instance{VK_NULL_HANDLE}; 11 | VkSurfaceKHR m_surface{VK_NULL_HANDLE}; 12 | 13 | public: 14 | /// @brief Default constructor. 15 | /// @param instance The Vulkan instance which will be associated with this surface. 16 | /// @param window The window which will be associated with this surface. 17 | WindowSurface(VkInstance instance, GLFWwindow *window); 18 | 19 | WindowSurface(const WindowSurface &) = delete; 20 | WindowSurface(WindowSurface &&) noexcept; 21 | 22 | ~WindowSurface(); 23 | 24 | WindowSurface &operator=(const WindowSurface &) = delete; 25 | WindowSurface &operator=(WindowSurface &&) = default; 26 | 27 | [[nodiscard]] VkSurfaceKHR get() const { 28 | return m_surface; 29 | } 30 | }; 31 | 32 | } // namespace inexor::vulkan_renderer::wrapper 33 | -------------------------------------------------------------------------------- /shaders/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_program(GLSL_VALIDATOR glslangValidator REQUIRED) 2 | if(NOT GLSL_VALIDATOR) 3 | message(FATAL_ERROR "glslangValidator not found!") 4 | endif() 5 | 6 | set( 7 | SHADERS 8 | main.vert 9 | main.frag 10 | ui.frag 11 | ui.vert 12 | ) 13 | 14 | foreach(SHADER ${SHADERS}) 15 | get_filename_component(FILE_NAME ${SHADER} NAME) 16 | set(SPIRV ${CMAKE_CURRENT_SOURCE_DIR}/${FILE_NAME}.spv) 17 | add_custom_command( 18 | OUTPUT ${SPIRV} 19 | COMMAND ${GLSL_VALIDATOR} -V ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV} 20 | DEPENDS ${SHADER} 21 | ) 22 | 23 | list(APPEND SPIRV_FILES ${SPIRV}) 24 | endforeach() 25 | 26 | source_group("Shader Files" FILES ${SHADERS}) 27 | 28 | add_custom_target(inexor-shaders DEPENDS ${SPIRV_FILES} SOURCES ${SHADERS}) 29 | -------------------------------------------------------------------------------- /shaders/main.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec3 frag_color; 4 | layout (location = 0) out vec4 out_color; 5 | 6 | void main() { 7 | out_color = vec4(frag_color, 1.0); 8 | } 9 | -------------------------------------------------------------------------------- /shaders/main.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec3 in_position; 4 | layout (location = 1) in vec3 in_color; 5 | 6 | layout (binding = 0) uniform UniformBufferObject { 7 | mat4 model; 8 | mat4 view; 9 | mat4 proj; 10 | } ubo; 11 | 12 | layout (location = 0) out vec3 frag_color; 13 | 14 | void main() { 15 | gl_Position = ubo.proj * ubo.view * ubo.model * vec4(in_position, 1.0); 16 | frag_color = in_color; 17 | } 18 | -------------------------------------------------------------------------------- /shaders/ui.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (binding = 0) uniform sampler2D font_sampler; 4 | 5 | layout (location = 0) in vec2 in_uv; 6 | layout (location = 1) in vec4 in_color; 7 | 8 | layout (location = 0) out vec4 out_color; 9 | 10 | void main() { 11 | out_color = in_color * texture(font_sampler, in_uv); 12 | } 13 | -------------------------------------------------------------------------------- /shaders/ui.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout (location = 0) in vec2 in_pos; 4 | layout (location = 1) in vec2 in_uv; 5 | layout (location = 2) in vec4 in_color; 6 | 7 | layout (push_constant) uniform PushConstants { 8 | vec2 scale; 9 | vec2 translate; 10 | } push_constants; 11 | 12 | layout (location = 0) out vec2 out_uv; 13 | layout (location = 1) out vec4 out_color; 14 | 15 | void main() { 16 | out_uv = in_uv; 17 | out_color = in_color; 18 | gl_Position = vec4(in_pos * push_constants.scale + push_constants.translate, 0.0, 1.0); 19 | } 20 | -------------------------------------------------------------------------------- /src/vulkan-renderer/exception.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/exception.hpp" 2 | 3 | #include "inexor/vulkan-renderer/vk_tools/representation.hpp" 4 | 5 | namespace inexor::vulkan_renderer { 6 | 7 | VulkanException::VulkanException(std::string message, const VkResult result) 8 | : InexorException(message.append(" (") 9 | .append(vk_tools::as_string(result)) 10 | .append(": ") 11 | .append(vk_tools::result_to_description(result)) 12 | .append(")")) {} 13 | 14 | } // namespace inexor::vulkan_renderer 15 | -------------------------------------------------------------------------------- /src/vulkan-renderer/fps_counter.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/fps_counter.hpp" 2 | 3 | namespace inexor::vulkan_renderer { 4 | 5 | std::optional FPSCounter::update() { 6 | const auto current_time = std::chrono::high_resolution_clock::now(); 7 | 8 | auto time_duration = std::chrono::duration(current_time - m_last_time).count(); 9 | 10 | if (time_duration >= m_fps_update_interval) { 11 | auto fps_value = static_cast(static_cast(m_frames) / time_duration); 12 | 13 | m_last_time = current_time; 14 | m_frames = 0; 15 | 16 | return fps_value; 17 | } 18 | 19 | m_frames++; 20 | 21 | return std::nullopt; 22 | } 23 | 24 | } // namespace inexor::vulkan_renderer 25 | -------------------------------------------------------------------------------- /src/vulkan-renderer/input/keyboard_mouse_data.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/input/keyboard_mouse_data.hpp" 2 | 3 | #include 4 | #include 5 | 6 | namespace inexor::vulkan_renderer::input { 7 | 8 | void KeyboardMouseInputData::press_key(const std::int32_t key) { 9 | assert(key >= 0); 10 | assert(key < GLFW_KEY_LAST); 11 | 12 | std::scoped_lock lock(m_input_mutex); 13 | m_pressed_keys[key] = true; 14 | m_keyboard_updated = true; 15 | } 16 | 17 | void KeyboardMouseInputData::release_key(const std::int32_t key) { 18 | assert(key >= 0); 19 | assert(key < GLFW_KEY_LAST); 20 | 21 | std::scoped_lock lock(m_input_mutex); 22 | m_pressed_keys[key] = false; 23 | m_keyboard_updated = true; 24 | } 25 | 26 | bool KeyboardMouseInputData::is_key_pressed(const std::int32_t key) const { 27 | assert(key >= 0); 28 | assert(key < GLFW_KEY_LAST); 29 | 30 | std::shared_lock lock(m_input_mutex); 31 | return m_pressed_keys[key]; 32 | } 33 | bool KeyboardMouseInputData::was_key_pressed_once(const std::int32_t key) { 34 | assert(key >= 0); 35 | assert(key < GLFW_KEY_LAST); 36 | 37 | std::scoped_lock lock(m_input_mutex); 38 | if (!m_pressed_keys[key] || !m_keyboard_updated) { 39 | return false; 40 | } 41 | 42 | m_pressed_keys[key] = false; 43 | return true; 44 | } 45 | 46 | void KeyboardMouseInputData::press_mouse_button(const std::int32_t button) { 47 | assert(button >= 0); 48 | assert(button < GLFW_MOUSE_BUTTON_LAST); 49 | 50 | std::scoped_lock lock(m_input_mutex); 51 | m_pressed_mouse_buttons[button] = true; 52 | m_mouse_buttons_updated = true; 53 | } 54 | 55 | void KeyboardMouseInputData::release_mouse_button(const std::int32_t button) { 56 | assert(button >= 0); 57 | assert(button < GLFW_MOUSE_BUTTON_LAST); 58 | 59 | std::scoped_lock lock(m_input_mutex); 60 | m_pressed_mouse_buttons[button] = false; 61 | m_mouse_buttons_updated = true; 62 | } 63 | 64 | bool KeyboardMouseInputData::is_mouse_button_pressed(const std::int32_t button) const { 65 | assert(button >= 0); 66 | assert(button < GLFW_MOUSE_BUTTON_LAST); 67 | 68 | std::shared_lock lock(m_input_mutex); 69 | return m_pressed_mouse_buttons[button]; 70 | } 71 | 72 | bool KeyboardMouseInputData::was_mouse_button_pressed_once(const std::int32_t button) { 73 | assert(button >= 0); 74 | assert(button < GLFW_MOUSE_BUTTON_LAST); 75 | 76 | std::scoped_lock lock(m_input_mutex); 77 | if (!m_pressed_mouse_buttons[button] || !m_mouse_buttons_updated) { 78 | return false; 79 | } 80 | 81 | m_pressed_mouse_buttons[button] = false; 82 | return true; 83 | } 84 | 85 | void KeyboardMouseInputData::set_cursor_pos(const double pos_x, const double pos_y) { 86 | std::scoped_lock lock(m_input_mutex); 87 | m_current_cursor_pos[0] = static_cast(pos_x); 88 | m_current_cursor_pos[1] = static_cast(pos_y); 89 | } 90 | 91 | std::array KeyboardMouseInputData::get_cursor_pos() const { 92 | std::shared_lock lock(m_input_mutex); 93 | return m_current_cursor_pos; 94 | } 95 | 96 | std::array KeyboardMouseInputData::calculate_cursor_position_delta() { 97 | std::scoped_lock lock(m_input_mutex); 98 | // Calculate the change in cursor position in x- and y-axis. 99 | const std::array m_cursor_pos_delta{ 100 | static_cast(m_current_cursor_pos[0]) - static_cast(m_previous_cursor_pos[0]), 101 | static_cast(m_current_cursor_pos[1]) - static_cast(m_previous_cursor_pos[1])}; 102 | 103 | m_previous_cursor_pos = m_current_cursor_pos; 104 | 105 | return m_cursor_pos_delta; 106 | } 107 | 108 | } // namespace inexor::vulkan_renderer::input 109 | -------------------------------------------------------------------------------- /src/vulkan-renderer/io/nxoc_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/io/nxoc_parser.hpp" 2 | 3 | #include "inexor/vulkan-renderer/io/byte_stream.hpp" 4 | #include "inexor/vulkan-renderer/io/exception.hpp" 5 | #include "inexor/vulkan-renderer/world/cube.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace inexor::vulkan_renderer::io { 12 | template <> 13 | ByteStream NXOCParser::serialize_impl<0>(const std::shared_ptr cube) { // NOLINT 14 | ByteStreamWriter writer; 15 | writer.write("Inexor Octree"); 16 | writer.write(0); 17 | 18 | std::function &)> iter_func; 19 | // pre-order traversal 20 | iter_func = [&iter_func, &writer](const std::shared_ptr &cube) { 21 | writer.write(cube->type()); 22 | if (cube->type() == world::Cube::Type::OCTANT) { 23 | for (const auto &child : cube->children()) { 24 | iter_func(child); 25 | } 26 | return; 27 | } 28 | if (cube->type() == world::Cube::Type::NORMAL) { 29 | writer.write(cube->indentations()); 30 | } 31 | }; 32 | 33 | iter_func(cube); 34 | return writer; 35 | } 36 | 37 | template <> 38 | std::shared_ptr NXOCParser::deserialize_impl<0>(const ByteStream &stream) { 39 | ByteStreamReader reader(stream); 40 | std::shared_ptr root = std::make_shared(); 41 | 42 | // Skip identifier, which is already checked. 43 | reader.skip(13); 44 | // Skip version. 45 | reader.skip(4); 46 | 47 | std::function &)> iter_func; 48 | // pre-order traversal 49 | iter_func = [&iter_func, &reader](std::shared_ptr &cube) { 50 | cube->set_type(reader.read()); 51 | if (cube->type() == world::Cube::Type::OCTANT) { 52 | for (auto child : cube->children()) { 53 | iter_func(child); 54 | } 55 | return; 56 | } 57 | if (cube->type() == world::Cube::Type::NORMAL) { 58 | cube->m_indentations = reader.read>(); 59 | } 60 | }; 61 | iter_func(root); 62 | return root; 63 | } 64 | 65 | ByteStream NXOCParser::serialize(const std::shared_ptr cube, const std::uint32_t version) { 66 | if (cube == nullptr) { 67 | throw std::invalid_argument("cube cannot be a nullptr"); 68 | } 69 | switch (version) { // NOLINT 70 | case 0: 71 | return serialize_impl<0>(cube); 72 | default: 73 | throw IoException("Unsupported octree version"); 74 | } 75 | } 76 | 77 | std::shared_ptr NXOCParser::deserialize(const ByteStream &stream) { 78 | ByteStreamReader reader(stream); 79 | if (reader.read(13ull) != "Inexor Octree") { 80 | throw IoException("Wrong identifier"); 81 | } 82 | const auto version = reader.read(); 83 | switch (version) { // NOLINT 84 | case 0: 85 | return deserialize_impl<0>(stream); 86 | default: 87 | throw IoException("Unsupported octree version"); 88 | } 89 | } 90 | } // namespace inexor::vulkan_renderer::io 91 | -------------------------------------------------------------------------------- /src/vulkan-renderer/time_step.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/time_step.hpp" 2 | 3 | namespace inexor::vulkan_renderer { 4 | 5 | TimeStep::TimeStep() { 6 | m_initialisation_time = std::chrono::high_resolution_clock::now(); 7 | 8 | m_last_time = std::chrono::high_resolution_clock::now(); 9 | } 10 | 11 | float TimeStep::time_step() { 12 | const auto current_time = std::chrono::high_resolution_clock::now(); 13 | 14 | auto time_duration = std::chrono::duration(current_time - m_last_time).count(); 15 | 16 | m_last_time = current_time; 17 | 18 | return time_duration; 19 | } 20 | 21 | float TimeStep::time_step_since_initialisation() { 22 | auto current_time = std::chrono::high_resolution_clock::now(); 23 | 24 | auto time_duration = 25 | std::chrono::duration(current_time - m_initialisation_time).count(); 26 | 27 | return time_duration; 28 | } 29 | 30 | } // namespace inexor::vulkan_renderer 31 | -------------------------------------------------------------------------------- /src/vulkan-renderer/tools/cla_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/tools/cla_parser.hpp" 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace inexor::vulkan_renderer::tools { 8 | 9 | template <> 10 | [[nodiscard]] int CommandLineArgumentValue::as() const { 11 | return std::stoi(m_value); 12 | } 13 | 14 | template <> 15 | [[nodiscard]] bool CommandLineArgumentValue::as() const { 16 | if (m_value == "false") { 17 | return false; 18 | } 19 | if (m_value == "true") { 20 | return true; 21 | } 22 | return static_cast(as()); 23 | } 24 | 25 | template <> 26 | [[nodiscard]] std::uint32_t CommandLineArgumentValue::as() const { 27 | return static_cast(as()); 28 | } 29 | 30 | std::optional 31 | CommandLineArgumentParser::make_arg_template(const std::string &argument_name) const { 32 | auto it = std::find_if(m_accepted_args.begin(), m_accepted_args.end(), 33 | [&](const auto &accepted_arg) { return argument_name == accepted_arg.argument(); }); 34 | if (it == m_accepted_args.end()) { 35 | return std::nullopt; 36 | } 37 | return *it; 38 | } 39 | 40 | // TODO: Take in an std::vector of arguments? This would avoid any hard to debug out of bounds errors (with 41 | // argc being bigger than the number of elements actually in argv). 42 | void CommandLineArgumentParser::parse_args(int argc, char **argv) { 43 | for (int i = 1; i < argc; i++) { 44 | // NOLINTNEXTLINE 45 | std::string arg_name(argv[i]); 46 | 47 | // If a user enters an unrecognized argument, just warn them about it for now. 48 | auto arg_template = make_arg_template(arg_name); 49 | if (!arg_template) { 50 | spdlog::warn("Unknown command line argument {}!", arg_name); 51 | continue; 52 | } 53 | 54 | // Insert a dummy value if the argument doesn't take any. 55 | if (!arg_template->takes_values()) { 56 | m_parsed_arguments.insert(std::make_pair(arg_name, "")); 57 | continue; 58 | } 59 | 60 | // We have to fail if the user doesn't specify a value for an argument expecting one (since it would mess up the 61 | // rest of parsing). 62 | if (i++ >= argc) { 63 | throw std::runtime_error("No value specified for argument " + arg_name); 64 | } 65 | 66 | // NOLINTNEXTLINE 67 | std::string arg_value(argv[i]); 68 | m_parsed_arguments.insert(std::make_pair(arg_name, arg_value)); 69 | } 70 | } 71 | 72 | } // namespace inexor::vulkan_renderer::tools 73 | -------------------------------------------------------------------------------- /src/vulkan-renderer/tools/file.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/tools/file.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace inexor::vulkan_renderer::tools { 9 | 10 | std::string get_file_extension_lowercase(const std::string &file_name) { 11 | assert(!file_name.empty()); 12 | 13 | // Extract the file extension 14 | std::string file_extension = std::filesystem::path(file_name).extension().string(); 15 | 16 | if (file_extension.empty()) { 17 | return ""; 18 | } 19 | 20 | // Convert file extension string to lowercase 21 | std::transform(file_extension.begin(), file_extension.end(), file_extension.begin(), 22 | [](unsigned char c) { return std::tolower(c); }); 23 | 24 | return file_extension; 25 | } 26 | 27 | std::vector read_file_binary_data(const std::string &file_name) { 28 | 29 | // Open stream at the end of the file to read it's size. 30 | std::ifstream file(file_name.c_str(), std::ios::ate | std::ios::binary | std::ios::in); 31 | 32 | if (!file) { 33 | throw std::runtime_error("Error: Could not open file " + file_name + "!"); 34 | } 35 | 36 | // Read the size of the file 37 | const auto file_size = file.tellg(); 38 | 39 | std::vector buffer(file_size); 40 | 41 | // Set the file read position to the beginning of the file 42 | file.seekg(0); 43 | 44 | file.read(buffer.data(), file_size); 45 | 46 | return buffer; 47 | } 48 | 49 | } // namespace inexor::vulkan_renderer::tools 50 | -------------------------------------------------------------------------------- /src/vulkan-renderer/vk_tools/device_info.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/vk_tools/device_info.hpp" 2 | 3 | #include 4 | #include 5 | 6 | namespace inexor::vulkan_renderer::vk_tools { 7 | 8 | std::vector get_device_features_as_vector(const VkPhysicalDeviceFeatures &features) { 9 | std::vector comparable_features(sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32)); 10 | std::memcpy(comparable_features.data(), &features, sizeof(VkPhysicalDeviceFeatures)); 11 | return comparable_features; 12 | } 13 | 14 | std::string get_physical_device_name(const VkPhysicalDevice physical_device) { 15 | assert(physical_device); 16 | VkPhysicalDeviceProperties properties{}; 17 | vkGetPhysicalDeviceProperties(physical_device, &properties); 18 | return properties.deviceName; 19 | } 20 | 21 | } // namespace inexor::vulkan_renderer::vk_tools 22 | -------------------------------------------------------------------------------- /src/vulkan-renderer/world/indentation.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/world/indentation.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace inexor::vulkan_renderer::world { 9 | Indentation::Indentation(const std::uint8_t start, const std::uint8_t end) noexcept : m_start(start), m_end(end) {} 10 | 11 | Indentation::Indentation(const std::uint8_t uid) noexcept { 12 | assert(uid <= 44); 13 | constexpr std::array MASKS{44, 42, 39, 35, 30, 24, 17, 9}; 14 | for (std::uint8_t idx = 0; idx < Indentation::MAX; idx++) { 15 | if (MASKS[idx] <= uid) { 16 | m_start = Indentation::MAX - idx; 17 | m_end = m_start + (uid - MASKS[idx]); 18 | return; 19 | } 20 | } 21 | m_start = 0; 22 | m_end = uid; 23 | } 24 | 25 | bool Indentation::operator==(const Indentation &rhs) const { 26 | return this->m_start == rhs.m_start && this->m_end == rhs.m_end; 27 | } 28 | 29 | bool Indentation::operator!=(const Indentation &rhs) const { 30 | return !(*this == rhs); 31 | } 32 | 33 | void Indentation::set_start(std::uint8_t position) noexcept { 34 | this->m_start = std::clamp(position, 0, Indentation::MAX); 35 | this->m_end = std::clamp(this->m_end, this->m_start, Indentation::MAX); 36 | } 37 | 38 | void Indentation::set_end(std::uint8_t position) noexcept { 39 | this->m_end = std::clamp(position, 0, Indentation::MAX); 40 | this->m_start = std::clamp(this->m_start, 0, this->m_end); 41 | } 42 | 43 | std::uint8_t Indentation::start_abs() const noexcept { 44 | return this->m_start; 45 | } 46 | 47 | std::uint8_t Indentation::end_abs() const noexcept { 48 | return this->m_end; 49 | } 50 | 51 | std::uint8_t Indentation::start() const noexcept { 52 | return this->m_start; 53 | } 54 | 55 | std::uint8_t Indentation::end() const noexcept { 56 | return Indentation::MAX - this->m_end; 57 | } 58 | 59 | std::uint8_t Indentation::offset() const noexcept { 60 | return this->m_end - this->m_start; 61 | } 62 | 63 | void Indentation::indent_start(std::uint8_t steps) noexcept { 64 | this->set_start(this->m_start + steps); 65 | } 66 | 67 | void Indentation::indent_end(std::uint8_t steps) noexcept { 68 | this->set_end(this->m_end - steps); 69 | } 70 | 71 | void Indentation::mirror() noexcept { 72 | std::uint8_t new_start = end(); 73 | m_end = Indentation::MAX - m_start; 74 | m_start = new_start; 75 | } 76 | 77 | std::uint8_t Indentation::uid() const { 78 | return static_cast(10 * m_start + offset() - (std::pow(m_start, 2) + m_start) / 2); 79 | } 80 | } // namespace inexor::vulkan_renderer::world 81 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/command_pool.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/command_pool.hpp" 2 | 3 | #include "inexor/vulkan-renderer/exception.hpp" 4 | #include "inexor/vulkan-renderer/wrapper/device.hpp" 5 | #include "inexor/vulkan-renderer/wrapper/make_info.hpp" 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace inexor::vulkan_renderer::wrapper { 12 | 13 | CommandPool::CommandPool(const Device &device, std::string name) : m_device(device), m_name(std::move(name)) { 14 | const auto cmd_pool_ci = make_info({ 15 | .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, 16 | .queueFamilyIndex = device.graphics_queue_family_index(), 17 | }); 18 | 19 | // Get the thread id as string for naming the command pool and the command buffers 20 | const std::size_t thread_id = std::hash{}(std::this_thread::get_id()); 21 | spdlog::trace("Creating command pool for thread {}", thread_id); 22 | 23 | if (const auto result = vkCreateCommandPool(m_device.device(), &cmd_pool_ci, nullptr, &m_cmd_pool); 24 | result != VK_SUCCESS) { 25 | throw VulkanException("Error: vkCreateCommandPool failed for command pool " + m_name + "!", result); 26 | } 27 | } 28 | 29 | CommandPool::CommandPool(CommandPool &&other) noexcept : m_device(other.m_device) { 30 | m_cmd_pool = std::exchange(other.m_cmd_pool, nullptr); 31 | } 32 | 33 | CommandPool::~CommandPool() { 34 | vkDestroyCommandPool(m_device.device(), m_cmd_pool, nullptr); 35 | } 36 | 37 | const CommandBuffer &CommandPool::request_command_buffer(const std::string &name) { 38 | // Try to find a command buffer which is currently not used 39 | for (const auto &cmd_buf : m_cmd_bufs) { 40 | if (cmd_buf->fence_status() == VK_SUCCESS) { 41 | // Reset the command buffer's fence to make it usable again 42 | cmd_buf->reset_fence(); 43 | m_device.set_debug_marker_name(*cmd_buf->ptr(), VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, name); 44 | cmd_buf->begin_command_buffer(); 45 | return *cmd_buf; 46 | } 47 | } 48 | 49 | // We need to create a new command buffer because no free one was found 50 | // Note that there is currently no method for shrinking m_cmd_bufs, but this should not be a problem 51 | m_cmd_bufs.emplace_back(std::make_unique(m_device, m_cmd_pool, "command buffer")); 52 | 53 | spdlog::trace("Creating new command buffer #{}", m_cmd_bufs.size()); 54 | 55 | m_cmd_bufs.back()->begin_command_buffer(); 56 | return *m_cmd_bufs.back(); 57 | } 58 | 59 | } // namespace inexor::vulkan_renderer::wrapper 60 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/cpu_texture.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/cpu_texture.hpp" 2 | 3 | #define STB_IMAGE_IMPLEMENTATION 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace inexor::vulkan_renderer::wrapper { 12 | 13 | CpuTexture::CpuTexture() : m_name("default texture") { 14 | generate_error_texture_data(); 15 | } 16 | 17 | CpuTexture::CpuTexture(const std::string &file_name, std::string name) : m_name(std::move(name)) { 18 | assert(!file_name.empty()); 19 | assert(!m_name.empty()); 20 | 21 | // Load the texture file using stb_image library. 22 | // Force stb_image to load an alpha channel as well. 23 | m_texture_data = stbi_load(file_name.c_str(), &m_texture_width, &m_texture_height, nullptr, STBI_rgb_alpha); 24 | 25 | if (m_texture_data == nullptr) { 26 | spdlog::error("Could not load texture file {} using stbi_load! Falling back to error texture", file_name); 27 | generate_error_texture_data(); 28 | } else { 29 | 30 | // TODO: We are currently hard coding the number of channels with STBI_rgb_alpha. 31 | // Eventually, we probably need to pass this information into this class from 32 | // a higher level class - like a material loader class. 33 | // So, as an example, if the material loader is loading a normal map, we know 34 | // we need to tell this class to load a 3 channel texture. If it can, great. 35 | // If it can not, then this class probably needs to load a 3 channel error texture. 36 | m_texture_channels = 4; 37 | 38 | // TODO: We are currently only supporting 1 mip level. 39 | m_mip_levels = 1; 40 | 41 | spdlog::trace("Texture dimensions: width: {}, height: {}, channels: {} mip levels: {}", m_texture_width, 42 | m_texture_height, m_texture_channels, m_mip_levels); 43 | } 44 | } 45 | 46 | CpuTexture::CpuTexture(CpuTexture &&other) noexcept { 47 | m_name = std::move(other.m_name); 48 | m_texture_width = other.m_texture_width; 49 | m_texture_height = other.m_texture_height; 50 | m_texture_channels = other.m_texture_channels; 51 | m_mip_levels = other.m_mip_levels; 52 | m_texture_data = other.m_texture_data; 53 | } 54 | 55 | CpuTexture::~CpuTexture() { 56 | stbi_image_free(m_texture_data); 57 | } 58 | 59 | void CpuTexture::generate_error_texture_data() { 60 | assert(m_texture_data == nullptr); 61 | 62 | m_texture_width = 512; 63 | m_texture_height = 512; 64 | m_texture_channels = 4; 65 | m_mip_levels = 1; 66 | 67 | // Create an 8x8 checkerboard pattern of squares. 68 | constexpr int SQUARE_DIMENSION{64}; 69 | // pink, purple 70 | constexpr std::array, 2> COLORS{{{0xFF, 0x69, 0xB4, 0xFF}, {0x94, 0x00, 0xD3, 0xFF}}}; 71 | 72 | const auto get_color = [](int x, int y, int square_dimension, std::size_t colors) -> int { 73 | return static_cast( 74 | (static_cast(x / square_dimension) + static_cast(y / square_dimension)) % colors); 75 | }; 76 | 77 | // Note: Using the stb library function since we are freeing with stbi_image_free. 78 | m_texture_data = static_cast(STBI_MALLOC(data_size())); // NOLINT 79 | 80 | // Performance could be improved by copying complete rows after one or two rows are created with the loops. 81 | for (int y = 0; y < m_texture_height; y++) { 82 | for (int x = 0; x < m_texture_width; x++) { 83 | const int color_id = get_color(x, y, SQUARE_DIMENSION, COLORS.size()); 84 | std::memcpy(m_texture_data, &COLORS[color_id][0], 4 * sizeof(COLORS[color_id][0])); 85 | } 86 | } 87 | } 88 | 89 | } // namespace inexor::vulkan_renderer::wrapper 90 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/descriptor_builder.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/descriptor_builder.hpp" 2 | 3 | #include "inexor/vulkan-renderer/wrapper/descriptor.hpp" 4 | #include "inexor/vulkan-renderer/wrapper/device.hpp" 5 | 6 | #include 7 | 8 | namespace inexor::vulkan_renderer::wrapper { 9 | 10 | DescriptorBuilder::DescriptorBuilder(const Device &device) : m_device(device) { 11 | assert(m_device.device()); 12 | } 13 | 14 | ResourceDescriptor DescriptorBuilder::build(std::string name) { 15 | assert(!m_layout_bindings.empty()); 16 | assert(!m_write_sets.empty()); 17 | assert(m_write_sets.size() == m_layout_bindings.size()); 18 | 19 | // Generate a new resource descriptor. 20 | ResourceDescriptor generated_descriptor(m_device, std::move(m_layout_bindings), std::move(m_write_sets), 21 | std::move(name)); 22 | 23 | m_descriptor_buffer_infos.clear(); 24 | m_descriptor_image_infos.clear(); 25 | 26 | return std::move(generated_descriptor); 27 | } 28 | 29 | DescriptorBuilder &DescriptorBuilder::add_combined_image_sampler(const VkSampler image_sampler, 30 | const VkImageView image_view, 31 | const std::uint32_t binding, 32 | const VkShaderStageFlagBits shader_stage) { 33 | assert(image_sampler); 34 | assert(image_view); 35 | 36 | m_layout_bindings.push_back({ 37 | .binding = 0, 38 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 39 | .descriptorCount = 1, 40 | .stageFlags = static_cast(shader_stage), 41 | }); 42 | 43 | m_descriptor_image_infos.push_back({ 44 | .sampler = image_sampler, 45 | .imageView = image_view, 46 | .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 47 | }); 48 | 49 | m_write_sets.push_back(make_info({ 50 | .dstSet = nullptr, 51 | .dstBinding = binding, 52 | .dstArrayElement = 0, 53 | .descriptorCount = 1, 54 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 55 | .pImageInfo = &m_descriptor_image_infos.back(), 56 | })); 57 | 58 | return *this; 59 | } 60 | 61 | } // namespace inexor::vulkan_renderer::wrapper 62 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/fence.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/fence.hpp" 2 | 3 | #include "inexor/vulkan-renderer/wrapper/device.hpp" 4 | #include "inexor/vulkan-renderer/wrapper/make_info.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace inexor::vulkan_renderer::wrapper { 11 | 12 | Fence::Fence(const Device &device, const std::string &name, const bool in_signaled_state) 13 | : m_device(device), m_name(name) { 14 | assert(!name.empty()); 15 | assert(device.device()); 16 | 17 | m_device.create_fence( 18 | make_info({ 19 | .flags = static_cast(in_signaled_state ? VK_FENCE_CREATE_SIGNALED_BIT : 0), 20 | }), 21 | &m_fence, m_name); 22 | } 23 | 24 | Fence::Fence(Fence &&other) noexcept : m_device(other.m_device) { 25 | m_fence = std::exchange(other.m_fence, nullptr); 26 | m_name = std::move(other.m_name); 27 | } 28 | 29 | Fence::~Fence() { 30 | vkDestroyFence(m_device.device(), m_fence, nullptr); 31 | } 32 | 33 | void Fence::block(std::uint64_t timeout_limit) const { 34 | vkWaitForFences(m_device.device(), 1, &m_fence, VK_TRUE, timeout_limit); 35 | } 36 | 37 | void Fence::reset() const { 38 | vkResetFences(m_device.device(), 1, &m_fence); 39 | } 40 | 41 | VkResult Fence::status() const { 42 | return vkGetFenceStatus(m_device.device(), m_fence); 43 | } 44 | 45 | } // namespace inexor::vulkan_renderer::wrapper 46 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/framebuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/framebuffer.hpp" 2 | 3 | #include "inexor/vulkan-renderer/wrapper/device.hpp" 4 | #include "inexor/vulkan-renderer/wrapper/make_info.hpp" 5 | #include "inexor/vulkan-renderer/wrapper/swapchain.hpp" 6 | 7 | #include 8 | #include 9 | 10 | namespace inexor::vulkan_renderer::wrapper { 11 | 12 | Framebuffer::Framebuffer(const Device &device, VkRenderPass render_pass, const std::vector &attachments, 13 | const Swapchain &swapchain, std::string name) 14 | : m_device(device), m_name(std::move(name)) { 15 | m_device.create_framebuffer(make_info({ 16 | .renderPass = render_pass, 17 | .attachmentCount = static_cast(attachments.size()), 18 | .pAttachments = attachments.data(), 19 | .width = swapchain.extent().width, 20 | .height = swapchain.extent().height, 21 | .layers = 1, 22 | }), 23 | &m_framebuffer, m_name); 24 | } 25 | 26 | Framebuffer::Framebuffer(Framebuffer &&other) noexcept : m_device(other.m_device) { 27 | m_framebuffer = std::exchange(other.m_framebuffer, nullptr); 28 | m_name = std::move(other.m_name); 29 | } 30 | 31 | Framebuffer::~Framebuffer() { 32 | vkDestroyFramebuffer(m_device.device(), m_framebuffer, nullptr); 33 | } 34 | 35 | } // namespace inexor::vulkan_renderer::wrapper 36 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/gpu_memory_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/gpu_memory_buffer.hpp" 2 | 3 | #include "inexor/vulkan-renderer/exception.hpp" 4 | #include "inexor/vulkan-renderer/wrapper/device.hpp" 5 | #include "inexor/vulkan-renderer/wrapper/make_info.hpp" 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace inexor::vulkan_renderer::wrapper { 13 | 14 | GPUMemoryBuffer::GPUMemoryBuffer(const Device &device, const std::string &name, const VkDeviceSize &size, 15 | const VkBufferUsageFlags &buffer_usage, const VmaMemoryUsage &memory_usage) 16 | : m_device(device), m_name(name), m_buffer_size(size) { 17 | assert(device.device()); 18 | assert(device.allocator()); 19 | assert(!name.empty()); 20 | 21 | spdlog::trace("Creating GPU memory buffer of size {} for {}", size, name); 22 | 23 | const auto buffer_ci = make_info({ 24 | .size = size, 25 | .usage = buffer_usage, 26 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 27 | }); 28 | 29 | const VmaAllocationCreateInfo m_allocation_ci{ 30 | .flags = VMA_ALLOCATION_CREATE_MAPPED_BIT, 31 | .usage = memory_usage, 32 | }; 33 | 34 | // TODO: Should we create this buffer as mapped? 35 | // TODO: Is it good to have memory mapped all the time? 36 | // TODO: When should memory be mapped / unmapped? 37 | 38 | if (const auto result = vmaCreateBuffer(m_device.allocator(), &buffer_ci, &m_allocation_ci, &m_buffer, 39 | &m_allocation, &m_allocation_info); 40 | result != VK_SUCCESS) { 41 | throw VulkanException("Error: GPU memory buffer allocation for " + name + " failed!", result); 42 | } 43 | 44 | // Assign an internal debug marker name to this buffer. 45 | m_device.set_debug_marker_name(m_buffer, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, name); 46 | 47 | vmaSetAllocationName(m_device.allocator(), m_allocation, m_name.c_str()); 48 | } 49 | 50 | GPUMemoryBuffer::GPUMemoryBuffer(const Device &device, const std::string &name, const VkDeviceSize &buffer_size, 51 | const void *data, const std::size_t data_size, const VkBufferUsageFlags &buffer_usage, 52 | const VmaMemoryUsage &memory_usage) 53 | : GPUMemoryBuffer(device, name, buffer_size, buffer_usage, memory_usage) { 54 | assert(device.device()); 55 | assert(device.allocator()); 56 | assert(!name.empty()); 57 | assert(buffer_size > 0); 58 | assert(data_size > 0); 59 | assert(data); 60 | 61 | // Copy the memory into the buffer! 62 | std::memcpy(m_allocation_info.pMappedData, data, data_size); 63 | } 64 | 65 | GPUMemoryBuffer::GPUMemoryBuffer(GPUMemoryBuffer &&other) noexcept : m_device(other.m_device) { 66 | m_name = std::move(other.m_name); 67 | m_buffer = std::exchange(other.m_buffer, nullptr); 68 | m_allocation = std::exchange(other.m_allocation, nullptr); 69 | m_allocation_info = other.m_allocation_info; 70 | } 71 | 72 | GPUMemoryBuffer::~GPUMemoryBuffer() { 73 | vmaDestroyBuffer(m_device.allocator(), m_buffer, m_allocation); 74 | } 75 | 76 | } // namespace inexor::vulkan_renderer::wrapper 77 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/image.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/image.hpp" 2 | 3 | #include "inexor/vulkan-renderer/exception.hpp" 4 | #include "inexor/vulkan-renderer/wrapper/device.hpp" 5 | #include "inexor/vulkan-renderer/wrapper/make_info.hpp" 6 | 7 | #include 8 | #include 9 | 10 | namespace inexor::vulkan_renderer::wrapper { 11 | 12 | Image::Image(const Device &device, const VkFormat format, const VkImageUsageFlags image_usage, 13 | const VkImageAspectFlags aspect_flags, const VkSampleCountFlagBits sample_count, const std::string &name, 14 | const VkExtent2D image_extent) 15 | : m_device(device), m_format(format), m_name(name) { 16 | assert(device.device()); 17 | assert(device.physical_device()); 18 | assert(device.allocator()); 19 | assert(image_extent.width > 0); 20 | assert(image_extent.height > 0); 21 | assert(!name.empty()); 22 | 23 | const auto image_ci = make_info({ 24 | .imageType = VK_IMAGE_TYPE_2D, 25 | .format = format, 26 | .extent{ 27 | .width = image_extent.width, 28 | .height = image_extent.height, 29 | .depth = 1, 30 | }, 31 | .mipLevels = 1, 32 | .arrayLayers = 1, 33 | .samples = sample_count, 34 | .tiling = VK_IMAGE_TILING_OPTIMAL, 35 | .usage = image_usage, 36 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 37 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, 38 | }); 39 | 40 | const VmaAllocationCreateInfo vma_allocation_ci{ 41 | .flags = VMA_ALLOCATION_CREATE_MAPPED_BIT, 42 | .usage = VMA_MEMORY_USAGE_GPU_ONLY, 43 | }; 44 | 45 | if (const auto result = vmaCreateImage(m_device.allocator(), &image_ci, &vma_allocation_ci, &m_image, &m_allocation, 46 | &m_allocation_info); 47 | result != VK_SUCCESS) { 48 | throw VulkanException("Error: vmaCreateImage failed for image " + m_name + "!", result); 49 | } 50 | 51 | vmaSetAllocationName(m_device.allocator(), m_allocation, m_name.c_str()); 52 | 53 | // Assign an internal name using Vulkan debug markers. 54 | m_device.set_debug_marker_name(m_image, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, m_name); 55 | 56 | m_device.create_image_view(make_info({ 57 | .image = m_image, 58 | .viewType = VK_IMAGE_VIEW_TYPE_2D, 59 | .format = format, 60 | .subresourceRange{ 61 | .aspectMask = aspect_flags, 62 | .baseMipLevel = 0, 63 | .levelCount = 1, 64 | .baseArrayLayer = 0, 65 | .layerCount = 1, 66 | }, 67 | }), 68 | &m_image_view, m_name); 69 | } 70 | 71 | Image::Image(Image &&other) noexcept : m_device(other.m_device) { 72 | m_allocation = other.m_allocation; 73 | m_allocation_info = other.m_allocation_info; 74 | m_image = other.m_image; 75 | m_format = other.m_format; 76 | m_image_view = other.m_image_view; 77 | m_name = std::move(other.m_name); 78 | } 79 | 80 | Image::~Image() { 81 | vkDestroyImageView(m_device.device(), m_image_view, nullptr); 82 | vmaDestroyImage(m_device.allocator(), m_image, m_allocation); 83 | } 84 | 85 | } // namespace inexor::vulkan_renderer::wrapper 86 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/semaphore.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/semaphore.hpp" 2 | 3 | #include "inexor/vulkan-renderer/wrapper/device.hpp" 4 | #include "inexor/vulkan-renderer/wrapper/make_info.hpp" 5 | 6 | #include 7 | #include 8 | 9 | namespace inexor::vulkan_renderer::wrapper { 10 | 11 | Semaphore::Semaphore(const Device &device, const std::string &name) : m_device(device), m_name(name) { 12 | assert(!name.empty()); 13 | device.create_semaphore(make_info(), &m_semaphore, m_name); 14 | } 15 | 16 | Semaphore::Semaphore(Semaphore &&other) noexcept : m_device(other.m_device) { 17 | m_semaphore = std::exchange(other.m_semaphore, VK_NULL_HANDLE); 18 | m_name = std::move(other.m_name); 19 | } 20 | 21 | Semaphore::~Semaphore() { 22 | vkDestroySemaphore(m_device.device(), m_semaphore, nullptr); 23 | } 24 | 25 | } // namespace inexor::vulkan_renderer::wrapper 26 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/shader.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/shader.hpp" 2 | 3 | #include "inexor/vulkan-renderer/tools/file.hpp" 4 | #include "inexor/vulkan-renderer/wrapper/device.hpp" 5 | #include "inexor/vulkan-renderer/wrapper/make_info.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace inexor::vulkan_renderer::wrapper { 12 | 13 | Shader::Shader(const Device &device, const VkShaderStageFlagBits type, const std::string &name, 14 | const std::string &file_name, const std::string &entry_point) 15 | : Shader(device, type, name, tools::read_file_binary_data(file_name), entry_point) {} 16 | 17 | Shader::Shader(const Device &device, const VkShaderStageFlagBits type, const std::string &name, 18 | const std::vector &code, const std::string &entry_point) 19 | : m_device(device), m_type(type), m_name(name), m_entry_point(entry_point) { 20 | assert(device.device()); 21 | assert(!name.empty()); 22 | assert(!code.empty()); 23 | assert(!entry_point.empty()); 24 | 25 | m_device.create_shader_module( 26 | make_info({ 27 | .codeSize = code.size(), 28 | // When you perform a cast like this, you also need to ensure that the data satisfies the alignment 29 | // requirements of std::uint32_t. Lucky for us, the data is stored in an std::vector where the default 30 | // allocator already ensures that the data satisfies the worst case alignment requirements. 31 | .pCode = reinterpret_cast(code.data()), // NOLINT 32 | }), 33 | &m_shader_module, m_name); 34 | } 35 | 36 | Shader::Shader(Shader &&other) noexcept : m_device(other.m_device) { 37 | m_type = other.m_type; 38 | m_name = std::move(other.m_name); 39 | m_entry_point = std::move(other.m_entry_point); 40 | m_shader_module = std::exchange(other.m_shader_module, nullptr); 41 | } 42 | 43 | Shader::~Shader() { 44 | vkDestroyShaderModule(m_device.device(), m_shader_module, nullptr); 45 | } 46 | 47 | } // namespace inexor::vulkan_renderer::wrapper 48 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/uniform_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/uniform_buffer.hpp" 2 | 3 | #include 4 | #include 5 | 6 | namespace inexor::vulkan_renderer::wrapper { 7 | 8 | UniformBuffer::UniformBuffer(const Device &device, const std::string &name, const VkDeviceSize &buffer_size) 9 | : GPUMemoryBuffer(device, name, buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU) {} 10 | 11 | UniformBuffer::UniformBuffer(UniformBuffer &&other) noexcept : GPUMemoryBuffer(std::move(other)) {} 12 | 13 | void UniformBuffer::update(void *data, const std::size_t size) { 14 | std::memcpy(m_allocation_info.pMappedData, data, size); 15 | } 16 | 17 | } // namespace inexor::vulkan_renderer::wrapper 18 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/window.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/window.hpp" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace inexor::vulkan_renderer::wrapper { 9 | 10 | Window::Window(const std::string &title, const std::uint32_t width, const std::uint32_t height, const bool visible, 11 | const bool resizable, const Mode mode) 12 | : m_width(width), m_height(height), m_mode(mode) { 13 | assert(!title.empty()); 14 | 15 | if (glfwInit() != GLFW_TRUE) { 16 | throw std::runtime_error("Failed to initialise GLFW!"); 17 | } 18 | 19 | glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 20 | glfwWindowHint(GLFW_VISIBLE, visible ? GLFW_TRUE : GLFW_FALSE); 21 | glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE); 22 | 23 | spdlog::trace("Creating window"); 24 | 25 | GLFWmonitor *monitor = nullptr; 26 | if (m_mode != Mode::WINDOWED) { 27 | monitor = glfwGetPrimaryMonitor(); 28 | if (m_mode == Mode::WINDOWED_FULLSCREEN) { 29 | const auto *video_mode = glfwGetVideoMode(monitor); 30 | m_width = video_mode->width; 31 | m_height = video_mode->height; 32 | } 33 | } 34 | 35 | m_window = glfwCreateWindow(static_cast(width), static_cast(height), title.c_str(), monitor, nullptr); 36 | 37 | if (m_window == nullptr) { 38 | throw std::runtime_error("Error: glfwCreateWindow failed for window " + title + " !"); 39 | } 40 | } 41 | 42 | Window::~Window() { 43 | glfwDestroyWindow(m_window); 44 | glfwTerminate(); 45 | } 46 | 47 | void Window::wait_for_focus() { 48 | int current_width = 0; 49 | int current_height = 0; 50 | 51 | do { 52 | glfwWaitEvents(); 53 | glfwGetFramebufferSize(m_window, ¤t_width, ¤t_height); 54 | } while (current_width == 0 || current_height == 0); 55 | 56 | m_width = current_width; 57 | m_height = current_height; 58 | } 59 | 60 | void Window::set_title(const std::string &title) { 61 | assert(!title.empty()); 62 | glfwSetWindowTitle(m_window, title.c_str()); 63 | } 64 | 65 | void Window::set_user_ptr(void *user_ptr) { 66 | glfwSetWindowUserPointer(m_window, user_ptr); 67 | } 68 | 69 | void Window::set_resize_callback(GLFWframebuffersizefun frame_buffer_resize_callback) { 70 | glfwSetFramebufferSizeCallback(m_window, frame_buffer_resize_callback); 71 | } 72 | 73 | void Window::set_keyboard_button_callback(GLFWkeyfun keyboard_button_callback) { 74 | glfwSetKeyCallback(m_window, keyboard_button_callback); 75 | } 76 | 77 | void Window::set_cursor_position_callback(GLFWcursorposfun cursor_pos_callback) { 78 | glfwSetCursorPosCallback(m_window, cursor_pos_callback); 79 | } 80 | 81 | void Window::set_mouse_button_callback(GLFWmousebuttonfun mouse_button_callback) { 82 | glfwSetMouseButtonCallback(m_window, mouse_button_callback); 83 | } 84 | 85 | void Window::set_mouse_scroll_callback(GLFWscrollfun mouse_scroll_callback) { 86 | glfwSetScrollCallback(m_window, mouse_scroll_callback); 87 | } 88 | 89 | void Window::show() { 90 | glfwShowWindow(m_window); 91 | } 92 | 93 | void Window::poll() { 94 | glfwPollEvents(); 95 | } 96 | 97 | bool Window::should_close() { 98 | return glfwWindowShouldClose(m_window) == GLFW_TRUE; 99 | } 100 | 101 | } // namespace inexor::vulkan_renderer::wrapper 102 | -------------------------------------------------------------------------------- /src/vulkan-renderer/wrapper/window_surface.cpp: -------------------------------------------------------------------------------- 1 | #include "inexor/vulkan-renderer/wrapper/window_surface.hpp" 2 | 3 | #include "inexor/vulkan-renderer/exception.hpp" 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace inexor::vulkan_renderer::wrapper { 11 | 12 | WindowSurface::WindowSurface(const VkInstance instance, GLFWwindow *window) : m_instance(instance) { 13 | assert(instance); 14 | assert(window); 15 | 16 | spdlog::trace("Creating window surface"); 17 | 18 | if (const auto result = glfwCreateWindowSurface(instance, window, nullptr, &m_surface); result != VK_SUCCESS) { 19 | throw VulkanException("Error: glfwCreateWindowSurface failed!", result); 20 | } 21 | } 22 | 23 | WindowSurface::WindowSurface(WindowSurface &&other) noexcept { 24 | m_instance = other.m_instance; 25 | m_surface = std::exchange(other.m_surface, nullptr); 26 | } 27 | 28 | WindowSurface::~WindowSurface() { 29 | vkDestroySurfaceKHR(m_instance, m_surface, nullptr); 30 | } 31 | 32 | } // namespace inexor::vulkan_renderer::wrapper 33 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | FetchContent_MakeAvailable(gtest) 2 | 3 | set(INEXOR_UNIT_TEST_SOURCE_FILES 4 | unit_tests_main.cpp 5 | gpu-selection/selection.cpp 6 | swapchain/choose_settings.cpp 7 | world/cube_collision.cpp 8 | world/cube.cpp 9 | ) 10 | 11 | add_executable(inexor-vulkan-renderer-tests ${INEXOR_UNIT_TEST_SOURCE_FILES}) 12 | 13 | set_target_properties( 14 | inexor-vulkan-renderer-tests PROPERTIES 15 | 16 | CXX_EXTENSIONS OFF 17 | CXX_STANDARD 20 18 | CXX_STANDARD_REQUIRED ON 19 | ) 20 | 21 | target_link_libraries( 22 | inexor-vulkan-renderer-tests 23 | 24 | PRIVATE 25 | inexor-vulkan-renderer 26 | 27 | PUBLIC 28 | GTest::gtest 29 | ) 30 | -------------------------------------------------------------------------------- /tests/unit_tests_main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "inexor/vulkan-renderer/meta.hpp" 4 | 5 | #include 6 | 7 | int main(int argc, char **argv) { 8 | using namespace inexor::vulkan_renderer; 9 | 10 | // Print engine and application metadata. 11 | std::cout << ENGINE_NAME << ", version " << ENGINE_VERSION_STR << std::endl; 12 | std::cout << APP_NAME << ", version " << APP_VERSION_STR << std::endl; 13 | std::cout << "Configuration: " << BUILD_TYPE << ", Git SHA " << BUILD_GIT << std::endl; 14 | 15 | testing::InitGoogleTest(&argc, argv); 16 | RUN_ALL_TESTS(); 17 | 18 | std::cout << "Press Enter to close" << std::endl; 19 | std::cin.get(); 20 | } 21 | -------------------------------------------------------------------------------- /tests/world/cube.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace { 6 | using namespace inexor::vulkan_renderer::world; 7 | 8 | TEST(Cube, neighbor) { 9 | std::shared_ptr root = std::make_shared(2.0f, glm::vec3{0, -1, -1}); 10 | root->set_type(Cube::Type::OCTANT); 11 | 12 | for (const auto &child : root->children()) { 13 | child->set_type(Cube::Type::OCTANT); 14 | 15 | for (const auto &grandchild : child->children()) { 16 | grandchild->set_type(Cube::Type::OCTANT); 17 | } 18 | } 19 | 20 | EXPECT_EQ(root->children()[1]->neighbor(Cube::NeighborAxis::Y, Cube::NeighborDirection::POSITIVE), 21 | root->children()[3]); 22 | EXPECT_NE(root->children()[1]->neighbor(Cube::NeighborAxis::Y, Cube::NeighborDirection::POSITIVE), 23 | root->children()[0]); 24 | EXPECT_EQ(root->children()[1]->children()[2]->neighbor(Cube::NeighborAxis::Y, Cube::NeighborDirection::POSITIVE), 25 | root->children()[3]->children()[0]); 26 | EXPECT_EQ(root->children()[1]->children()[2]->neighbor(Cube::NeighborAxis::Z, Cube::NeighborDirection::NEGATIVE), 27 | root->children()[0]->children()[3]); 28 | } 29 | 30 | } // namespace 31 | -------------------------------------------------------------------------------- /tests/world/cube_collision.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace inexor::vulkan_renderer { 7 | 8 | TEST(CubeCollision, CollisionCheck) { 9 | const glm::vec3 world_pos{0, 0, 0}; 10 | world::Cube world(1.0f, world_pos); 11 | world.set_type(world::Cube::Type::SOLID); 12 | 13 | glm::vec3 cam_pos{0.0f, 0.0f, 10.0f}; 14 | glm::vec3 cam_direction{0.0f, 0.0f, 0.0f}; 15 | 16 | auto collision1 = ray_cube_collision_check(world, cam_pos, cam_direction); 17 | bool collision_found = collision1.has_value(); 18 | 19 | // There must be no collision for this data setup. 20 | EXPECT_FALSE(collision_found); 21 | 22 | cam_direction = {0.0f, 0.0f, -1.0f}; 23 | 24 | auto collision2 = ray_cube_collision_check(world, cam_pos, cam_direction); 25 | collision_found = collision2.has_value(); 26 | 27 | // Since we are now directly looking down on the cube, we collide with it. 28 | EXPECT_TRUE(collision_found); 29 | } 30 | 31 | } // namespace inexor::vulkan_renderer 32 | --------------------------------------------------------------------------------