diff --git a/.gitignore b/.gitignore index ae5f6c81..410b95ad 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,221 @@ ads.txt build_ebook.log temp_ebook.md ebook/*.pdf -ebook/*.epub \ No newline at end of file +ebook/*.epub + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +# Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +# poetry.lock +# poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +# pdm.lock +# pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +# pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# Redis +*.rdb +*.aof +*.pid + +# RabbitMQ +mnesia/ +rabbitmq/ +rabbitmq-data/ + +# ActiveMQ +activemq-data/ + +# SageMath parsed files +*.sage.py + +# Environments +.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +# .idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, +# you could uncomment the following to ignore the entire vscode folder +# .vscode/ + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ + +# Streamlit +.streamlit/secrets.toml diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..24ee5b1b --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/README.md b/README.md index fcbb3775..b14b7f26 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ necessary. Now with the above done, we can generate the static files. Asuming the daux.io and VulkanTutorial directories are next to each other, go into the `daux.io` directory and run a command similar to: -`php generate -s ../VulkanTutorial -d ../VulkanTutorial/out`. +`daux generate -s ../VulkanTutorial -d ../VulkanTutorial/out`. `-s` tells it where to find the documentation, while `-d` tells it where to put the generated files. diff --git a/build_ebook.py b/build_ebook.py index 39e9a969..112483dc 100755 --- a/build_ebook.py +++ b/build_ebook.py @@ -11,6 +11,9 @@ from subprocess import CalledProcessError from re import Match import shutil +import argparse +import sys +from make_parser import make_parser logging.basicConfig( format="%(asctime)s %(levelname)-8s %(message)s", @@ -148,7 +151,7 @@ def compile_full_markdown( return markdown_file -def build_pdf(markdown_file: Path, pdf_file: Path) -> Path: +def build_pdf(markdown_file: Path, pdf_file: Path, args: argparse.Namespace) -> Path: """Build combined Markdown file into a PDF.""" try: @@ -157,12 +160,21 @@ def build_pdf(markdown_file: Path, pdf_file: Path) -> Path: raise RuntimeError(f"failed to build {pdf_file}: xelatex not installed") try: + keys_values = [(arg, getattr(args, arg)) for arg in vars(args)] + opts = [f"{key}={val}" for key, val in keys_values if val != ""] + pandoc_args = [x for i in opts for x in ("-V", i)] + subprocess.check_output( [ "pandoc", markdown_file.as_posix(), "-V", - "documentclass=report", + "documentclass=report" + ] + + + pandoc_args + + + [ "-t", "latex", "-s", @@ -202,8 +214,10 @@ def build_epub(markdown_file: Path, epub_file: Path) -> Path: return epub_file - def main() -> None: + parser = make_parser() + args = parser.parse_args(sys.argv[1:]) + """Build ebooks.""" with TemporaryDirectory() as raw_out_dir: out_dir = Path(raw_out_dir) @@ -223,11 +237,11 @@ def main() -> None: ) logging.info(f"{lang}: building pdf...") - pdf_file = build_pdf(markdown_file, out_dir / f"{lang}.pdf") + pdf_file = build_pdf(markdown_file, out_dir / f"{lang}.pdf", args) logging.info(f"{lang}: building epub...") epub_file = build_epub(markdown_file, out_dir / f"{lang}.epub") - + shutil.copy(pdf_file, f"ebook/vulkan_tutorial_{lang}.pdf") shutil.copy(epub_file, f"ebook/vulkan_tutorial_{lang}.epub") diff --git a/code/28_model_loading.cpp b/code/28_model_loading.cpp index 319e4f7f..0097a311 100644 --- a/code/28_model_loading.cpp +++ b/code/28_model_loading.cpp @@ -995,10 +995,10 @@ class HelloTriangleApplication { tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; - std::string warn, err; + std::string err; - if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, MODEL_PATH.c_str())) { - throw std::runtime_error(warn + err); + if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, MODEL_PATH.c_str())) { + throw std::runtime_error(err); } std::unordered_map uniqueVertices{}; diff --git a/code/29_mipmapping.cpp b/code/29_mipmapping.cpp index ae0cadf5..874a8d82 100644 --- a/code/29_mipmapping.cpp +++ b/code/29_mipmapping.cpp @@ -1089,10 +1089,10 @@ class HelloTriangleApplication { tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; - std::string warn, err; + std::string err; - if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, MODEL_PATH.c_str())) { - throw std::runtime_error(warn + err); + if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, MODEL_PATH.c_str())) { + throw std::runtime_error(err); } std::unordered_map uniqueVertices{}; diff --git a/code/30_multisampling.cpp b/code/30_multisampling.cpp index 638c2219..ab6cbc3f 100644 --- a/code/30_multisampling.cpp +++ b/code/30_multisampling.cpp @@ -1139,10 +1139,10 @@ class HelloTriangleApplication { tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; - std::string warn, err; + std::string err; - if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, MODEL_PATH.c_str())) { - throw std::runtime_error(warn + err); + if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, MODEL_PATH.c_str())) { + throw std::runtime_error(err); } std::unordered_map uniqueVertices{}; diff --git a/config.json b/config.json index bc711b52..edb3a0b3 100644 --- a/config.json +++ b/config.json @@ -21,7 +21,7 @@ "Support the website": "https://www.paypal.me/AOvervoorde", "Vulkan Specification": "https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/", "LunarG Vulkan SDK": "https://lunarg.com/vulkan-sdk/", - "Vulkan Guide": "https://github.com/KhronosGroup/Vulkan-Guide", + "Vulkan Guide": "https://docs.vulkan.org/guide/latest/", "Vulkan Hardware Database": "https://vulkan.gpuinfo.org/", "Rust code": "https://github.com/bwasty/vulkan-tutorial-rs", "Java code": "https://github.com/Naitsirc98/Vulkan-Tutorial-Java", diff --git a/en/00_Introduction.md b/en/00_Introduction.md index e56799e9..1d14c781 100644 --- a/en/00_Introduction.md +++ b/en/00_Introduction.md @@ -1,3 +1,12 @@ +>## Read before following this tutorial +> +>This tutorial was written shortly after Vulkan was initially released, back in +>2016. A lot has changed since then and this tutorial no longer reflects the best +>way to use Vulkan today. +> +>Instead of reading this website, I recommend to follow the guide or one of the +>tutorials linked here: [https://vulkan.org/learn](https://vulkan.org/learn) + ## About This tutorial will teach you the basics of using the [Vulkan](https://www.khronos.org/vulkan/) diff --git a/en/02_Development_environment.md b/en/02_Development_environment.md index 8eac260f..2d8b2535 100644 --- a/en/02_Development_environment.md +++ b/en/02_Development_environment.md @@ -204,7 +204,7 @@ The most important components you'll need for developing Vulkan applications on * `sudo apt install vulkan-tools` or `sudo dnf install vulkan-tools`: Command-line utilities, most importantly `vulkaninfo` and `vkcube`. Run these to confirm your machine supports Vulkan. * `sudo apt install libvulkan-dev` or `sudo dnf install vulkan-loader-devel` : Installs Vulkan loader. The loader looks up the functions in the driver at runtime, similarly to GLEW for OpenGL - if you're familiar with that. -* `sudo apt install vulkan-validationlayers-dev spirv-tools` or `sudo dnf install mesa-vulkan-devel vulkan-validation-layers-devel`: Installs the standard validation layers and required SPIR-V tools. These are crucial when debugging Vulkan applications, and we'll discuss them in the upcoming chapter. +* `sudo apt install vulkan-validationlayers spirv-tools` or `sudo dnf install mesa-vulkan-drivers vulkan-validation-layers-devel`: Installs the standard validation layers and required SPIR-V tools. These are crucial when debugging Vulkan applications, and we'll discuss them in the upcoming chapter. On Arch Linux, you can run `sudo pacman -S vulkan-devel` to install all the required tools above. @@ -246,7 +246,7 @@ sudo dnf install glfw-devel ``` or ```bash -sudo pacman -S glfw-wayland # glfw-x11 for X11 users +sudo pacman -S glfw ``` ### GLM @@ -353,7 +353,7 @@ LDFLAGS = -lglfw -lvulkan -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi The flag `-lglfw` is for GLFW, `-lvulkan` links with the Vulkan function loader and the remaining flags are low-level system libraries that GLFW needs. The remaining flags are dependencies of GLFW itself: the threading and window management. -It is possible that the `Xxf68vm` and `Xi` libraries are not yet installed on your system. You can find them in the following packages: +It is possible that the `Xxf86vm` and `Xi` libraries are not yet installed on your system. You can find them in the following packages: ```bash sudo apt install libxxf86vm-dev libxi-dev diff --git a/en/03_Drawing_a_triangle/00_Setup/00_Base_code.md b/en/03_Drawing_a_triangle/00_Setup/00_Base_code.md index df26c6ac..e5b0e0b3 100644 --- a/en/03_Drawing_a_triangle/00_Setup/00_Base_code.md +++ b/en/03_Drawing_a_triangle/00_Setup/00_Base_code.md @@ -145,8 +145,14 @@ disable it for now with another window hint call: glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); ``` -All that's left now is creating the actual window. Add a `GLFWwindow* window;` -private class member to store a reference to it and initialize the window with: +All that's left now is creating the actual window. Add a private class member to store a reference to it: + +```c++ +private: +GLFWwindow* window; +``` + +Initialize the window with ```c++ window = glfwCreateWindow(800, 600, "Vulkan", nullptr, nullptr); diff --git a/en/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.md b/en/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.md index ef1ceabd..f593b5a6 100644 --- a/en/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.md +++ b/en/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.md @@ -515,7 +515,7 @@ you'll get the best performance by enabling clipping. createInfo.oldSwapchain = VK_NULL_HANDLE; ``` -That leaves one last field, `oldSwapChain`. With Vulkan it's possible that your swap chain becomes invalid or unoptimized while your application is +That leaves one last field, `oldSwapchain`. With Vulkan it's possible that your swap chain becomes invalid or unoptimized while your application is running, for example because the window was resized. In that case the swap chain actually needs to be recreated from scratch and a reference to the old one must be specified in this field. This is a complex topic that we'll learn more about diff --git a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.md b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.md index a80f72ae..5b4bfdec 100644 --- a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.md +++ b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.md @@ -175,7 +175,7 @@ viewportState.scissorCount = 1; viewportState.pScissors = &scissor; ``` -Independent of how you set them, it's is possible to use multiple viewports and scissor rectangles on some graphics cards, so the structure members reference an array of them. Using multiple requires enabling a GPU feature (see logical device creation). +Independent of how you set them, it's possible to use multiple viewports and scissor rectangles on some graphics cards, so the structure members reference an array of them. Using multiple requires enabling a GPU feature (see logical device creation). ## Rasterizer diff --git a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.md b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.md index 9c598528..ce58528b 100644 --- a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.md +++ b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.md @@ -49,7 +49,7 @@ void recreateSwapChain() { } ``` -Note that we don't recreate the renderpass here for simplicity. In theory it can be possible for the swap chain image format to change during an applications' lifetime, e.g. when moving a window from an standard range to an high dynamic range monitor. This may require the application to recreate the renderpass to make sure the change between dynamic ranges is properly reflected. +Note that we don't recreate the renderpass here for simplicity. In theory it can be possible for the swap chain image format to change during an applications' lifetime, e.g. when moving a window from a standard range to a high dynamic range monitor. This may require the application to recreate the renderpass to make sure the change between dynamic ranges is properly reflected. We'll move the cleanup code of all objects that are recreated as part of a swap chain refresh from `cleanup` to `cleanupSwapChain`: diff --git a/en/06_Texture_mapping/02_Combined_image_sampler.md b/en/06_Texture_mapping/02_Combined_image_sampler.md index 787ea367..0f1e5496 100644 --- a/en/06_Texture_mapping/02_Combined_image_sampler.md +++ b/en/06_Texture_mapping/02_Combined_image_sampler.md @@ -74,7 +74,7 @@ type (`VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER`, etc.) as specified by the corresponding `descriptorCount` members for the creation of the descriptor pool. However, it remains best practise to do so, and in the future, `VK_LAYER_KHRONOS_validation` will warn about this type of problem if you enable -[Best Practice Validation](https://vulkan.lunarg.com/doc/view/1.2.189.0/linux/best_practices.html). +[Best Practice Validation](https://vulkan.lunarg.com/doc/view/1.4.304.0/linux/best_practices.html). The final step is to bind the actual image and sampler resources to the descriptors in the descriptor set. Go to the `createDescriptorSets` function. diff --git a/en/08_Loading_models.md b/en/08_Loading_models.md index 620e31bf..f3ae89c0 100644 --- a/en/08_Loading_models.md +++ b/en/08_Loading_models.md @@ -138,10 +138,10 @@ void loadModel() { tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; - std::string warn, err; + std::string err; - if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, MODEL_PATH.c_str())) { - throw std::runtime_error(warn + err); + if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, MODEL_PATH.c_str())) { + throw std::runtime_error(err); } } ``` diff --git "a/fr/02_Environnement_de_d\303\251veloppement.md" "b/fr/02_Environnement_de_d\303\251veloppement.md" index 80796d81..1041fdbe 100644 --- "a/fr/02_Environnement_de_d\303\251veloppement.md" +++ "b/fr/02_Environnement_de_d\303\251veloppement.md" @@ -186,7 +186,7 @@ packages. Il vous faut un compilateur qui supporte C++17 (GCC 7+ ou Clang 5+). V Les composants les plus importants pour le développement d'applications Vulkan sous Linux sont le loader Vulkan, les validation layers et quelques utilitaires pour tester que votre machine est bien en état de faire fonctionner une application Vulkan: * `sudo apt install vulkan-tools` ou `sudo dnf install vulkan-tools`: Les utilitaires en ligne de commande, plus précisément `vulkaninfo` et `vkcube`. Lancez ceux-ci pour vérifier le bon fonctionnement de votre machine pour Vulkan. * `sudo apt install libvulkan-dev` ou `sudo dnf install vulkan-headers vulkan-loader-devel`: Installe le loader Vulkan. Il sert à aller chercher les fonctions auprès du driver de votre GPU au runtime, de la même façon que GLEW le fait pour OpenGL - si vous êtes familier avec ceci. -* `sudo apt install vulkan-validationlayers-dev` ou `sudo dnf install mesa-vulkan-devel vulkan-validation-layers-devel`: Installe les layers de validation standards. Ceux-ci sont cruciaux pour débugger vos applications Vulkan, et nous en reparlerons dans un prochain chapitre. +* `sudo apt install vulkan-validationlayers-dev` ou `sudo dnf install mesa-vulkan-drivers vulkan-validation-layers-devel`: Installe les layers de validation standards. Ceux-ci sont cruciaux pour débugger vos applications Vulkan, et nous en reparlerons dans un prochain chapitre. Si l'installation est un succès, vous devriez être prêt pour la partie Vulkan. N'oubliez pas de lancer `vkcube` et assurez-vous de voir la fenêtre suivante: diff --git "a/fr/03_Dessiner_un_triangle/01_Pr\303\251sentation/01_Swap_chain.md" "b/fr/03_Dessiner_un_triangle/01_Pr\303\251sentation/01_Swap_chain.md" index d12f1c76..539efe5b 100644 --- "a/fr/03_Dessiner_un_triangle/01_Pr\303\251sentation/01_Swap_chain.md" +++ "b/fr/03_Dessiner_un_triangle/01_Pr\303\251sentation/01_Swap_chain.md" @@ -458,7 +458,7 @@ informations, vous obtiendrez de meilleures performances en activant ce mode. createInfo.oldSwapchain = VK_NULL_HANDLE; ``` -Il nous reste un dernier champ, `oldSwapChain`. Il est possible avec Vulkan que la swap chain devienne +Il nous reste un dernier champ, `oldSwapchain`. Il est possible avec Vulkan que la swap chain devienne invalide ou mal adaptée pendant que votre application tourne, par exemple parce que la fenêtre a été redimensionnée. Dans ce cas la swap chain doit être intégralement recréée et une référence à l'ancienne swap chain doit être fournie. C'est un sujet compliqué que nous aborderons [dans un chapitre futur](!fr/Dessiner_un_triangle/Recréation_de_la_swap_chain). diff --git "a/fr/08_Charger_des_mod\303\250les.md" "b/fr/08_Charger_des_mod\303\250les.md" index 13a9b35e..04cdfda1 100644 --- "a/fr/08_Charger_des_mod\303\250les.md" +++ "b/fr/08_Charger_des_mod\303\250les.md" @@ -120,10 +120,10 @@ void loadModel() { tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; - std::string warn, err; + std::string err; - if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, MODEL_PATH.c_str())) { - throw std::runtime_error(warn + err); + if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, MODEL_PATH.c_str())) { + throw std::runtime_error(err); } } ``` diff --git a/make_parser.py b/make_parser.py new file mode 100644 index 00000000..8d0c5b5b --- /dev/null +++ b/make_parser.py @@ -0,0 +1,37 @@ +import argparse + +def make_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + description="Build the pdf and epub files of the Vulkan Tutorial." + ) + + parser.add_argument( + "--geometry:left", + type=str, + required=False, + default="2.5cm", + help="Specify left margin space as a string. Example: 2cm.", + ) + parser.add_argument( + "--geometry:right", + type=str, + required=False, + default="2.5cm", + help="Specify right margin space as a string. Example: 2cm.", + ) + parser.add_argument( + "--geometry:top", + type=str, + required=False, + default="2.5cm", + help="Specify top margin space as a string. Example: 2cm.", + ) + parser.add_argument( + "--geometry:bottom", + type=str, + required=False, + default="2.5cm", + help="Specify bottom margin space as a string. Example: 2cm.", + ) + + return parser diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..7749678c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "vulkantutorial" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = "~=3.13.0" +dependencies = [] diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000..84d6b942 --- /dev/null +++ b/uv.lock @@ -0,0 +1,8 @@ +version = 1 +revision = 3 +requires-python = "==3.13.*" + +[[package]] +name = "vulkantutorial" +version = "0.1.0" +source = { virtual = "." }