Compare commits
20 commits
feat/test_
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 63cb6dfe92 | |||
| 14c2512202 | |||
| 599f28fe73 | |||
| 0a1bda9573 | |||
| 311b20bdf2 | |||
| 6a257566bd | |||
| 4534ed11d2 | |||
| d029c0e473 | |||
| 604ee5e6a1 | |||
| 7ee4381bbf | |||
| 8730d31e2f | |||
| f50208653e | |||
| 5422792705 | |||
| 2ddb90faff | |||
| 736c37d2f1 | |||
| 97ca429d38 | |||
| 5a404d5269 | |||
| a9e27d6935 | |||
| 80662983a3 | |||
| c39ce89a9b |
161 changed files with 3836 additions and 2799 deletions
5
.clangd
Normal file
5
.clangd
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
CompileFlags:
|
||||
DriverMode: cl
|
||||
Add:
|
||||
- /EHsc
|
||||
- /std:c++latest
|
||||
286
.drone.yml
286
.drone.yml
|
|
@ -1,42 +1,42 @@
|
|||
# ---
|
||||
# kind: pipeline
|
||||
# type: exec
|
||||
# name: amd64 — msvc
|
||||
# trigger:
|
||||
# branch:
|
||||
# - main
|
||||
# platform:
|
||||
# os: windows
|
||||
# arch: amd64
|
||||
#
|
||||
# steps:
|
||||
# - name: unit tests
|
||||
# shell: powershell
|
||||
# commands:
|
||||
# - ./tools/ci/amd64/msvc/unit_tests.ps1
|
||||
#
|
||||
# ---
|
||||
# kind: pipeline
|
||||
# type: docker
|
||||
# name: amd64 — gcc
|
||||
# trigger:
|
||||
# branch:
|
||||
# - main
|
||||
#
|
||||
# steps:
|
||||
# - name: unit tests
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/amd64/gcc/unit_tests.sh
|
||||
#
|
||||
# - name: valgrind
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/amd64/gcc/valgrind.sh
|
||||
#
|
||||
# ---
|
||||
---
|
||||
kind: pipeline
|
||||
type: exec
|
||||
name: amd64 — msvc
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
platform:
|
||||
os: windows
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: unit tests
|
||||
shell: powershell
|
||||
commands:
|
||||
- ./tools/ci/amd64/msvc/unit_tests.ps1
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: amd64 — gcc
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
|
||||
steps:
|
||||
- name: unit tests
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/amd64/gcc/unit_tests.sh
|
||||
|
||||
- name: valgrind
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/amd64/gcc/valgrind.sh
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: amd64 — clang
|
||||
|
|
@ -45,114 +45,110 @@ trigger:
|
|||
- main
|
||||
|
||||
steps:
|
||||
# - name: code coverage
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# environment:
|
||||
# CODECOV_TOKEN:
|
||||
# from_secret: CODECOV_TOKEN
|
||||
# commands:
|
||||
# - ./tools/ci/amd64/clang/coverage.sh
|
||||
#
|
||||
# - name: leak sanitizer
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/amd64/clang/lsan.sh
|
||||
#
|
||||
- name: code coverage
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
environment:
|
||||
CODECOV_TOKEN:
|
||||
from_secret: CODECOV_TOKEN
|
||||
commands:
|
||||
- ./tools/ci/amd64/clang/coverage.sh
|
||||
|
||||
- name: leak sanitizer
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/amd64/clang/lsan.sh
|
||||
|
||||
- name: memory sanitizer
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/amd64/clang/msan.sh
|
||||
#
|
||||
# ---
|
||||
# kind: pipeline
|
||||
# type: docker
|
||||
# name: static analysis
|
||||
# trigger:
|
||||
# branch:
|
||||
# - main
|
||||
#
|
||||
# steps:
|
||||
# - name: clang tidy
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# privileged: true
|
||||
# commands:
|
||||
# - ./tools/ci/static_analysis/clang_tidy.sh
|
||||
#
|
||||
# - name: shell check
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/static_analysis/shell_check.sh
|
||||
#
|
||||
# - name: clang format
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/static_analysis/clang_format.sh
|
||||
#
|
||||
# - name: cmake format
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/static_analysis/cmake_format.sh
|
||||
#
|
||||
# - name: shell format
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/static_analysis/shell_format.sh
|
||||
#
|
||||
# ---
|
||||
# kind: pipeline
|
||||
# type: docker
|
||||
# name: documentation — development
|
||||
# node:
|
||||
# environment: ryali
|
||||
# trigger:
|
||||
# branch:
|
||||
# - main
|
||||
#
|
||||
# steps:
|
||||
# - name: build and deploy
|
||||
# image: documentation:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - pwd
|
||||
# - cd docs
|
||||
# - mkdir generated
|
||||
# - touch generated/changelogs.rst
|
||||
# - touch generated/api.rst
|
||||
# - sphinx-build -M html . .
|
||||
#
|
||||
# - rm -rf /light_docs_dev/*
|
||||
# - mv ./html/* /light_docs_dev/
|
||||
#
|
||||
# ---
|
||||
#
|
||||
# kind: pipeline
|
||||
# type: docker
|
||||
# name: documentation — production
|
||||
# node:
|
||||
# environment: ryali
|
||||
# trigger:
|
||||
# event:
|
||||
# - tag
|
||||
#
|
||||
# steps:
|
||||
# - name: build and deploy
|
||||
# image: documentation:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - cd docs
|
||||
# - mkdir generated
|
||||
# - touch generated/changelogs.rst
|
||||
# - touch generated/api.rst
|
||||
# - sphinx-build -M html . .
|
||||
#
|
||||
# - rm -rf /light_docs/*
|
||||
# - mv ./html/* /light_docs/
|
||||
#
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: static analysis
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
|
||||
steps:
|
||||
- name: clang tidy
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
privileged: true
|
||||
commands:
|
||||
- ./tools/ci/static_analysis/clang_tidy.sh
|
||||
|
||||
- name: shell check
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/static_analysis/shell_check.sh
|
||||
|
||||
- name: clang format
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/static_analysis/clang_format.sh
|
||||
|
||||
- name: cmake format
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/static_analysis/cmake_format.sh
|
||||
|
||||
- name: shell format
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/static_analysis/shell_format.sh
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: documentation — development
|
||||
node:
|
||||
environment: ryali
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
|
||||
steps:
|
||||
- name: build and deploy
|
||||
image: documentation:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- cd docs
|
||||
- sphinx-build -M html . .
|
||||
|
||||
- rm -rf /light_docs_dev/*
|
||||
- mv ./html/* /light_docs_dev/
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: documentation — production
|
||||
node:
|
||||
environment: ryali
|
||||
trigger:
|
||||
event:
|
||||
- tag
|
||||
|
||||
steps:
|
||||
- name: build and deploy
|
||||
image: documentation:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- cd docs
|
||||
- mkdir generated
|
||||
- touch generated/changelogs.rst
|
||||
- touch generated/api.rst
|
||||
- sphinx-build -M html . .
|
||||
|
||||
- rm -rf /light_docs/*
|
||||
- mv ./html/* /light_docs/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,128 +0,0 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
Discord: Light7734#4652.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
Binary file not shown.
|
|
@ -1,21 +1,26 @@
|
|||
#version 450 core
|
||||
|
||||
vec2 positions[3] = vec2[](
|
||||
vec2(0.0, -0.5),
|
||||
vec2(0.5, 0.5),
|
||||
vec2(-0.5, 0.5)
|
||||
layout(push_constant ) uniform pc {
|
||||
mat4 view_projection;
|
||||
};
|
||||
|
||||
vec3 positions[3] = vec3[](
|
||||
vec3(0.0, -0.5, 0.5),
|
||||
vec3(0.5, 0.5, 0.5),
|
||||
vec3(-0.5, 0.5, 0.5)
|
||||
);
|
||||
|
||||
vec3 colors[3] = vec3[](
|
||||
vec3(1.0, 0.0, 0.0),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
vec3(0.0, 0.0, 1.0)
|
||||
vec3(0.0, 0.0, 0.0),
|
||||
vec3(0.0, 0.0, 0.0),
|
||||
vec3(0.0, 0.0, 0.0)
|
||||
);
|
||||
|
||||
layout(location = 0) out vec3 out_frag_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||
gl_Position = view_projection * vec4(positions[gl_VertexIndex], 1.0);
|
||||
out_frag_color = colors[gl_VertexIndex];
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
2
docs/.gitignore
vendored
2
docs/.gitignore
vendored
|
|
@ -1,3 +1,5 @@
|
|||
_build/
|
||||
generated/
|
||||
html/
|
||||
xml/
|
||||
|
||||
|
|
|
|||
86
docs/Doxyfile
Normal file
86
docs/Doxyfile
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
TARGET = ./
|
||||
INPUT = "../modules"
|
||||
RECURSIVE = YES
|
||||
|
||||
PROJECT_NAME = "Light"
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
JAVADOC_BANNER = YES
|
||||
GENERATE_XML = YES
|
||||
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
|
||||
GENERATE_TODOLIST = NO
|
||||
GENERATE_HTML = NO
|
||||
GENERATE_DOCSET = NO
|
||||
GENERATE_HTMLHELP = NO
|
||||
GENERATE_CHI = NO
|
||||
GENERATE_QHP = NO
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
GENERATE_TREEVIEW = NO
|
||||
GENERATE_LATEX = NO
|
||||
GENERATE_RTF = NO
|
||||
GENERATE_MAN = NO
|
||||
GENERATE_DOCBOOK = NO
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
GENERATE_SQLITE3 = NO
|
||||
GENERATE_PERLMOD = NO
|
||||
GENERATE_TAGFILE = NO
|
||||
GENERATE_LEGEND = NO
|
||||
GENERATE_TESTLIST = NO
|
||||
GENERATE_BUGLIST = NO
|
||||
GENERATE_DEPRECATEDLIST= NO
|
||||
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cxxm \
|
||||
*.cpp \
|
||||
*.cppm \
|
||||
*.ccm \
|
||||
*.c++ \
|
||||
*.c++m \
|
||||
*.java \
|
||||
*.ii \
|
||||
*.ixx \
|
||||
*.ipp \
|
||||
*.i++ \
|
||||
*.inl \
|
||||
*.idl \
|
||||
*.ddl \
|
||||
*.odl \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++ \
|
||||
*.l \
|
||||
*.cs \
|
||||
*.d \
|
||||
*.php \
|
||||
*.php4 \
|
||||
*.php5 \
|
||||
*.phtml \
|
||||
*.inc \
|
||||
*.m \
|
||||
*.markdown \
|
||||
*.md \
|
||||
*.mm \
|
||||
*.dox \
|
||||
*.py \
|
||||
*.pyw \
|
||||
*.f90 \
|
||||
*.f95 \
|
||||
*.f03 \
|
||||
*.f08 \
|
||||
*.f18 \
|
||||
*.f \
|
||||
*.for \
|
||||
*.vhd \
|
||||
*.vhdl \
|
||||
*.ucf \
|
||||
*.qsf \
|
||||
*.ice
|
||||
17
docs/api/app.rst
Normal file
17
docs/api/app.rst
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
Application
|
||||
===================================================================================================
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:caption: App
|
||||
|
||||
Functions
|
||||
---------------------------------------------------------------------------------------------------
|
||||
.. doxygenfunction:: main
|
||||
|
||||
Classes
|
||||
---------------------------------------------------------------------------------------------------
|
||||
.. doxygenclass:: lt::app::ISystem
|
||||
|
||||
.. doxygenstruct:: lt::app::TickInfo
|
||||
|
||||
.. doxygenstruct:: lt::app::TickResult
|
||||
13
docs/api/renderer.rst
Normal file
13
docs/api/renderer.rst
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Renderer
|
||||
===================================================================================================
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:caption: App
|
||||
|
||||
Classes
|
||||
---------------------------------------------------------------------------------------------------
|
||||
.. doxygenenum:: lt::renderer::Api
|
||||
|
||||
.. doxygenclass:: lt::renderer::System
|
||||
|
||||
.. doxygenstruct:: lt::renderer::components::Sprite
|
||||
14
docs/conf.py
14
docs/conf.py
|
|
@ -13,13 +13,21 @@ author = 'light7734'
|
|||
# -- General configuration ---------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||
|
||||
extensions = []
|
||||
extensions = ['breathe']
|
||||
|
||||
breathe_projects = {"Light": "./xml"}
|
||||
breathe_default_project = "Light"
|
||||
breathe_default_members = ()
|
||||
|
||||
# Tell sphinx what the primary language being documented is.
|
||||
primary_domain = 'cpp'
|
||||
|
||||
# Tell sphinx what the pygments highlight language should be.
|
||||
highlight_language = 'cpp'
|
||||
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
from git import Repo
|
||||
import re
|
||||
|
||||
repo = Repo(search_parent_directories=True)
|
||||
assert not repo.bare
|
||||
|
||||
file_path = "generated/changelog.rst"
|
||||
|
||||
messages = []
|
||||
short_shas = []
|
||||
hex_shas = []
|
||||
logs = []
|
||||
|
||||
remote_url = "https://git.light7734.com/light7734/light/commit"
|
||||
def format_log(commit_type, message, major, minor, patch, short_sha, hex_sha):
|
||||
href = f"{remote_url}/{hex_sha}"
|
||||
version = f"{major}.{minor}.{patch}-kitten+{short_sha}";
|
||||
link = f"`{version} <{remote_url}/{hex_sha}>`__"
|
||||
return f"| **{message}** ({link})"
|
||||
|
||||
for commit in repo.iter_commits():
|
||||
messages.append(commit.summary)
|
||||
short_shas.append(repo.git.rev_parse(commit.hexsha, short=5))
|
||||
hex_shas.append(commit.hexsha)
|
||||
|
||||
ver_major = 0
|
||||
ver_minor = 0
|
||||
ver_patch = 0
|
||||
|
||||
idx = len(messages)
|
||||
for message in reversed(messages):
|
||||
idx = idx - 1;
|
||||
|
||||
commit_type = re.match("^(feat|fix|refactor|perf|build|asset|test|chore|ci|docs)", message)
|
||||
if not commit_type:
|
||||
continue
|
||||
|
||||
match commit_type.group(0):
|
||||
case "feat":
|
||||
ver_minor = ver_minor + 1
|
||||
ver_patch = 0
|
||||
|
||||
case "fix":
|
||||
ver_patch = ver_patch + 1
|
||||
|
||||
case "refactor":
|
||||
ver_patch = ver_patch + 1
|
||||
|
||||
case "perf":
|
||||
ver_patch = ver_patch + 1
|
||||
|
||||
case "build":
|
||||
ver_patch = ver_patch + 1
|
||||
|
||||
case "asset":
|
||||
ver_patch = ver_patch + 1
|
||||
|
||||
logs.append(format_log(commit_type, message, ver_major, ver_minor, ver_patch, short_shas[idx], hex_shas[idx]))
|
||||
|
||||
with open(file_path, "w") as f:
|
||||
f.write(".. changelogs\n\n\n")
|
||||
f.write("Changelogs\n")
|
||||
f.write("==================================================\n\n")
|
||||
|
||||
f.write("KITTEN\n")
|
||||
f.write("--------------------------------------------------\n\n")
|
||||
for log in reversed(logs):
|
||||
f.write(log + '\n')
|
||||
|
|
@ -23,10 +23,10 @@
|
|||
guidelines/conventions.rst
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Generated Docs
|
||||
:maxdepth: 3
|
||||
:caption: API
|
||||
|
||||
generated/api.rst
|
||||
generated/changelog.rst
|
||||
api/app.rst
|
||||
api/renderer.rst
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
|
|
@ -1,26 +1,37 @@
|
|||
# engine
|
||||
add_subdirectory(./std)
|
||||
add_subdirectory(./bitwise)
|
||||
add_subdirectory(./env)
|
||||
add_subdirectory(./memory)
|
||||
add_subdirectory(./time)
|
||||
add_subdirectory(./logger)
|
||||
add_subdirectory(./debug)
|
||||
add_subdirectory(./math)
|
||||
#
|
||||
add_subdirectory(./asset_baker)
|
||||
add_subdirectory(./assets)
|
||||
#
|
||||
add_subdirectory(./camera)
|
||||
add_subdirectory(./input)
|
||||
# add_subdirectory(./ui)
|
||||
#
|
||||
add_subdirectory(./surface)
|
||||
add_subdirectory(./renderer)
|
||||
add_subdirectory(./ecs)
|
||||
#
|
||||
add_subdirectory(./app)
|
||||
# engine add_subdirectory(./std)
|
||||
|
||||
# apps
|
||||
add_subdirectory(./mirror)
|
||||
add_subdirectory(test)
|
||||
|
||||
add_subdirectory(./logger)
|
||||
|
||||
add_subdirectory(./bitwise)
|
||||
|
||||
add_subdirectory(./env)
|
||||
|
||||
add_subdirectory(./memory)
|
||||
|
||||
add_subdirectory(./time)
|
||||
|
||||
add_subdirectory(./debug)
|
||||
|
||||
add_subdirectory(./math)
|
||||
|
||||
add_subdirectory(./assets)
|
||||
|
||||
add_subdirectory(./asset_baker)
|
||||
|
||||
add_subdirectory(./camera)
|
||||
|
||||
add_subdirectory(./app)
|
||||
add_subdirectory(./ecs)
|
||||
|
||||
add_subdirectory(./surface)
|
||||
|
||||
add_subdirectory(./input)
|
||||
|
||||
# add_subdirectory(./ui)
|
||||
|
||||
# add_subdirectory(./renderer)
|
||||
|
||||
#
|
||||
# add_subdirectory(./mirror)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
add_library_module(app application.cpp)
|
||||
add_library_module(
|
||||
NAME
|
||||
app
|
||||
INTERFACES
|
||||
application.cppm
|
||||
system.cppm
|
||||
SOURCES
|
||||
entrypoint.cpp)
|
||||
|
||||
target_link_libraries(
|
||||
app
|
||||
PUBLIC memory
|
||||
|
|
|
|||
98
modules/app/application.cppm
Normal file
98
modules/app/application.cppm
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
export module app;
|
||||
import app.system;
|
||||
import memory.reference;
|
||||
import memory.scope;
|
||||
import std;
|
||||
|
||||
namespace lt::app {
|
||||
|
||||
/** The main application class.
|
||||
* Think of this like an aggregate of systems, you register systems through this interface.
|
||||
* Then they'll tick every "application frame".
|
||||
*/
|
||||
export class Application
|
||||
{
|
||||
public:
|
||||
Application(const Application &) = delete;
|
||||
|
||||
Application(Application &&) = delete;
|
||||
|
||||
auto operator=(const Application &) -> Application & = delete;
|
||||
|
||||
auto operator=(Application &&) -> Application & = delete;
|
||||
|
||||
virtual ~Application() = default;
|
||||
|
||||
void game_loop();
|
||||
|
||||
void register_system(memory::Ref<app::ISystem> system);
|
||||
|
||||
void unregister_system(memory::Ref<app::ISystem> system);
|
||||
|
||||
protected:
|
||||
Application() = default;
|
||||
|
||||
private:
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems;
|
||||
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems_to_be_unregistered;
|
||||
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems_to_be_registered;
|
||||
};
|
||||
|
||||
export extern memory::Scope<class Application> create_application();
|
||||
|
||||
} // namespace lt::app
|
||||
|
||||
module :private;
|
||||
namespace lt::app {
|
||||
|
||||
void Application::game_loop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
for (auto &system : m_systems)
|
||||
{
|
||||
const auto &last_tick = system->get_last_tick_result();
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
|
||||
system->tick(
|
||||
TickInfo {
|
||||
.delta_time = now - last_tick.end_time,
|
||||
.budget = std::chrono::milliseconds { 10 },
|
||||
.start_time = now,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for (auto &system : m_systems_to_be_registered)
|
||||
{
|
||||
m_systems.emplace_back(system)->on_register();
|
||||
}
|
||||
|
||||
for (auto &system : m_systems_to_be_unregistered)
|
||||
{
|
||||
m_systems.erase(
|
||||
std::remove(m_systems.begin(), m_systems.end(), system),
|
||||
m_systems.end()
|
||||
);
|
||||
}
|
||||
|
||||
if (m_systems.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::register_system(memory::Ref<app::ISystem> system)
|
||||
{
|
||||
m_systems.emplace_back(std::move(system));
|
||||
}
|
||||
|
||||
void Application::unregister_system(memory::Ref<app::ISystem> system)
|
||||
{
|
||||
m_systems_to_be_unregistered.emplace_back(std::move(system));
|
||||
}
|
||||
|
||||
} // namespace lt::app
|
||||
31
modules/app/entrypoint.cpp
Normal file
31
modules/app/entrypoint.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import memory.scope;
|
||||
import logger;
|
||||
import app;
|
||||
import std;
|
||||
|
||||
/** The ultimate entrypoint. */
|
||||
auto main(int argc, char *argv[]) -> std::int32_t
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ignore = argc;
|
||||
std::ignore = argv;
|
||||
|
||||
auto application = lt::memory::Scope<lt::app::Application> {};
|
||||
application = lt::app::create_application();
|
||||
if (!application)
|
||||
{
|
||||
throw std::runtime_error { "Failed to create application\n" };
|
||||
}
|
||||
|
||||
application->game_loop();
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
lt::log::critical("Terminating due to uncaught exception:");
|
||||
lt::log::critical("\texception.what(): {}", exp.what());
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#include <app/application.hpp>
|
||||
#include <app/system.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
|
||||
namespace lt::app {
|
||||
|
||||
void Application::game_loop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
for (auto &system : m_systems)
|
||||
{
|
||||
const auto &last_tick = system->get_last_tick_result();
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
|
||||
system->tick(
|
||||
TickInfo {
|
||||
.delta_time = now - last_tick.end_time,
|
||||
.budget = std::chrono::milliseconds { 10 },
|
||||
.start_time = now,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for (auto &system : m_systems_to_be_registered)
|
||||
{
|
||||
m_systems.emplace_back(system)->on_register();
|
||||
}
|
||||
|
||||
for (auto &system : m_systems_to_be_unregistered)
|
||||
{
|
||||
m_systems.erase(
|
||||
std::remove(m_systems.begin(), m_systems.end(), system),
|
||||
m_systems.end()
|
||||
);
|
||||
}
|
||||
|
||||
if (m_systems.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::register_system(memory::Ref<app::ISystem> system)
|
||||
{
|
||||
m_systems.emplace_back(std::move(system));
|
||||
}
|
||||
|
||||
void Application::unregister_system(memory::Ref<app::ISystem> system)
|
||||
{
|
||||
m_systems_to_be_unregistered.emplace_back(std::move(system));
|
||||
}
|
||||
|
||||
} // namespace lt::app
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
|
||||
namespace lt::app {
|
||||
|
||||
class ISystem;
|
||||
|
||||
extern memory::Scope<class Application> create_application();
|
||||
|
||||
/** The main application class.
|
||||
* Think of this like an aggregate of systems, you register systems through this interface.
|
||||
* Then they'll tick every "application frame".
|
||||
*/
|
||||
class Application
|
||||
{
|
||||
public:
|
||||
Application(const Application &) = delete;
|
||||
|
||||
Application(Application &&) = delete;
|
||||
|
||||
auto operator=(const Application &) -> Application & = delete;
|
||||
|
||||
auto operator=(Application &&) -> Application & = delete;
|
||||
|
||||
virtual ~Application() = default;
|
||||
|
||||
void game_loop();
|
||||
|
||||
void register_system(memory::Ref<app::ISystem> system);
|
||||
|
||||
void unregister_system(memory::Ref<app::ISystem> system);
|
||||
|
||||
protected:
|
||||
Application() = default;
|
||||
|
||||
private:
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems;
|
||||
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems_to_be_unregistered;
|
||||
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems_to_be_registered;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt::app
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/application.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
|
||||
auto main(int argc, char *argv[]) -> int32_t
|
||||
try
|
||||
{
|
||||
std::ignore = argc;
|
||||
std::ignore = argv;
|
||||
|
||||
auto application = lt::memory::Scope<lt::app::Application> {};
|
||||
application = lt::app::create_application();
|
||||
if (!application)
|
||||
{
|
||||
throw std::runtime_error { "Failed to create application\n" };
|
||||
}
|
||||
|
||||
application->game_loop();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
log_crt("Terminating due to uncaught exception:");
|
||||
log_crt("\texception.what(): {}", exp.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
export module app.system;
|
||||
import logger;
|
||||
import std;
|
||||
|
||||
namespace lt::app {
|
||||
|
||||
/** Information required to tick a system.
|
||||
* @note May be used across an entire application-frame (consisting of multiple systems ticking)
|
||||
*/
|
||||
struct TickInfo
|
||||
export struct TickInfo
|
||||
{
|
||||
using Timepoint_T = std::chrono::time_point<std::chrono::steady_clock>;
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ struct TickInfo
|
|||
};
|
||||
|
||||
/** Information about how a system's tick performed */
|
||||
struct TickResult
|
||||
export struct TickResult
|
||||
{
|
||||
using Timepoint_T = std::chrono::time_point<std::chrono::steady_clock>;
|
||||
|
||||
|
|
@ -46,10 +46,9 @@ struct TickResult
|
|||
Timepoint_T end_time;
|
||||
};
|
||||
|
||||
|
||||
struct SystemDiagnosis
|
||||
export struct SystemDiagnosis
|
||||
{
|
||||
enum class Severity : uint8_t
|
||||
enum class Severity : std::uint8_t
|
||||
{
|
||||
verbose,
|
||||
info,
|
||||
|
|
@ -65,14 +64,14 @@ struct SystemDiagnosis
|
|||
Severity severity;
|
||||
};
|
||||
|
||||
class SystemStats
|
||||
export class SystemStats
|
||||
{
|
||||
public:
|
||||
void push_diagnosis(SystemDiagnosis &&diagnosis)
|
||||
{
|
||||
auto diag = m_diagnosis.emplace_back(std::move(diagnosis));
|
||||
|
||||
log_dbg("message: {}", diag.message);
|
||||
log::debug("message: {}", diag.message);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto empty_diagnosis() const -> bool
|
||||
|
|
@ -84,7 +83,7 @@ private:
|
|||
std::vector<SystemDiagnosis> m_diagnosis;
|
||||
};
|
||||
|
||||
class ISystem
|
||||
export class ISystem
|
||||
{
|
||||
public:
|
||||
ISystem() = default;
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
add_library_module(libasset_baker bakers.cpp)
|
||||
target_link_libraries(libasset_baker PUBLIC assets logger lt_debug tbb)
|
||||
add_test_module(libasset_baker bakers.test.cpp)
|
||||
add_library_module(NAME libasset_baker INTERFACES bakers.cppm)
|
||||
target_link_libraries(libasset_baker PUBLIC assets logger lt_debug)
|
||||
|
||||
add_executable_module(asset_baker entrypoint/baker.cpp)
|
||||
add_executable(asset_baker entrypoint.cpp)
|
||||
target_link_libraries(asset_baker PRIVATE libasset_baker)
|
||||
|
|
|
|||
68
modules/asset_baker/bakers.cppm
Normal file
68
modules/asset_baker/bakers.cppm
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
export module bakers;
|
||||
|
||||
import debug.assertions;
|
||||
import assets.metadata;
|
||||
import assets.shader;
|
||||
import logger;
|
||||
import std;
|
||||
|
||||
export void bake_shader(
|
||||
const std::filesystem::path &in_path,
|
||||
const std::filesystem::path &out_path,
|
||||
lt::assets::ShaderAsset::Type type
|
||||
)
|
||||
{
|
||||
using lt::assets::ShaderAsset;
|
||||
using enum lt::assets::ShaderAsset::Type;
|
||||
|
||||
auto glsl_path = in_path.string();
|
||||
auto spv_path = std::format("{}.spv", glsl_path);
|
||||
lt::log::trace(
|
||||
"Compiling {} shader {} -> {}",
|
||||
type == vertex ? "vertex" : "fragment",
|
||||
glsl_path,
|
||||
spv_path
|
||||
);
|
||||
|
||||
// Don't bother linking to shaderc, just invoke the command with a system call.
|
||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||
std::system(
|
||||
std::format(
|
||||
"glslc --target-env=vulkan1.4 -std=450core -fshader-stage={} {} -o {}",
|
||||
type == vertex ? "vert" : "frag",
|
||||
glsl_path,
|
||||
spv_path
|
||||
)
|
||||
.c_str()
|
||||
);
|
||||
|
||||
auto stream = std::ifstream(spv_path, std::ios::binary);
|
||||
lt::debug::ensure(
|
||||
stream.is_open(),
|
||||
"Failed to open compiled {} shader at: {}",
|
||||
type == vertex ? "vert" : "frag",
|
||||
spv_path
|
||||
);
|
||||
|
||||
stream.seekg(0, std::ios::end);
|
||||
const auto size = stream.tellg();
|
||||
|
||||
auto bytes = std::vector<std::byte>(size);
|
||||
stream.seekg(0, std::ios::beg);
|
||||
stream.read((char *)bytes.data(), size); // NOLINT
|
||||
lt::log::debug("BYTES: {}", bytes.size());
|
||||
stream.close();
|
||||
std::filesystem::remove(spv_path);
|
||||
|
||||
ShaderAsset::pack(
|
||||
out_path,
|
||||
lt::assets::AssetMetadata {
|
||||
.version = lt::assets::current_version,
|
||||
.type = ShaderAsset::asset_type_identifier,
|
||||
},
|
||||
ShaderAsset::Metadata {
|
||||
.type = type,
|
||||
},
|
||||
std::move(bytes)
|
||||
);
|
||||
}
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
#include <asset_baker/bakers.hpp>
|
||||
#include <assets/shader.hpp>
|
||||
import assets.shader;
|
||||
import logger;
|
||||
import bakers;
|
||||
import std;
|
||||
|
||||
auto main(int argc, char *argv[]) -> int32_t
|
||||
|
||||
auto main(int argc, char *argv[]) -> std::int32_t
|
||||
try
|
||||
{
|
||||
if (argc != 2)
|
||||
|
|
@ -30,12 +33,12 @@ try
|
|||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
log_crt("Terminating due to uncaught exception:");
|
||||
log_crt("\texception.what: {}:", exp.what());
|
||||
lt::log::critical("Terminating due to uncaught exception:");
|
||||
lt::log::critical("\texception.what: {}:", exp.what());
|
||||
|
||||
return EXIT_FAILURE;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#include <asset_baker/bakers.hpp>
|
||||
#include <test/test.hpp>
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/shader.hpp>
|
||||
|
||||
inline void bake_shader(
|
||||
const std::filesystem::path &in_path,
|
||||
|
|
@ -13,7 +12,7 @@ inline void bake_shader(
|
|||
|
||||
auto glsl_path = in_path.string();
|
||||
auto spv_path = std::format("{}.spv", glsl_path);
|
||||
log_trc(
|
||||
lt::log::trace(
|
||||
"Compiling {} shader {} -> {}",
|
||||
type == vertex ? "vertex" : "fragment",
|
||||
glsl_path,
|
||||
|
|
@ -33,7 +32,7 @@ inline void bake_shader(
|
|||
);
|
||||
|
||||
auto stream = std::ifstream(spv_path, std::ios::binary);
|
||||
lt::ensure(
|
||||
lt::debug::ensure(
|
||||
stream.is_open(),
|
||||
"Failed to open compiled {} shader at: {}",
|
||||
type == vertex ? "vert" : "frag",
|
||||
|
|
@ -46,7 +45,7 @@ inline void bake_shader(
|
|||
auto bytes = std::vector<std::byte>(size);
|
||||
stream.seekg(0, std::ios::beg);
|
||||
stream.read((char *)bytes.data(), size); // NOLINT
|
||||
log_dbg("BYTES: {}", bytes.size());
|
||||
lt::log::debug("BYTES: {}", bytes.size());
|
||||
stream.close();
|
||||
std::filesystem::remove(spv_path);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
add_library_module(assets shader.cpp)
|
||||
|
||||
add_library_module(NAME assets INTERFACES shader.cppm metadata.cppm)
|
||||
target_link_libraries(assets PUBLIC logger lt_debug)
|
||||
|
||||
add_test_module(assets shader.test.cpp)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
#pragma once
|
||||
export module assets.metadata;
|
||||
import std;
|
||||
|
||||
namespace lt::assets {
|
||||
export namespace lt::assets {
|
||||
|
||||
using Type_T = std::array<const char, 16>;
|
||||
|
||||
using Tag_T = uint8_t;
|
||||
using Tag_T = std::uint8_t;
|
||||
|
||||
using Version = uint8_t;
|
||||
using Version = std::uint8_t;
|
||||
|
||||
using Blob = std::vector<std::byte>;
|
||||
|
||||
constexpr auto current_version = Version { 1u };
|
||||
|
||||
enum class CompressionType : uint8_t
|
||||
enum class CompressionType : std::uint8_t
|
||||
{
|
||||
none,
|
||||
lz4,
|
||||
|
|
@ -30,13 +31,13 @@ struct BlobMetadata
|
|||
{
|
||||
Tag_T tag;
|
||||
|
||||
size_t offset;
|
||||
std::size_t offset;
|
||||
|
||||
CompressionType compression_type;
|
||||
|
||||
size_t compressed_size;
|
||||
std::size_t compressed_size;
|
||||
|
||||
size_t uncompressed_size;
|
||||
std::size_t uncompressed_size;
|
||||
};
|
||||
|
||||
} // namespace lt::assets
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// TO BE DOOO
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/metadata.hpp>
|
||||
|
||||
namespace lt::assets {
|
||||
|
||||
class ShaderAsset
|
||||
{
|
||||
public:
|
||||
static constexpr auto asset_type_identifier = Type_T { "SHADER_________" };
|
||||
|
||||
enum class BlobTag : Tag_T
|
||||
{
|
||||
code,
|
||||
};
|
||||
|
||||
enum class Type : uint8_t
|
||||
{
|
||||
vertex,
|
||||
fragment,
|
||||
geometry,
|
||||
compute,
|
||||
};
|
||||
|
||||
struct Metadata
|
||||
{
|
||||
Type type;
|
||||
};
|
||||
|
||||
static void pack(
|
||||
const std::filesystem::path &destination,
|
||||
AssetMetadata asset_metadata,
|
||||
Metadata metadata,
|
||||
Blob code_blob
|
||||
);
|
||||
|
||||
ShaderAsset(const std::filesystem::path &path);
|
||||
|
||||
void unpack_to(BlobTag tag, std::span<std::byte> destination) const;
|
||||
|
||||
[[nodiscard]] auto unpack(BlobTag tag) const -> Blob;
|
||||
|
||||
[[nodiscard]] auto get_asset_metadata() const -> const AssetMetadata &
|
||||
{
|
||||
return m_asset_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_metadata() const -> const Metadata &
|
||||
{
|
||||
return m_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_blob_metadata(BlobTag tag) const -> const BlobMetadata &
|
||||
{
|
||||
ensure(
|
||||
tag == BlobTag::code,
|
||||
"Invalid blob tag for shader asset: {}",
|
||||
std::to_underlying(tag)
|
||||
);
|
||||
|
||||
return m_code_blob_metadata;
|
||||
}
|
||||
|
||||
private:
|
||||
AssetMetadata m_asset_metadata {};
|
||||
|
||||
Metadata m_metadata {};
|
||||
|
||||
BlobMetadata m_code_blob_metadata {};
|
||||
|
||||
mutable std::ifstream m_stream;
|
||||
};
|
||||
|
||||
} // namespace lt::assets
|
||||
|
|
@ -1,4 +1,80 @@
|
|||
#include <assets/shader.hpp>
|
||||
export module assets.shader;
|
||||
import assets.metadata;
|
||||
import debug.assertions;
|
||||
|
||||
import std;
|
||||
|
||||
export namespace lt::assets {
|
||||
|
||||
class ShaderAsset
|
||||
{
|
||||
public:
|
||||
static constexpr auto asset_type_identifier = Type_T { "SHADER_________" };
|
||||
|
||||
enum class BlobTag : Tag_T
|
||||
{
|
||||
code,
|
||||
};
|
||||
|
||||
enum class Type : std::uint8_t
|
||||
{
|
||||
vertex,
|
||||
fragment,
|
||||
geometry,
|
||||
compute,
|
||||
};
|
||||
|
||||
struct Metadata
|
||||
{
|
||||
Type type;
|
||||
};
|
||||
|
||||
static void pack(
|
||||
const std::filesystem::path &destination,
|
||||
AssetMetadata asset_metadata,
|
||||
Metadata metadata,
|
||||
Blob code_blob
|
||||
);
|
||||
|
||||
ShaderAsset(const std::filesystem::path &path);
|
||||
|
||||
void unpack_to(BlobTag tag, std::span<std::byte> destination) const;
|
||||
|
||||
[[nodiscard]] auto unpack(BlobTag tag) const -> Blob;
|
||||
|
||||
[[nodiscard]] auto get_asset_metadata() const -> const AssetMetadata &
|
||||
{
|
||||
return m_asset_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_metadata() const -> const Metadata &
|
||||
{
|
||||
return m_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_blob_metadata(BlobTag tag) const -> const BlobMetadata &
|
||||
{
|
||||
debug::ensure(
|
||||
tag == BlobTag::code,
|
||||
"Invalid blob tag for shader asset: {}",
|
||||
std::to_underlying(tag)
|
||||
);
|
||||
|
||||
return m_code_blob_metadata;
|
||||
}
|
||||
|
||||
private:
|
||||
AssetMetadata m_asset_metadata {};
|
||||
|
||||
Metadata m_metadata {};
|
||||
|
||||
BlobMetadata m_code_blob_metadata {};
|
||||
|
||||
mutable std::ifstream m_stream;
|
||||
};
|
||||
|
||||
} // namespace lt::assets
|
||||
|
||||
|
||||
namespace lt::assets {
|
||||
|
||||
|
|
@ -14,14 +90,14 @@ constexpr auto total_metadata_size = //
|
|||
|
||||
ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
||||
{
|
||||
ensure(m_stream.is_open(), "Failed to open shader asset at: {}", path.string());
|
||||
debug::ensure(m_stream.is_open(), "Failed to open shader asset at: {}", path.string());
|
||||
const auto read = [this](auto &field) {
|
||||
m_stream.read(std::bit_cast<char *>(&field), sizeof(field));
|
||||
};
|
||||
|
||||
m_stream.seekg(0, std::ifstream::end);
|
||||
const auto file_size = static_cast<size_t>(m_stream.tellg());
|
||||
ensure(
|
||||
const auto file_size = static_cast<std::size_t>(m_stream.tellg());
|
||||
debug::ensure(
|
||||
file_size > total_metadata_size,
|
||||
"Failed to open shader asset at: {}, file smaller than metadata: {} < {}",
|
||||
path.string(),
|
||||
|
|
@ -39,7 +115,7 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
read(m_code_blob_metadata.compressed_size);
|
||||
read(m_code_blob_metadata.uncompressed_size);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
m_asset_metadata.type == asset_type_identifier,
|
||||
"Failed to open shader asset at: {}, incorrect asset type: {} != {}",
|
||||
path.string(),
|
||||
|
|
@ -47,7 +123,7 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
asset_type_identifier
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
m_asset_metadata.version == current_version,
|
||||
"Failed to open shader asset at: {}, version mismatch: {} != {}",
|
||||
path.string(),
|
||||
|
|
@ -55,21 +131,21 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
current_version
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
std::to_underlying(m_metadata.type) <= std::to_underlying(Type::compute),
|
||||
"Failed to open shader asset at: {}, invalid shader type: {}",
|
||||
path.string(),
|
||||
std::to_underlying(m_metadata.type)
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
m_code_blob_metadata.tag == std::to_underlying(BlobTag::code),
|
||||
"Failed to open shader asset at: {}, invalid blob tag: {}",
|
||||
path.string(),
|
||||
m_code_blob_metadata.tag
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
m_code_blob_metadata.offset + m_code_blob_metadata.compressed_size <= file_size,
|
||||
"Failed to open shader asset at: {}, file smaller than blob: {} > {} + {}",
|
||||
path.string(),
|
||||
|
|
@ -99,7 +175,7 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
.uncompressed_size = code_blob.size(),
|
||||
};
|
||||
|
||||
ensure(stream.is_open(), "Failed to pack shader asset to {}", destination.string());
|
||||
debug::ensure(stream.is_open(), "Failed to pack shader asset to {}", destination.string());
|
||||
const auto write = [&stream](auto &field) {
|
||||
stream.write(std::bit_cast<char *>(&field), sizeof(field));
|
||||
};
|
||||
|
|
@ -116,14 +192,18 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
|
||||
void ShaderAsset::unpack_to(BlobTag tag, std::span<std::byte> destination) const
|
||||
{
|
||||
ensure(tag == BlobTag::code, "Invalid blob tag for shader asset: {}", std::to_underlying(tag));
|
||||
debug::ensure(
|
||||
tag == BlobTag::code,
|
||||
"Invalid blob tag for shader asset: {}",
|
||||
std::to_underlying(tag)
|
||||
);
|
||||
|
||||
ensure(
|
||||
debug::ensure(
|
||||
destination.size() >= m_code_blob_metadata.uncompressed_size,
|
||||
"Failed to unpack shader blob {} to destination ({}) of size {} since it's smaller "
|
||||
"than the blobl's uncompressed size: {}",
|
||||
std::to_underlying(tag),
|
||||
std::bit_cast<size_t>(destination.data()),
|
||||
std::bit_cast<std::size_t>(destination.data()),
|
||||
destination.size(),
|
||||
m_code_blob_metadata.uncompressed_size
|
||||
);
|
||||
|
|
@ -137,7 +217,11 @@ void ShaderAsset::unpack_to(BlobTag tag, std::span<std::byte> destination) const
|
|||
|
||||
[[nodiscard]] auto ShaderAsset::unpack(BlobTag tag) const -> Blob
|
||||
{
|
||||
ensure(tag == BlobTag::code, "Invalid blob tag for shader asset: {}", std::to_underlying(tag));
|
||||
debug::ensure(
|
||||
tag == BlobTag::code,
|
||||
"Invalid blob tag for shader asset: {}",
|
||||
std::to_underlying(tag)
|
||||
);
|
||||
|
||||
auto blob = Blob(m_code_blob_metadata.uncompressed_size);
|
||||
unpack_to(tag, blob);
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
#include <assets/shader.hpp>
|
||||
#include <ranges>
|
||||
#include <test/test.hpp>
|
||||
import assets.metadata;
|
||||
import assets.shader;
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import std;
|
||||
|
||||
using ::lt::assets::AssetMetadata;
|
||||
using ::lt::assets::BlobMetadata;
|
||||
|
|
@ -10,6 +12,7 @@ using ::lt::test::expect_eq;
|
|||
using ::lt::test::expect_throw;
|
||||
using ::lt::test::expect_true;
|
||||
using ::lt::test::Suite;
|
||||
using ::lt::test::operator""_suite;
|
||||
|
||||
const auto test_data_path = std::filesystem::path { "./data/test_assets" };
|
||||
const auto tmp_path = std::filesystem::path { "/tmp/lt_assets_tests/" };
|
||||
|
|
@ -70,7 +73,7 @@ Suite packing = "shader_pack"_suite = [] {
|
|||
expect_true(stream.is_open());
|
||||
|
||||
stream.seekg(0, std::ios::end);
|
||||
const auto file_size = static_cast<size_t>(stream.tellg());
|
||||
const auto file_size = static_cast<std::size_t>(stream.tellg());
|
||||
expect_eq(file_size, expected_size);
|
||||
stream.close();
|
||||
|
||||
|
|
@ -1 +1 @@
|
|||
add_library_module(bitwise)
|
||||
add_library_module(NAME bitwise INTERFACES operations.cppm)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
export module bitwise;
|
||||
import std;
|
||||
|
||||
namespace lt::bitwise {
|
||||
|
||||
/* bit-wise */
|
||||
constexpr auto bit(uint32_t x) -> uint32_t
|
||||
constexpr auto bit(std::uint32_t x) -> std::uint32_t
|
||||
{
|
||||
return 1u << x;
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
add_library_module(camera camera.cpp scene.cpp)
|
||||
add_library_module(NAME camera INTERFACES components.cppm)
|
||||
|
||||
target_link_libraries(camera PUBLIC math)
|
||||
|
|
|
|||
21
modules/camera/components.cppm
Normal file
21
modules/camera/components.cppm
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
export module camera.components;
|
||||
import math.vec4;
|
||||
|
||||
namespace lt::camera::components {
|
||||
|
||||
export struct PerspectiveCamera
|
||||
{
|
||||
float vertical_fov {};
|
||||
|
||||
float near_plane {};
|
||||
|
||||
float far_plane {};
|
||||
|
||||
float aspect_ratio {};
|
||||
|
||||
math::vec4 background_color;
|
||||
|
||||
bool is_primary {};
|
||||
};
|
||||
|
||||
} // namespace lt::camera::components
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#include <camera/camera.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#include <camera/camera.hpp>
|
||||
#include <camera/component.hpp>
|
||||
#include <math/algebra.hpp>
|
||||
#include <math/trig.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
SceneCamera::SceneCamera()
|
||||
: m_orthographic_specification { .size = 1000.0f, .near_plane = -1.0f, .far_plane = 10000.0f }
|
||||
, m_perspective_specification { .vertical_fov = math::radians(45.0f),
|
||||
.near_plane = 0.01f,
|
||||
.far_plane = 10000.0f }
|
||||
, m_aspect_ratio(16.0f / 9.0f)
|
||||
|
||||
{
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_viewport_size(unsigned int width, unsigned int height)
|
||||
{
|
||||
m_aspect_ratio = static_cast<float>(width) / static_cast<float>(height);
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_projection_type(ProjectionType projection_type)
|
||||
{
|
||||
m_projection_type = projection_type;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_orthographic_size(float size)
|
||||
{
|
||||
m_orthographic_specification.size = size;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_orthographic_far_plane(float far_plane)
|
||||
{
|
||||
m_orthographic_specification.far_plane = far_plane;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_orthographic_near_plane(float near_plane)
|
||||
{
|
||||
m_orthographic_specification.near_plane = near_plane;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_perspective_vertical_fov(float vertical_fov)
|
||||
{
|
||||
m_perspective_specification.vertical_fov = vertical_fov;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_perspective_far_plane(float far_plane)
|
||||
{
|
||||
m_perspective_specification.far_plane = far_plane;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_perspective_near_plane(float near_plane)
|
||||
{
|
||||
m_perspective_specification.near_plane = near_plane;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::calculate_projection()
|
||||
{
|
||||
// TODO(Light): implement ortho perspective
|
||||
if (m_projection_type == ProjectionType::Orthographic)
|
||||
{
|
||||
// throw std::runtime_error { "ortho perspective not supported yet" };
|
||||
}
|
||||
|
||||
// defaults to perspective for now...
|
||||
m_projection = math::perspective(
|
||||
m_perspective_specification.vertical_fov,
|
||||
m_aspect_ratio,
|
||||
m_perspective_specification.near_plane,
|
||||
m_perspective_specification.far_plane
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace lt
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <math/mat4.hpp>
|
||||
#include <math/vec4.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
class Camera
|
||||
{
|
||||
public:
|
||||
Camera() = default;
|
||||
|
||||
[[nodiscard]] auto get_projection() const -> const math::mat4 &
|
||||
{
|
||||
return m_projection;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_background_color() const -> const math::vec4 &
|
||||
{
|
||||
return m_background_color;
|
||||
}
|
||||
|
||||
void set_background_color(const math::vec4 &color)
|
||||
{
|
||||
m_background_color = color;
|
||||
}
|
||||
|
||||
protected:
|
||||
math::mat4 m_projection;
|
||||
|
||||
private:
|
||||
math::vec4 m_background_color = math::vec4(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
};
|
||||
|
||||
} // namespace lt
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <camera/scene.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
struct CameraComponent
|
||||
{
|
||||
CameraComponent() = default;
|
||||
|
||||
CameraComponent(const CameraComponent &) = default;
|
||||
|
||||
CameraComponent(SceneCamera _camera, bool _isPrimary = false)
|
||||
: camera(_camera)
|
||||
, isPrimary(_isPrimary)
|
||||
{
|
||||
}
|
||||
|
||||
operator SceneCamera() const
|
||||
{
|
||||
return camera;
|
||||
}
|
||||
|
||||
SceneCamera camera;
|
||||
|
||||
bool isPrimary {};
|
||||
};
|
||||
|
||||
} // namespace lt
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <camera/camera.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
class SceneCamera: public Camera
|
||||
{
|
||||
public:
|
||||
enum class ProjectionType
|
||||
{
|
||||
Orthographic = 0,
|
||||
Perspetcive = 1
|
||||
};
|
||||
|
||||
struct OrthographicSpecification
|
||||
{
|
||||
float size;
|
||||
|
||||
float near_plane;
|
||||
|
||||
float far_plane;
|
||||
};
|
||||
|
||||
struct PerspectiveSpecification
|
||||
{
|
||||
float vertical_fov;
|
||||
|
||||
float near_plane;
|
||||
|
||||
float far_plane;
|
||||
};
|
||||
|
||||
SceneCamera();
|
||||
|
||||
void set_viewport_size(unsigned int width, unsigned int height);
|
||||
|
||||
void set_projection_type(ProjectionType projection_type);
|
||||
|
||||
void set_orthographic_size(float size);
|
||||
|
||||
void set_orthographic_far_plane(float far_plane);
|
||||
|
||||
void set_orthographic_near_plane(float near_plane);
|
||||
|
||||
void set_perspective_vertical_fov(float vertical_fov);
|
||||
|
||||
void set_perspective_far_plane(float far_plane);
|
||||
|
||||
void set_perspective_near_plane(float near_plane);
|
||||
|
||||
[[nodiscard]] auto get_orthographic_size() const -> float
|
||||
{
|
||||
return m_orthographic_specification.size;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_orthographic_far_plane() const -> float
|
||||
{
|
||||
return m_orthographic_specification.far_plane;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_orthographic_near_plane() const -> float
|
||||
{
|
||||
return m_orthographic_specification.near_plane;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_perspective_vertical_fov() const -> float
|
||||
{
|
||||
return m_perspective_specification.vertical_fov;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_perspective_far_plane() const -> float
|
||||
{
|
||||
return m_perspective_specification.far_plane;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_perspective_near_plane() const -> float
|
||||
{
|
||||
return m_perspective_specification.near_plane;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_projection_type() const -> ProjectionType
|
||||
{
|
||||
return m_projection_type;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
OrthographicSpecification m_orthographic_specification;
|
||||
|
||||
PerspectiveSpecification m_perspective_specification;
|
||||
|
||||
float m_aspect_ratio;
|
||||
|
||||
ProjectionType m_projection_type { ProjectionType::Orthographic };
|
||||
|
||||
void calculate_projection();
|
||||
};
|
||||
|
||||
} // namespace lt
|
||||
|
|
@ -1,4 +1,2 @@
|
|||
add_library_module(lt_debug instrumentor.cpp)
|
||||
add_library_module(NAME lt_debug INTERFACES instrumentor.cppm assertions.cppm)
|
||||
target_link_libraries(lt_debug PUBLIC logger)
|
||||
target_precompile_headers(lt_debug PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/private/pch.hpp)
|
||||
|
|
|
|||
47
modules/debug/assertions.cppm
Normal file
47
modules/debug/assertions.cppm
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
export module debug.assertions;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt::debug {
|
||||
|
||||
///////////////////////////////////////
|
||||
// ----------* INTERFACE *--------- //
|
||||
/////////////////////////////////////
|
||||
export template<typename Expression_T, typename... Args_T>
|
||||
struct ensure
|
||||
{
|
||||
ensure(
|
||||
const Expression_T &expression,
|
||||
std::format_string<Args_T...> fmt,
|
||||
Args_T &&...args,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
);
|
||||
};
|
||||
|
||||
export template<typename Expression_T, typename... Args_T>
|
||||
ensure(Expression_T, std::format_string<Args_T...>, Args_T &&...)
|
||||
-> ensure<Expression_T, Args_T...>;
|
||||
|
||||
///////////////////////////////////////
|
||||
// * IMPLEMENTATION -- TEMPLATES * //
|
||||
/////////////////////////////////////
|
||||
template<typename Expression_T, typename... Args_T>
|
||||
ensure<Expression_T, Args_T...>::ensure(
|
||||
const Expression_T &expression,
|
||||
std::format_string<Args_T...> fmt,
|
||||
Args_T &&...args,
|
||||
const std::source_location &location
|
||||
)
|
||||
{
|
||||
if (!static_cast<bool>(expression))
|
||||
{
|
||||
throw std::runtime_error { std::format(
|
||||
"exception: {}\nlocation: {}:{}",
|
||||
std::format(fmt, std::forward<Args_T>(args)...),
|
||||
location.file_name(),
|
||||
location.line()
|
||||
) };
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lt::debug
|
||||
145
modules/debug/instrumentor.cppm
Normal file
145
modules/debug/instrumentor.cppm
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
export module debug.instrumentor;
|
||||
|
||||
import std;
|
||||
import logger;
|
||||
|
||||
namespace lt::debug {
|
||||
|
||||
struct ScopeProfileResult
|
||||
{
|
||||
std::string name;
|
||||
long long start, duration;
|
||||
std::uint32_t threadID;
|
||||
};
|
||||
|
||||
class Instrumentor
|
||||
{
|
||||
public:
|
||||
static auto instance() -> Instrumentor &
|
||||
{
|
||||
static auto instance = Instrumentor {};
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void begin_session(const std::string &outputPath)
|
||||
{
|
||||
instance().begin_session_impl(outputPath);
|
||||
}
|
||||
static void end_session()
|
||||
{
|
||||
instance().end_session_impl();
|
||||
}
|
||||
|
||||
static void submit_scope_profile(const ScopeProfileResult &profileResult)
|
||||
{
|
||||
instance().submit_scope_profile_impl(profileResult);
|
||||
}
|
||||
|
||||
private:
|
||||
std::ofstream m_output_file_stream;
|
||||
|
||||
unsigned int m_current_session_count { 0u };
|
||||
|
||||
Instrumentor() = default;
|
||||
|
||||
void begin_session_impl(const std::string &outputPath);
|
||||
|
||||
void end_session_impl();
|
||||
|
||||
void submit_scope_profile_impl(const ScopeProfileResult &profileResult);
|
||||
};
|
||||
|
||||
class InstrumentorTimer
|
||||
{
|
||||
public:
|
||||
InstrumentorTimer(const std::string &scopeName);
|
||||
|
||||
~InstrumentorTimer();
|
||||
|
||||
private:
|
||||
ScopeProfileResult m_result;
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_start;
|
||||
};
|
||||
|
||||
} // namespace lt::debug
|
||||
|
||||
/* scope */
|
||||
#define lt_profile_scope(name) lt_profile_scope_no_redifinition(name, __LINE__)
|
||||
#define lt_profile_scope_no_redifinition(name, line) lt_profile_scope_no_redifinition2(name, line)
|
||||
#define lt_profile_scope_no_redifinition2(name, line) InstrumentorTimer timer##line(name)
|
||||
|
||||
/* function */
|
||||
#define LT_PROFILE_FUNCTION lt_profile_scope(__FUNCSIG__)
|
||||
|
||||
/* session */
|
||||
#define lt_profile_begin_session(outputPath) ::lt::Instrumentor::begin_session(outputPath)
|
||||
#define lt_profile_end_session() ::lt::Instrumentor::end_session()
|
||||
|
||||
module :private;
|
||||
using namespace lt::debug;
|
||||
|
||||
void Instrumentor::begin_session_impl(const std::string &outputPath)
|
||||
{
|
||||
std::filesystem::create_directory(outputPath.substr(0, outputPath.find_last_of('/') + 1));
|
||||
|
||||
m_output_file_stream.open(outputPath);
|
||||
m_output_file_stream << "{\"traceEvents\":[";
|
||||
}
|
||||
|
||||
void Instrumentor::end_session_impl()
|
||||
{
|
||||
if (m_current_session_count == 0u)
|
||||
{
|
||||
log::warn("0 profiling for the ended session");
|
||||
}
|
||||
|
||||
m_current_session_count = 0u;
|
||||
|
||||
m_output_file_stream << "]}";
|
||||
m_output_file_stream.flush();
|
||||
m_output_file_stream.close();
|
||||
}
|
||||
|
||||
void Instrumentor::submit_scope_profile_impl(const ScopeProfileResult &profileResult)
|
||||
{
|
||||
if (m_current_session_count++ == 0u)
|
||||
{
|
||||
m_output_file_stream << "{";
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output_file_stream << ",{";
|
||||
}
|
||||
|
||||
m_output_file_stream << R"("name":")" << profileResult.name << "\",";
|
||||
m_output_file_stream << R"("cat": "scope",)";
|
||||
m_output_file_stream << R"("ph": "X",)";
|
||||
m_output_file_stream << "\"ts\":" << profileResult.start << ",";
|
||||
m_output_file_stream << "\"dur\":" << profileResult.duration << ",";
|
||||
m_output_file_stream << "\"pid\":0,";
|
||||
m_output_file_stream << "\"tid\":" << profileResult.threadID << "";
|
||||
m_output_file_stream << "}";
|
||||
}
|
||||
|
||||
InstrumentorTimer::InstrumentorTimer(const std::string &scopeName)
|
||||
: m_result({ .name = scopeName, .start = 0, .duration = 0, .threadID = 0 })
|
||||
, m_start(std::chrono::steady_clock::now())
|
||||
{
|
||||
}
|
||||
|
||||
InstrumentorTimer::~InstrumentorTimer()
|
||||
{
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
|
||||
m_result.start = std::chrono::time_point_cast<std::chrono::microseconds>(m_start)
|
||||
.time_since_epoch()
|
||||
.count();
|
||||
|
||||
m_result.duration = std::chrono::time_point_cast<std::chrono::microseconds>(end)
|
||||
.time_since_epoch()
|
||||
.count()
|
||||
- m_result.start;
|
||||
|
||||
Instrumentor::submit_scope_profile(m_result);
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <lt_debug/instrumentor.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
void Instrumentor::begin_session_impl(const std::string &outputPath)
|
||||
{
|
||||
std::filesystem::create_directory(outputPath.substr(0, outputPath.find_last_of('/') + 1));
|
||||
|
||||
m_output_file_stream.open(outputPath);
|
||||
m_output_file_stream << "{\"traceEvents\":[";
|
||||
}
|
||||
|
||||
void Instrumentor::end_session_impl()
|
||||
{
|
||||
if (m_current_session_count == 0u)
|
||||
{
|
||||
log_wrn("0 profiling for the ended session");
|
||||
}
|
||||
|
||||
m_current_session_count = 0u;
|
||||
|
||||
m_output_file_stream << "]}";
|
||||
m_output_file_stream.flush();
|
||||
m_output_file_stream.close();
|
||||
}
|
||||
|
||||
void Instrumentor::submit_scope_profile_impl(const ScopeProfileResult &profileResult)
|
||||
{
|
||||
if (m_current_session_count++ == 0u)
|
||||
{
|
||||
m_output_file_stream << "{";
|
||||
}
|
||||
else
|
||||
{
|
||||
m_output_file_stream << ",{";
|
||||
}
|
||||
|
||||
m_output_file_stream << R"("name":")" << profileResult.name << "\",";
|
||||
m_output_file_stream << R"("cat": "scope",)";
|
||||
m_output_file_stream << R"("ph": "X",)";
|
||||
m_output_file_stream << "\"ts\":" << profileResult.start << ",";
|
||||
m_output_file_stream << "\"dur\":" << profileResult.duration << ",";
|
||||
m_output_file_stream << "\"pid\":0,";
|
||||
m_output_file_stream << "\"tid\":" << profileResult.threadID << "";
|
||||
m_output_file_stream << "}";
|
||||
}
|
||||
|
||||
InstrumentorTimer::InstrumentorTimer(const std::string &scopeName)
|
||||
: m_result({ .name = scopeName, .start = 0, .duration = 0, .threadID = 0 })
|
||||
, m_start(std::chrono::steady_clock::now())
|
||||
{
|
||||
}
|
||||
|
||||
InstrumentorTimer::~InstrumentorTimer()
|
||||
{
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
|
||||
m_result.start = std::chrono::time_point_cast<std::chrono::microseconds>(m_start)
|
||||
.time_since_epoch()
|
||||
.count();
|
||||
|
||||
m_result.duration = std::chrono::time_point_cast<std::chrono::microseconds>(end)
|
||||
.time_since_epoch()
|
||||
.count()
|
||||
- m_result.start;
|
||||
|
||||
Instrumentor::submit_scope_profile(m_result);
|
||||
}
|
||||
|
||||
} // namespace lt
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <lt_debug/assertions.hpp>
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <logger/logger.hpp>
|
||||
#include <source_location>
|
||||
|
||||
namespace lt {
|
||||
|
||||
template<typename Expression_T, typename... Args_T>
|
||||
struct ensure
|
||||
{
|
||||
ensure(
|
||||
const Expression_T &expression,
|
||||
std::format_string<Args_T...> fmt,
|
||||
Args_T &&...args,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
)
|
||||
{
|
||||
if (!static_cast<bool>(expression))
|
||||
{
|
||||
throw std::runtime_error { std::format(
|
||||
"exception: {}\nlocation: {}:{}",
|
||||
std::format(fmt, std::forward<Args_T>(args)...),
|
||||
location.file_name(),
|
||||
location.line()
|
||||
) };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Expression_T, typename... Args_T>
|
||||
ensure(Expression_T, std::format_string<Args_T...>, Args_T &&...)
|
||||
-> ensure<Expression_T, Args_T...>;
|
||||
|
||||
} // namespace lt
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
namespace lt {
|
||||
|
||||
struct ScopeProfileResult
|
||||
{
|
||||
std::string name;
|
||||
long long start, duration;
|
||||
uint32_t threadID;
|
||||
};
|
||||
|
||||
class Instrumentor
|
||||
{
|
||||
public:
|
||||
static auto instance() -> Instrumentor &
|
||||
{
|
||||
static auto instance = Instrumentor {};
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void begin_session(const std::string &outputPath)
|
||||
{
|
||||
instance().begin_session_impl(outputPath);
|
||||
}
|
||||
static void end_session()
|
||||
{
|
||||
instance().end_session_impl();
|
||||
}
|
||||
|
||||
static void submit_scope_profile(const ScopeProfileResult &profileResult)
|
||||
{
|
||||
instance().submit_scope_profile_impl(profileResult);
|
||||
}
|
||||
|
||||
private:
|
||||
std::ofstream m_output_file_stream;
|
||||
|
||||
unsigned int m_current_session_count { 0u };
|
||||
|
||||
Instrumentor() = default;
|
||||
|
||||
void begin_session_impl(const std::string &outputPath);
|
||||
|
||||
void end_session_impl();
|
||||
|
||||
void submit_scope_profile_impl(const ScopeProfileResult &profileResult);
|
||||
};
|
||||
|
||||
class InstrumentorTimer
|
||||
{
|
||||
public:
|
||||
InstrumentorTimer(const std::string &scopeName);
|
||||
|
||||
~InstrumentorTimer();
|
||||
|
||||
private:
|
||||
ScopeProfileResult m_result;
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_start;
|
||||
};
|
||||
|
||||
} // namespace lt
|
||||
|
||||
/* scope */
|
||||
#define lt_profile_scope(name) lt_profile_scope_no_redifinition(name, __LINE__)
|
||||
#define lt_profile_scope_no_redifinition(name, line) lt_profile_scope_no_redifinition2(name, line)
|
||||
#define lt_profile_scope_no_redifinition2(name, line) InstrumentorTimer timer##line(name)
|
||||
|
||||
/* function */
|
||||
#define LT_PROFILE_FUNCTION lt_profile_scope(__FUNCSIG__)
|
||||
|
||||
/* session */
|
||||
#define lt_profile_begin_session(outputPath) ::lt::Instrumentor::begin_session(outputPath)
|
||||
#define lt_profile_end_session() ::lt::Instrumentor::end_session()
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
add_library_module(ecs sparse_set.cpp)
|
||||
add_library_module(NAME ecs INTERFACES sparse_set.cppm registry.cppm
|
||||
entity.cppm)
|
||||
target_link_libraries(ecs PUBLIC logger lt_debug memory)
|
||||
|
||||
add_test_module(ecs sparse_set.test.cpp registry.test.cpp)
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
export module ecs.entity;
|
||||
import debug.assertions;
|
||||
import memory.reference;
|
||||
import ecs.registry;
|
||||
import std;
|
||||
|
||||
namespace lt::ecs {
|
||||
|
||||
/** High-level entity convenience wrapper */
|
||||
class Entity
|
||||
export class Entity
|
||||
{
|
||||
public:
|
||||
Entity(memory::Ref<Registry> registry, EntityId identifier)
|
||||
: m_registry(std::move(registry))
|
||||
, m_identifier(identifier)
|
||||
{
|
||||
ensure(m_registry, "Failed to create Entity ({}): null registry", m_identifier);
|
||||
debug::ensure(m_registry, "Failed to create Entity ({}): null registry", m_identifier);
|
||||
}
|
||||
|
||||
template<typename Component_T>
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <ecs/sparse_set.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
export module ecs.registry;
|
||||
import debug.assertions;
|
||||
import ecs.sparse_set;
|
||||
import memory.scope;
|
||||
import std;
|
||||
|
||||
namespace lt::ecs {
|
||||
|
||||
using EntityId = uint32_t;
|
||||
export using EntityId = std::uint32_t;
|
||||
|
||||
constexpr auto null_entity = std::numeric_limits<EntityId>::max();
|
||||
export constexpr auto null_entity = std::numeric_limits<EntityId>::max();
|
||||
|
||||
/** A registry of components, the heart of an ECS architecture.
|
||||
*
|
||||
|
|
@ -22,7 +23,7 @@ constexpr auto null_entity = std::numeric_limits<EntityId>::max();
|
|||
* @ref https://github.com/skypjack/entt
|
||||
* @ref https://github.com/SanderMertens/flecs
|
||||
*/
|
||||
class Registry
|
||||
export class Registry
|
||||
{
|
||||
public:
|
||||
using UnderlyingSparseSet_T = TypeErasedSparseSet<EntityId>;
|
||||
|
|
@ -189,25 +190,25 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] auto get_entity_count() const -> size_t
|
||||
[[nodiscard]] auto get_entity_count() const -> std::size_t
|
||||
{
|
||||
return static_cast<size_t>(m_entity_count);
|
||||
return static_cast<std::size_t>(m_entity_count);
|
||||
}
|
||||
|
||||
private:
|
||||
using TypeId = size_t;
|
||||
using TypeId = std::size_t;
|
||||
|
||||
static consteval auto hash_cstr(const char *str) -> TypeId
|
||||
{
|
||||
constexpr auto fnv_offset_basis = size_t { 14695981039346656037ull };
|
||||
constexpr auto fnv_prime = size_t { 1099511628211ull };
|
||||
constexpr auto fnv_offset_basis = std::size_t { 14695981039346656037ull };
|
||||
constexpr auto fnv_prime = std::size_t { 1099511628211ull };
|
||||
|
||||
auto hash = fnv_offset_basis;
|
||||
|
||||
for (const auto &ch : std::string_view { str })
|
||||
{
|
||||
hash *= fnv_prime;
|
||||
hash ^= static_cast<uint8_t>(ch);
|
||||
hash ^= static_cast<std::uint8_t>(ch);
|
||||
}
|
||||
|
||||
return hash;
|
||||
|
|
@ -241,7 +242,7 @@ private:
|
|||
|
||||
auto *base_set = m_sparsed_sets[type_id].get();
|
||||
auto *derived_set = dynamic_cast<SparseSet<T, EntityId> *>(base_set);
|
||||
ensure(derived_set, "Failed to downcast to derived set");
|
||||
debug::ensure(derived_set, "Failed to downcast to derived set");
|
||||
|
||||
return *derived_set;
|
||||
}
|
||||
|
|
@ -1,19 +1,17 @@
|
|||
#include <ecs/registry.hpp>
|
||||
#include <ranges>
|
||||
#include <test/expects.hpp>
|
||||
#include <test/test.hpp>
|
||||
import ecs.registry;
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import std;
|
||||
|
||||
using lt::test::Case;
|
||||
using lt::test::expect_unreachable;
|
||||
using lt::test::Suite;
|
||||
|
||||
using lt::test::expect_eq;
|
||||
|
||||
using lt::test::expect_false;
|
||||
using lt::test::expect_true;
|
||||
|
||||
using lt::ecs::EntityId;
|
||||
using lt::ecs::Registry;
|
||||
using ::lt::ecs::EntityId;
|
||||
using ::lt::ecs::Registry;
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::expect_eq;
|
||||
using ::lt::test::expect_false;
|
||||
using ::lt::test::expect_true;
|
||||
using ::lt::test::expect_unreachable;
|
||||
using ::lt::test::Suite;
|
||||
using ::lt::test::operator""_suite;
|
||||
|
||||
struct Component
|
||||
{
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
#pragma once
|
||||
export module ecs.sparse_set;
|
||||
import debug.assertions;
|
||||
import std;
|
||||
|
||||
namespace lt::ecs {
|
||||
|
||||
/**
|
||||
*
|
||||
* @ref https://programmingpraxis.com/2012/03/09/sparse-sets/
|
||||
*/
|
||||
template<typename Identifier_T = uint32_t>
|
||||
export template<typename Identifier_T = std::uint32_t>
|
||||
class TypeErasedSparseSet
|
||||
{
|
||||
public:
|
||||
|
|
@ -25,19 +26,19 @@ public:
|
|||
virtual void remove(Identifier_T identifier) = 0;
|
||||
};
|
||||
|
||||
template<typename Value_T, typename Identifier_T = uint32_t>
|
||||
export template<typename Value_T, typename Identifier_T = std::uint32_t>
|
||||
class SparseSet: public TypeErasedSparseSet<Identifier_T>
|
||||
{
|
||||
public:
|
||||
using Dense_T = std::pair<Identifier_T, Value_T>;
|
||||
|
||||
static constexpr auto max_capacity = size_t { 1'000'000 };
|
||||
static constexpr auto max_capacity = std::size_t { 1'000'000 };
|
||||
|
||||
static constexpr auto null_identifier = std::numeric_limits<Identifier_T>().max();
|
||||
|
||||
explicit SparseSet(size_t initial_capacity = 1)
|
||||
explicit SparseSet(std::size_t initial_capacity = 1)
|
||||
{
|
||||
ensure(
|
||||
debug::ensure(
|
||||
initial_capacity <= max_capacity,
|
||||
"Failed to create SparseSet: capacity too large ({} > {})",
|
||||
initial_capacity,
|
||||
|
|
@ -52,13 +53,16 @@ public:
|
|||
{
|
||||
if (m_sparse.size() < identifier + 1)
|
||||
{
|
||||
auto new_capacity = std::max(static_cast<size_t>(identifier + 1), m_sparse.size() * 2);
|
||||
auto new_capacity = std::max(
|
||||
static_cast<std::size_t>(identifier + 1),
|
||||
m_sparse.size() * 2
|
||||
);
|
||||
new_capacity = std::min(new_capacity, max_capacity);
|
||||
|
||||
// log_dbg("Increasing sparse vector size:", m_dead_count);
|
||||
// log_dbg("\tdead_count: {}", m_dead_count);
|
||||
// log_dbg("\talive_count: {}", m_alive_count);
|
||||
// log_dbg("\tsparse.size: {} -> {}", m_sparse.size(), new_capacity);
|
||||
// log::debug("Increasing sparse vector size:", m_dead_count);
|
||||
// log::debug("\tdead_count: {}", m_dead_count);
|
||||
// log::debug("\talive_count: {}", m_alive_count);
|
||||
// log::debug("\tsparse.size: {} -> {}", m_sparse.size(), new_capacity);
|
||||
|
||||
m_sparse.resize(new_capacity, null_identifier);
|
||||
}
|
||||
|
|
@ -145,12 +149,12 @@ public:
|
|||
return std::forward<Self_T>(self).m_dense[std::forward<Self_T>(self).m_sparse[identifier]];
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_size() const noexcept -> size_t
|
||||
[[nodiscard]] auto get_size() const noexcept -> std::size_t
|
||||
{
|
||||
return m_alive_count;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_capacity() const noexcept -> size_t
|
||||
[[nodiscard]] auto get_capacity() const noexcept -> std::size_t
|
||||
{
|
||||
return m_sparse.capacity();
|
||||
}
|
||||
|
|
@ -165,9 +169,9 @@ private:
|
|||
|
||||
std::vector<Identifier_T> m_sparse;
|
||||
|
||||
size_t m_alive_count {};
|
||||
std::size_t m_alive_count {};
|
||||
|
||||
size_t m_dead_count {};
|
||||
std::size_t m_dead_count {};
|
||||
};
|
||||
|
||||
} // namespace lt::ecs
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
#include <ecs/sparse_set.hpp>
|
||||
#include <ranges>
|
||||
#include <test/expects.hpp>
|
||||
#include <test/test.hpp>
|
||||
import ecs.sparse_set;
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import std;
|
||||
|
||||
using lt::test::Case;
|
||||
using lt::test::Suite;
|
||||
|
||||
using lt::test::expect_eq;
|
||||
using lt::test::expect_false;
|
||||
using lt::test::expect_ne;
|
||||
using lt::test::expect_throw;
|
||||
using lt::test::expect_true;
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::expect_eq;
|
||||
using ::lt::test::expect_false;
|
||||
using ::lt::test::expect_ne;
|
||||
using ::lt::test::expect_throw;
|
||||
using ::lt::test::expect_true;
|
||||
using ::lt::test::Suite;
|
||||
using ::lt::test::operator""_suite;
|
||||
|
||||
using Set = lt::ecs::SparseSet<int>;
|
||||
constexpr auto capacity = 100;
|
||||
2
modules/env/CMakeLists.txt
vendored
2
modules/env/CMakeLists.txt
vendored
|
|
@ -1 +1 @@
|
|||
add_library_module(env)
|
||||
add_library_module(NAME env INTERFACES constants.cppm)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
export module env;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt {
|
||||
|
||||
enum class Platform : uint8_t
|
||||
enum class Platform : std::uint8_t
|
||||
{
|
||||
/** The GNU/Linux platform.
|
||||
* Tested on the following distros: arch-x86_64
|
||||
|
|
@ -24,7 +26,7 @@ enum class Platform : uint8_t
|
|||
};
|
||||
|
||||
/** The compiler that was used for compiling the project. */
|
||||
enum class Compiler : uint8_t
|
||||
enum class Compiler : std::uint8_t
|
||||
{
|
||||
clang,
|
||||
gcc,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
add_library_module(input system.cpp)
|
||||
add_library_module(NAME input INTERFACES system.cpp)
|
||||
target_link_libraries(input PUBLIC surface math logger tbb)
|
||||
|
||||
add_test_module(input system.test.cpp)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
namespace lt::Key {
|
||||
|
||||
enum : uint16_t
|
||||
{
|
||||
|
|
@ -177,4 +176,21 @@ enum : uint16_t
|
|||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
enum : uint8_t
|
||||
{
|
||||
Button1 = 0,
|
||||
Button2 = 1,
|
||||
Button3 = 2,
|
||||
Button4 = 3,
|
||||
Button5 = 4,
|
||||
Button6 = 5,
|
||||
Button7 = 6,
|
||||
Button8 = 7,
|
||||
|
||||
LButton = Button1,
|
||||
RButton = Button2,
|
||||
MButton = Button3,
|
||||
};
|
||||
|
||||
} // namespace lt::Key
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#pragma once
|
||||
export module input.components;
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace lt::Mouse {
|
||||
|
||||
enum : uint8_t
|
||||
{
|
||||
Button1 = 0,
|
||||
Button2 = 1,
|
||||
Button3 = 2,
|
||||
Button4 = 3,
|
||||
Button5 = 4,
|
||||
Button6 = 5,
|
||||
Button7 = 6,
|
||||
Button8 = 7,
|
||||
|
||||
LButton = Button1,
|
||||
RButton = Button2,
|
||||
MButton = Button3,
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/system.hpp>
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <surface/components.hpp>
|
||||
#include <surface/events/keyboard.hpp>
|
||||
#include <surface/events/mouse.hpp>
|
||||
|
||||
namespace lt::input {
|
||||
|
||||
class System: public app::ISystem
|
||||
{
|
||||
public:
|
||||
System(memory::Ref<ecs::Registry> registry);
|
||||
|
||||
void tick(app::TickInfo tick) override;
|
||||
|
||||
void on_register() override;
|
||||
|
||||
void on_unregister() override;
|
||||
|
||||
[[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override
|
||||
{
|
||||
return m_last_tick_result;
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_event(const surface::SurfaceComponent::Event &event);
|
||||
|
||||
void on_surface_lost_focus();
|
||||
|
||||
void on_key_press(const lt::surface::KeyPressedEvent &event);
|
||||
|
||||
void on_key_release(const lt::surface::KeyReleasedEvent &event);
|
||||
|
||||
void on_pointer_move(const lt::surface::MouseMovedEvent &event);
|
||||
|
||||
void on_button_press(const lt::surface::ButtonPressedEvent &event);
|
||||
|
||||
void on_button_release(const lt::surface::ButtonReleasedEvent &event);
|
||||
|
||||
memory::Ref<ecs::Registry> m_registry;
|
||||
|
||||
std::array<bool, 512> m_keys {};
|
||||
|
||||
std::array<bool, 512> m_buttons {};
|
||||
|
||||
math::vec2 m_pointer_position;
|
||||
|
||||
app::TickResult m_last_tick_result {};
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt::input
|
||||
|
|
@ -1,3 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/system.hpp>
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <surface/components.hpp>
|
||||
#include <surface/events/keyboard.hpp>
|
||||
#include <surface/events/mouse.hpp>
|
||||
|
||||
namespace lt::input {
|
||||
|
||||
class System: public app::ISystem
|
||||
{
|
||||
public:
|
||||
System(memory::Ref<ecs::Registry> registry);
|
||||
|
||||
void tick(app::TickInfo tick) override;
|
||||
|
||||
void on_register() override;
|
||||
|
||||
void on_unregister() override;
|
||||
|
||||
[[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override
|
||||
{
|
||||
return m_last_tick_result;
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_event(const surface::SurfaceComponent::Event &event);
|
||||
|
||||
void on_surface_lost_focus();
|
||||
|
||||
void on_key_press(const lt::surface::KeyPressedEvent &event);
|
||||
|
||||
void on_key_release(const lt::surface::KeyReleasedEvent &event);
|
||||
|
||||
void on_pointer_move(const lt::surface::MouseMovedEvent &event);
|
||||
|
||||
void on_button_press(const lt::surface::ButtonPressedEvent &event);
|
||||
|
||||
void on_button_release(const lt::surface::ButtonReleasedEvent &event);
|
||||
|
||||
memory::Ref<ecs::Registry> m_registry;
|
||||
|
||||
std::array<bool, 512> m_keys {};
|
||||
|
||||
std::array<bool, 512> m_buttons {};
|
||||
|
||||
math::vec2 m_pointer_position;
|
||||
|
||||
app::TickResult m_last_tick_result {};
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt::input
|
||||
|
||||
|
||||
module :private;
|
||||
|
||||
#include <input/components.hpp>
|
||||
#include <input/system.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
|
|
@ -101,7 +160,7 @@ void System::on_key_press(const lt::surface::KeyPressedEvent &event)
|
|||
{
|
||||
if (event.get_key() > m_keys.size())
|
||||
{
|
||||
log_dbg(
|
||||
log::debug(
|
||||
"Key code larger than key container size, implement platform-dependant "
|
||||
"key-code-mapping!"
|
||||
);
|
||||
|
|
@ -116,7 +175,7 @@ void System::on_key_release(const lt::surface::KeyReleasedEvent &event)
|
|||
{
|
||||
if (event.get_key() > m_keys.size())
|
||||
{
|
||||
log_dbg(
|
||||
log::debug(
|
||||
"Key code larger than key container size, implement platform-dependant "
|
||||
"key-code-mapping!"
|
||||
);
|
||||
|
|
@ -1 +1,2 @@
|
|||
add_library_module(logger logger.cpp)
|
||||
add_library_module(NAME logger INTERFACES logger.cppm)
|
||||
# add_test_module(logger logger.test.cpp)
|
||||
|
|
|
|||
180
modules/logger/logger.cppm
Normal file
180
modules/logger/logger.cppm
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
export module logger;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt::log {
|
||||
|
||||
/** Severity of a log message. */
|
||||
enum class Level : std::uint8_t
|
||||
{
|
||||
/** Lowest and most vebose log level, for tracing execution paths and events */
|
||||
trace = 0,
|
||||
|
||||
/** Vebose log level, for enabling temporarily to debug */
|
||||
debug = 1,
|
||||
|
||||
/** General information */
|
||||
info = 2,
|
||||
|
||||
/** Things we should to be aware of and edge cases */
|
||||
warn = 3,
|
||||
|
||||
/** Defects, bugs and undesired behaviour */
|
||||
error = 4,
|
||||
|
||||
/** Unrecoverable errors */
|
||||
critical = 5,
|
||||
|
||||
/** No logging */
|
||||
off = 6,
|
||||
};
|
||||
|
||||
namespace details {
|
||||
|
||||
inline auto thread_hash_id() noexcept -> std::uint64_t
|
||||
{
|
||||
return static_cast<std::uint64_t>(std::hash<std::thread::id> {}(std::this_thread::get_id()));
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
template<typename... Args>
|
||||
struct [[maybe_unused]] print
|
||||
{
|
||||
[[maybe_unused]] print(
|
||||
Level level,
|
||||
const std::source_location &location,
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments
|
||||
) noexcept
|
||||
{
|
||||
constexpr auto to_string = [](Level level, auto location) {
|
||||
// clang-format off
|
||||
switch (level)
|
||||
{
|
||||
using enum Level;
|
||||
case trace : return "\033[1;37m| trc |\033[0m";
|
||||
case debug : return "\033[1;36m| dbg |\033[0m";
|
||||
case info : return "\033[1;32m| inf |\033[0m";
|
||||
case warn : return "\033[1;33m| wrn |\033[0m";
|
||||
case error : return "\033[1;31m| err |\033[0m";
|
||||
case critical: return "\033[1;41m| crt |\033[0m";
|
||||
case off: return "off";
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
std::unreachable();
|
||||
};
|
||||
|
||||
const auto path = std::filesystem::path { location.file_name() };
|
||||
|
||||
std::println(
|
||||
"{} {} ==> {}",
|
||||
to_string(level, location),
|
||||
std::format("{}:{}", path.filename().c_str(), location.line()),
|
||||
std::format(format, std::forward<Args>(arguments)...)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
print(Level, const std::source_location &, std::format_string<Args...>, Args &&...) noexcept
|
||||
-> print<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] trace
|
||||
{
|
||||
[[maybe_unused]] trace(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::trace, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
trace(std::format_string<Args...>, Args &&...) noexcept -> trace<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] debug
|
||||
{
|
||||
[[maybe_unused]] debug(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::debug, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
debug(std::format_string<Args...>, Args &&...) noexcept -> debug<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] info
|
||||
{
|
||||
[[maybe_unused]] info(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::info, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
info(std::format_string<Args...>, Args &&...) noexcept -> info<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] warn
|
||||
{
|
||||
[[maybe_unused]] warn(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::warn, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
warn(std::format_string<Args...>, Args &&...) noexcept -> warn<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] error
|
||||
{
|
||||
[[maybe_unused]] error(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::error, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
error(std::format_string<Args...>, Args &&...) noexcept -> error<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] critical
|
||||
{
|
||||
[[maybe_unused]] critical(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::critical, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
critical(std::format_string<Args...>, Args &&...) noexcept -> critical<Args...>;
|
||||
|
||||
} // namespace lt::log
|
||||
25
modules/logger/logger.test.cpp
Normal file
25
modules/logger/logger.test.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import logger;
|
||||
import test;
|
||||
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::Suite;
|
||||
|
||||
Suite suite = [] {
|
||||
Case { "no format" } = [] {
|
||||
lt::log::trace("trace");
|
||||
lt::log::debug("debug");
|
||||
lt::log::info("info");
|
||||
lt::log::warn("warn");
|
||||
lt::log::error("error");
|
||||
lt::log::critical("critical");
|
||||
};
|
||||
|
||||
Case { "formatted" } = [] {
|
||||
lt::log::trace("trace {}", 69);
|
||||
lt::log::debug("debug {}", 69);
|
||||
lt::log::info("info {}", 69);
|
||||
lt::log::warn("warn {}", 69);
|
||||
lt::log::error("error {}", 69);
|
||||
lt::log::critical("critical {}", 69);
|
||||
};
|
||||
};
|
||||
|
|
@ -1 +0,0 @@
|
|||
#include <logger/logger.hpp>
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <print>
|
||||
|
||||
/** Severity of a log message. */
|
||||
enum class LogLvl : uint8_t
|
||||
{
|
||||
/** Lowest and most vebose log level, for tracing execution paths and events */
|
||||
trace = 0,
|
||||
|
||||
/** Vebose log level, for enabling temporarily to debug */
|
||||
debug = 1,
|
||||
|
||||
/** General information */
|
||||
info = 2,
|
||||
|
||||
/** Things we should to be aware of and edge cases */
|
||||
warn = 3,
|
||||
|
||||
/** Defects, bugs and undesired behaviour */
|
||||
error = 4,
|
||||
|
||||
/** Unrecoverable errors */
|
||||
critical = 5,
|
||||
|
||||
/** No logging */
|
||||
off = 6,
|
||||
};
|
||||
|
||||
/** Simple console logger */
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
void static show_imgui_window();
|
||||
|
||||
template<typename... Args>
|
||||
void static log(LogLvl lvl, std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
std::ignore = lvl;
|
||||
std::println(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void static log(LogLvl lvl, const char *message) noexcept
|
||||
{
|
||||
std::ignore = lvl;
|
||||
std::println("{}", message);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Logger() = default;
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
void log_trc(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::trace, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log_dbg(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::debug, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log_inf(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::info, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log_wrn(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::warn, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log_err(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::error, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log_crt(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::critical, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
|
@ -1 +1,11 @@
|
|||
add_library_module(math)
|
||||
add_library_module(
|
||||
NAME
|
||||
math
|
||||
INTERFACES
|
||||
algebra.cppm
|
||||
mat4.cppm
|
||||
trig.cppm
|
||||
vec2.cppm
|
||||
vec3.cppm
|
||||
vec4.cppm
|
||||
components/transform.cppm)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <math/mat4.hpp>
|
||||
export module math.algebra;
|
||||
import math.mat4;
|
||||
import std;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
|
|
@ -31,25 +31,29 @@ namespace lt::math {
|
|||
*
|
||||
* the 1 at [z][3] is to save the Z axis into the resulting W for perspective division.
|
||||
*
|
||||
* thanks to pikuma: https://www.youtube.com/watch?v=EqNcqBdrNyI
|
||||
* @ref Thanks to pikuma for explaining the math behind this:
|
||||
* https://www.youtube.com/watch?v=EqNcqBdrNyI
|
||||
*/
|
||||
template<typename T>
|
||||
constexpr auto perspective(T field_of_view, T aspect_ratio, T z_near, T z_far)
|
||||
{
|
||||
const T half_fov_tan = std::tan(field_of_view / static_cast<T>(2));
|
||||
|
||||
auto result = mat4_impl<T> { T { 0 } };
|
||||
auto result = mat4_impl<T>::identity();
|
||||
|
||||
result[0][0] = T { 1 } / (aspect_ratio * half_fov_tan);
|
||||
|
||||
//
|
||||
result[1][1] = T { 1 } / (half_fov_tan);
|
||||
|
||||
result[2][2] = -(z_far + z_near) / (z_far - z_near);
|
||||
|
||||
//
|
||||
// result[2][2] = -(z_far + z_near) / (z_far - z_near);
|
||||
//
|
||||
result[2][2] = z_far / (z_far - z_near);
|
||||
//
|
||||
result[2][3] = -T { 1 };
|
||||
|
||||
result[3][2] = -(T { 2 } * z_far * z_near) / (z_far - z_near);
|
||||
|
||||
//
|
||||
// result[3][2] = -(T { 2 } * z_far * z_near) / (z_far - z_near);
|
||||
result[3][2] = -(z_far * z_near) / (z_far - z_near);
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
16
modules/math/components/transform.cppm
Normal file
16
modules/math/components/transform.cppm
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export module math.components;
|
||||
|
||||
import math.vec3;
|
||||
|
||||
namespace lt::math::components {
|
||||
|
||||
export struct Transform
|
||||
{
|
||||
math::vec3 translation;
|
||||
|
||||
math::vec3 scale;
|
||||
|
||||
math::vec3 rotation;
|
||||
};
|
||||
|
||||
} // namespace lt::math::components
|
||||
|
|
@ -1,14 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <math/vec3.hpp>
|
||||
#include <math/vec4.hpp>
|
||||
export module math.mat4;
|
||||
import math.vec3;
|
||||
import math.vec4;
|
||||
import std;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
template<typename T = float>
|
||||
export template<typename T = float>
|
||||
struct mat4_impl
|
||||
{
|
||||
using Column_T = vec4_impl<T>;
|
||||
|
||||
constexpr explicit mat4_impl(T scalar = 0)
|
||||
: values(
|
||||
{
|
||||
|
|
@ -43,7 +44,7 @@ struct mat4_impl
|
|||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto identity() -> mat4_impl<T>
|
||||
[[nodiscard]] static constexpr auto identity() -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {
|
||||
{ 1 }, {}, {}, {}, //
|
||||
|
|
@ -53,12 +54,12 @@ struct mat4_impl
|
|||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) -> Column_T &
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) -> Column_T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) const -> const Column_T &
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) const -> const Column_T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
|
@ -76,34 +77,34 @@ struct mat4_impl
|
|||
std::array<Column_T, 4> values; // NOLINT
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto translate(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto translate(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto rotate(float value, const vec3_impl<T> &xyz) -> mat4_impl<T>
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto rotate(float value, const vec3_impl<T> &xyz) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto scale(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto scale(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto inverse(const mat4_impl<T> &value) -> mat4_impl<T>
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto inverse(const mat4_impl<T> &value) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
using mat4 = mat4_impl<float>;
|
||||
export using mat4 = mat4_impl<float>;
|
||||
|
||||
using imat4 = mat4_impl<int32_t>;
|
||||
export using imat4 = mat4_impl<std::int32_t>;
|
||||
|
||||
using umat4 = mat4_impl<uint32_t>;
|
||||
export using umat4 = mat4_impl<std::uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#pragma once
|
||||
export module math.trig;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
export module math.vec2;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
template<typename T = float>
|
||||
export template<typename T = float>
|
||||
struct vec2_impl
|
||||
{
|
||||
constexpr vec2_impl(): x(), y()
|
||||
|
|
@ -57,15 +59,15 @@ struct vec2_impl
|
|||
};
|
||||
|
||||
|
||||
using vec2 = vec2_impl<float>;
|
||||
export using vec2 = vec2_impl<float>;
|
||||
|
||||
using ivec2 = vec2_impl<int32_t>;
|
||||
export using ivec2 = vec2_impl<std::int32_t>;
|
||||
|
||||
using uvec2 = vec2_impl<uint32_t>;
|
||||
export using uvec2 = vec2_impl<std::uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
||||
template<typename T>
|
||||
export template<typename T>
|
||||
struct std::formatter<lt::math::vec2_impl<T>>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context &context)
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
export module math.vec3;
|
||||
|
||||
#include <cstdint>
|
||||
#include <math/vec2.hpp>
|
||||
import math.vec2;
|
||||
import std;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
template<typename T = float>
|
||||
export template<typename T = float>
|
||||
struct vec3_impl
|
||||
{
|
||||
constexpr vec3_impl(): x(), y(), z()
|
||||
|
|
@ -61,11 +61,11 @@ struct vec3_impl
|
|||
T z; // NOLINT
|
||||
};
|
||||
|
||||
using vec3 = vec3_impl<float>;
|
||||
export using vec3 = vec3_impl<float>;
|
||||
|
||||
using ivec3 = vec3_impl<int32_t>;
|
||||
export using ivec3 = vec3_impl<std::int32_t>;
|
||||
|
||||
using uvec3 = vec3_impl<uint32_t>;
|
||||
export using uvec3 = vec3_impl<std::uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
export module math.vec4;
|
||||
import math.vec2;
|
||||
import math.vec3;
|
||||
import std;
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
template<typename T = float>
|
||||
export template<typename T = float>
|
||||
struct vec4_impl
|
||||
{
|
||||
constexpr vec4_impl(): x(), y(), z(), w()
|
||||
|
|
@ -40,12 +40,12 @@ struct vec4_impl
|
|||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) -> T &
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) -> T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) const -> const T &
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) const -> const T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
|
@ -86,15 +86,15 @@ struct vec4_impl
|
|||
};
|
||||
};
|
||||
|
||||
using vec4 = vec4_impl<float>;
|
||||
export using vec4 = vec4_impl<float>;
|
||||
|
||||
using ivec4 = vec4_impl<int32_t>;
|
||||
export using ivec4 = vec4_impl<std::int32_t>;
|
||||
|
||||
using uvec4 = vec4_impl<uint32_t>;
|
||||
export using uvec4 = vec4_impl<std::uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
||||
template<typename T>
|
||||
export template<typename T>
|
||||
struct std::formatter<lt::math::vec4_impl<T>>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context &context)
|
||||
|
|
@ -1 +1,2 @@
|
|||
add_library_module(memory)
|
||||
add_library_module(NAME memory INTERFACES null_on_move.cppm reference.cppm
|
||||
scope.cppm)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
#pragma once
|
||||
export module memory.null_on_move;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt::memory {
|
||||
|
||||
/** Holds an `Underlying_T`, assigns it to `null_value` when this object is moved.
|
||||
*
|
||||
* @note For avoiding the need to explicitly implement the move constructor for objects that hold
|
||||
* Vulkan objects. But may server other purposes, hence why I kept the implementation generic.
|
||||
* Vulkan objects. But may serve other purposes, hence why I kept the implementation generic.
|
||||
*/
|
||||
template<typename Underlying_T, Underlying_T null_value = nullptr>
|
||||
class NullOnMove
|
||||
|
|
@ -77,9 +79,9 @@ public:
|
|||
return m_value;
|
||||
}
|
||||
|
||||
operator uint64_t() const
|
||||
operator std::uint64_t() const
|
||||
{
|
||||
return (uint64_t)m_value;
|
||||
return (std::uint64_t)m_value;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get() -> Underlying_T
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
export module memory.reference;
|
||||
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory>
|
||||
import std;
|
||||
|
||||
namespace lt::memory {
|
||||
|
||||
|
|
@ -10,21 +9,21 @@ namespace lt::memory {
|
|||
* @note Currently just an alias, might turn into an implementation later.
|
||||
* @ref https://en.cppreference.com/w/cpp/memory/shared_ptr.html
|
||||
*/
|
||||
template<typename t>
|
||||
using Ref = std::shared_ptr<t>;
|
||||
export template<typename T>
|
||||
using Ref = std::shared_ptr<T>;
|
||||
|
||||
/** Allocates memory for an `Underlying_T` and directly constructs it there.
|
||||
*
|
||||
* @return A Ref<Underlying_T> to the constructed object.
|
||||
*/
|
||||
template<typename Underlying_T, typename... Args>
|
||||
export template<typename Underlying_T, typename... Args>
|
||||
constexpr Ref<Underlying_T> create_ref(Args &&...args)
|
||||
{
|
||||
return std::make_shared<Underlying_T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Converts c-style pointer of type `Underlying_T` to a `Ref<Underlying_T>`. */
|
||||
template<typename Underlying_T>
|
||||
export template<typename Underlying_T>
|
||||
constexpr Ref<Underlying_T> make_ref(Underlying_T *raw_pointer)
|
||||
{
|
||||
return Ref<Underlying_T>(raw_pointer);
|
||||
|
|
@ -1,30 +1,29 @@
|
|||
#pragma once
|
||||
export module memory.scope;
|
||||
|
||||
#include <memory/scope.hpp>
|
||||
#include <memory>
|
||||
import std;
|
||||
|
||||
namespace lt::memory {
|
||||
|
||||
/** Wrapper around std::unique_ptr.
|
||||
/** @brief Wrapper around std::unique_ptr.
|
||||
*
|
||||
* @note Currently just an alias, might turn into an implementation later.
|
||||
* @ref https://en.cppreference.com/w/cpp/memory/unique_ptr.html
|
||||
*/
|
||||
template<typename t>
|
||||
export template<typename t>
|
||||
using Scope = std::unique_ptr<t>;
|
||||
|
||||
/** Allocates memory for an `Underlying_T` and directly constructs it there.
|
||||
*
|
||||
* @return A Scope<Underlying_T> to the constructed object.
|
||||
*/
|
||||
template<typename Underlying_T, typename... Args>
|
||||
export template<typename Underlying_T, typename... Args>
|
||||
constexpr Scope<Underlying_T> create_scope(Args &&...args)
|
||||
{
|
||||
return std::make_unique<Underlying_T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Converts c-style pointer of type `Underlying_T` to a `Scope<Underlying_T>`. */
|
||||
template<typename Underlying_T>
|
||||
export template<typename Underlying_T>
|
||||
constexpr Scope<Underlying_T> make_scope(Underlying_T *raw_pointer)
|
||||
{
|
||||
return Scope<Underlying_T>(raw_pointer);
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
add_library_module(libmirror)
|
||||
target_link_libraries(libmirror INTERFACE app time input surface renderer)
|
||||
target_link_libraries(libmirror INTERFACE app time input surface renderer
|
||||
camera)
|
||||
|
||||
add_test_module(
|
||||
libmirror layers/editor_layer.test.cpp panels/asset_browser.test.cpp
|
||||
|
|
|
|||
|
|
@ -2,13 +2,17 @@
|
|||
#include <app/application.hpp>
|
||||
#include <app/entrypoint.hpp>
|
||||
#include <app/system.hpp>
|
||||
#include <camera/components.hpp>
|
||||
#include <ecs/entity.hpp>
|
||||
#include <input/components.hpp>
|
||||
#include <input/system.hpp>
|
||||
#include <math/components/transform.hpp>
|
||||
#include <math/trig.hpp>
|
||||
#include <math/vec2.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
#include <renderer/components/messenger.hpp>
|
||||
#include <renderer/components/sprite.hpp>
|
||||
#include <renderer/system.hpp>
|
||||
#include <surface/events/keyboard.hpp>
|
||||
#include <surface/events/surface.hpp>
|
||||
|
|
@ -28,7 +32,7 @@ void renderer_callback(
|
|||
std::ignore = message_type;
|
||||
std::ignore = user_data;
|
||||
|
||||
log_dbg("RENDERER CALLBACK: {}", data.message);
|
||||
log::debug("RENDERER CALLBACK: {}", data.message);
|
||||
}
|
||||
|
||||
class MirrorSystem: public lt::app::ISystem
|
||||
|
|
@ -66,13 +70,18 @@ public:
|
|||
const auto &[x, y] = surface.get_position();
|
||||
const auto &[width, height] = surface.get_resolution();
|
||||
|
||||
|
||||
if (input.get_action(m_quit_action_key).state == State::active)
|
||||
{
|
||||
should_quit = true;
|
||||
}
|
||||
if (input.get_action(m_debug_action_keys[0]).state == State::active)
|
||||
{
|
||||
surface.push_request(surface::ModifyPositionRequest({ x + 5, y + 5 }));
|
||||
for (auto &[id, camera] :
|
||||
m_registry->view<lt::camera::components::PerspectiveCamera>())
|
||||
{
|
||||
camera.vertical_fov += (static_cast<float>(tick.delta_time.count()) * 40.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (input.get_action(m_debug_action_keys[1]).state == State::active)
|
||||
|
|
@ -138,7 +147,7 @@ public:
|
|||
|
||||
void on_window_close()
|
||||
{
|
||||
log_inf("Window close requested...");
|
||||
log::info("Window close requested...");
|
||||
|
||||
unregister_system(m_input_system);
|
||||
unregister_system(m_surface_system);
|
||||
|
|
@ -219,6 +228,35 @@ public:
|
|||
.callback = &renderer_callback,
|
||||
.user_data = this,
|
||||
} });
|
||||
|
||||
m_sprite_id = m_editor_registry->create_entity();
|
||||
|
||||
m_editor_registry->add(
|
||||
m_sprite_id,
|
||||
renderer::components::Sprite { .color = lt::math::vec3 { 1.0f, 0.0f, 0.0f } }
|
||||
);
|
||||
m_editor_registry->add(
|
||||
m_sprite_id,
|
||||
math::components::Transform {
|
||||
.translation = { -5.0, -5.0, 0.5 },
|
||||
.scale = { 5.0, 5.0, 1.0 },
|
||||
.rotation = {},
|
||||
}
|
||||
);
|
||||
|
||||
m_camera_id = m_editor_registry->create_entity();
|
||||
|
||||
m_editor_registry->add(
|
||||
m_camera_id,
|
||||
camera::components::PerspectiveCamera {
|
||||
.vertical_fov = math::radians(90.0f),
|
||||
.near_plane = 0.1f,
|
||||
.far_plane = 30.0,
|
||||
.aspect_ratio = 1.0f,
|
||||
.background_color = math::vec4(1.0, 0.0, 0.0, 1.0),
|
||||
.is_primary = true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void setup_input_system()
|
||||
|
|
@ -245,6 +283,10 @@ private:
|
|||
memory::Ref<MirrorSystem> m_mirror_system;
|
||||
|
||||
lt::ecs::EntityId m_window = lt::ecs::null_entity;
|
||||
|
||||
lt::ecs::EntityId m_camera_id = lt::ecs::null_entity;
|
||||
|
||||
lt::ecs::EntityId m_sprite_id = lt::ecs::null_entity;
|
||||
};
|
||||
|
||||
auto app::create_application() -> memory::Scope<app::Application>
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ void AssetBrowserPanel::on_user_interface_update()
|
|||
))
|
||||
{
|
||||
auto serializer = SceneSerializer { m_active_scene };
|
||||
log_inf("Attempting to deserialize: {}", path.string());
|
||||
log::info("Attempting to deserialize: {}", path.string());
|
||||
serializer.deserialize(path.string());
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -8,21 +8,29 @@ add_library_module(
|
|||
backend/vk/context/instance.cpp
|
||||
backend/vk/context/surface.cpp
|
||||
backend/vk/context/swapchain.cpp
|
||||
backend/vk/data/buffer.cpp
|
||||
backend/vk/renderer/pass.cpp
|
||||
backend/vk/renderer/renderer.cpp
|
||||
# Vulkan - frontend
|
||||
# frontend
|
||||
frontend/messenger.cpp
|
||||
frontend/context/device.cpp
|
||||
frontend/context/gpu.cpp
|
||||
frontend/context/instance.cpp
|
||||
frontend/context/surface.cpp
|
||||
frontend/context/swapchain.cpp
|
||||
frontend/data/buffer.cpp
|
||||
frontend/renderer/renderer.cpp
|
||||
frontend/renderer/pass.cpp)
|
||||
|
||||
target_link_libraries(
|
||||
renderer
|
||||
PUBLIC app ecs memory assets time bitwise
|
||||
PUBLIC app
|
||||
ecs
|
||||
memory
|
||||
assets
|
||||
time
|
||||
bitwise
|
||||
camera
|
||||
PRIVATE surface pthread)
|
||||
|
||||
add_test_module(
|
||||
|
|
@ -34,11 +42,10 @@ add_test_module(
|
|||
frontend/context/surface.test.cpp
|
||||
frontend/context/device.test.cpp
|
||||
frontend/context/swapchain.test.cpp
|
||||
frontend/renderer/pass.test.cpp
|
||||
frontend/data/buffer.test.cpp
|
||||
# frontend/renderer/pass.test.cpp
|
||||
frontend/renderer/renderer.test.cpp
|
||||
# backend specific tests -- vk
|
||||
backend/vk/context/instance.test.cpp
|
||||
# backend specific tests -- dx backend specific tests -- mt
|
||||
)
|
||||
backend/vk/context/instance.test.cpp)
|
||||
|
||||
target_link_libraries(renderer_tests PRIVATE surface pthread)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
//
|
||||
#include <logger/logger.hpp>
|
||||
#include <renderer/backend/vk/context/device.hpp>
|
||||
#include <renderer/backend/vk/context/gpu.hpp>
|
||||
#include <renderer/backend/vk/context/surface.hpp>
|
||||
|
|
@ -47,8 +48,8 @@ Device::~Device()
|
|||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
log_err("Failed to destroy vk device:");
|
||||
log_err("\twhat: {}", exp.what());
|
||||
log::error("Failed to destroy vk device:");
|
||||
log::error("\twhat: {}", exp.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,20 +76,107 @@ void Device::initialize_logical_device()
|
|||
|
||||
auto extensions = std::vector<const char *> {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
|
||||
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
auto device_info = VkDeviceCreateInfo {
|
||||
auto descriptor_indexing_features = m_gpu->get_descriptor_indexing_features();
|
||||
log::debug("");
|
||||
|
||||
log::debug(
|
||||
"shaderInputAttachmentArrayDynamicIndexing: {}",
|
||||
descriptor_indexing_features.shaderInputAttachmentArrayDynamicIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderUniformTexelBufferArrayDynamicIndexing: {}",
|
||||
descriptor_indexing_features.shaderUniformTexelBufferArrayDynamicIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageTexelBufferArrayDynamicIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageTexelBufferArrayDynamicIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderUniformBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderUniformBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderSampledImageArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageImageArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageImageArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderInputAttachmentArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderInputAttachmentArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderUniformTexelBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderUniformTexelBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" shaderStorageTexelBufferArrayNonUniformIndexing: {}",
|
||||
descriptor_indexing_features.shaderStorageTexelBufferArrayNonUniformIndexing
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingUniformBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingUniformBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingSampledImageUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingStorageImageUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingStorageImageUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingStorageBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingStorageBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingUniformTexelBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingUniformTexelBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingStorageTexelBufferUpdateAfterBind: {}",
|
||||
descriptor_indexing_features.descriptorBindingStorageTexelBufferUpdateAfterBind
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingUpdateUnusedWhilePending: {}",
|
||||
descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingPartiallyBound: {}",
|
||||
descriptor_indexing_features.descriptorBindingPartiallyBound
|
||||
);
|
||||
log::debug(
|
||||
" descriptorBindingVariableDescriptorCount: {}",
|
||||
descriptor_indexing_features.descriptorBindingVariableDescriptorCount
|
||||
);
|
||||
log::debug(" runtimeDescriptorArray: {}", descriptor_indexing_features.runtimeDescriptorArray);
|
||||
const auto dynamic_rendering_features = VkPhysicalDeviceDynamicRenderingFeatures {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
|
||||
.pNext = &descriptor_indexing_features,
|
||||
.dynamicRendering = true,
|
||||
};
|
||||
|
||||
|
||||
m_device = m_gpu->create_device(
|
||||
VkDeviceCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = &dynamic_rendering_features,
|
||||
.queueCreateInfoCount = static_cast<uint32_t>(queue_infos.size()),
|
||||
.pQueueCreateInfos = queue_infos.data(),
|
||||
.enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
|
||||
.ppEnabledExtensionNames = extensions.data(),
|
||||
.pEnabledFeatures = &physical_device_features,
|
||||
};
|
||||
|
||||
ensure(
|
||||
!vk_create_device(m_gpu->vk(), &device_info, nullptr, &m_device),
|
||||
"Failed to create logical vulkan device"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -207,6 +295,31 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
|
|||
return images;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::get_memory_requirements(VkBuffer buffer) const -> VkMemoryRequirements
|
||||
{
|
||||
auto requirements = VkMemoryRequirements {};
|
||||
vk_get_buffer_memory_requirements(m_device, buffer, &requirements);
|
||||
return requirements;
|
||||
}
|
||||
|
||||
void Device::bind_memory(VkBuffer buffer, VkDeviceMemory memory, size_t offset /* = 0u */) const
|
||||
{
|
||||
vkc(vk_bind_buffer_memory(m_device, buffer, memory, offset));
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::map_memory(VkDeviceMemory memory, size_t size, size_t offset) const
|
||||
-> std::span<std::byte>
|
||||
{
|
||||
void *data = {};
|
||||
vkc(vk_map_memory(m_device, memory, offset, size, {}, &data));
|
||||
return { std::bit_cast<std::byte *>(data), size };
|
||||
}
|
||||
|
||||
void Device::unmap_memory(VkDeviceMemory memory)
|
||||
{
|
||||
vk_unmap_memory(m_device, memory);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::create_swapchain(VkSwapchainCreateInfoKHR info) const -> VkSwapchainKHR
|
||||
{
|
||||
auto *swapchain = VkSwapchainKHR {};
|
||||
|
|
@ -251,9 +364,19 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
|
|||
return pass;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::create_pipeline_layout(VkPipelineLayoutCreateInfo info) const
|
||||
-> VkPipelineLayout
|
||||
[[nodiscard]] auto Device::create_pipeline_layout(
|
||||
std::vector<VkDescriptorSetLayout> descriptor_set_layout,
|
||||
std::vector<VkPushConstantRange> push_constant_ranges
|
||||
) const -> VkPipelineLayout
|
||||
{
|
||||
auto info = VkPipelineLayoutCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = static_cast<uint32_t>(descriptor_set_layout.size()),
|
||||
.pSetLayouts = descriptor_set_layout.data(),
|
||||
.pushConstantRangeCount = static_cast<uint32_t>(push_constant_ranges.size()),
|
||||
.pPushConstantRanges = push_constant_ranges.data(),
|
||||
};
|
||||
|
||||
auto *pipeline_layout = VkPipelineLayout {};
|
||||
vkc(vk_create_pipeline_layout(m_device, &info, nullptr, &pipeline_layout));
|
||||
return pipeline_layout;
|
||||
|
|
@ -299,6 +422,28 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
|
|||
return fences;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::create_buffer(VkBufferCreateInfo info) const -> VkBuffer
|
||||
{
|
||||
auto *buffer = VkBuffer {};
|
||||
vkc(vk_create_buffer(m_device, &info, nullptr, &buffer));
|
||||
return buffer;
|
||||
}
|
||||
[[nodiscard]] auto Device::create_desscriptor_pool(VkDescriptorPoolCreateInfo info) const
|
||||
-> VkDescriptorPool
|
||||
{
|
||||
auto *pool = VkDescriptorPool {};
|
||||
vkc(vk_create_descriptor_pool(m_device, &info, nullptr, &pool));
|
||||
return pool;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::create_descriptor_set_layout(VkDescriptorSetLayoutCreateInfo info) const
|
||||
-> VkDescriptorSetLayout
|
||||
{
|
||||
auto *layout = VkDescriptorSetLayout {};
|
||||
vkc(vk_create_descriptor_set_layout(m_device, &info, nullptr, &layout));
|
||||
return layout;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::allocate_command_buffers(VkCommandBufferAllocateInfo info) const
|
||||
-> std::vector<VkCommandBuffer>
|
||||
{
|
||||
|
|
@ -307,6 +452,34 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
|
|||
return command_buffers;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory
|
||||
{
|
||||
auto *memory = VkDeviceMemory {};
|
||||
vkc(vk_allocate_memory(m_device, &info, nullptr, &memory));
|
||||
return memory;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Device::allocate_descriptor_set(VkDescriptorSetAllocateInfo info) const
|
||||
-> VkDescriptorSet
|
||||
{
|
||||
auto *descriptor_set = VkDescriptorSet {};
|
||||
vkc(vk_allocate_descriptor_sets(m_device, &info, &descriptor_set));
|
||||
return descriptor_set;
|
||||
}
|
||||
|
||||
void Device::free_memory(VkDeviceMemory memory) const
|
||||
{
|
||||
vk_free_memory(m_device, memory, nullptr);
|
||||
}
|
||||
|
||||
void Device::free_descriptor_set(
|
||||
VkDescriptorPool descriptor_pool,
|
||||
VkDescriptorSet descriptor_set
|
||||
) const
|
||||
{
|
||||
vkc(vk_free_descriptor_sets(m_device, descriptor_pool, 1, &descriptor_set));
|
||||
}
|
||||
|
||||
void Device::destroy_swapchain(VkSwapchainKHR swapchain) const
|
||||
{
|
||||
vk_destroy_swapchain_khr(m_device, swapchain, m_allocator);
|
||||
|
|
@ -389,4 +562,19 @@ void Device::destroy_fences(std::span<VkFence> fences) const
|
|||
}
|
||||
}
|
||||
|
||||
void Device::destroy_buffer(VkBuffer buffer) const
|
||||
{
|
||||
vk_destroy_buffer(m_device, buffer, nullptr);
|
||||
}
|
||||
|
||||
void Device::destroy_descriptor_set_layout(VkDescriptorSetLayout layout) const
|
||||
{
|
||||
vk_destroy_descriptor_set_layout(m_device, layout, nullptr);
|
||||
}
|
||||
|
||||
void Device::destroy_descriptor_pool(VkDescriptorPool pool) const
|
||||
{
|
||||
vk_destroy_descriptor_pool(m_device, pool, nullptr);
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
|
|||
|
|
@ -96,6 +96,16 @@ public:
|
|||
|
||||
[[nodiscard]] auto get_swapchain_images(VkSwapchainKHR swapchain) const -> std::vector<VkImage>;
|
||||
|
||||
[[nodiscard]] auto get_memory_requirements(VkBuffer buffer) const -> VkMemoryRequirements;
|
||||
|
||||
/** binders / mappers */
|
||||
void bind_memory(VkBuffer buffer, VkDeviceMemory memory, size_t offset = 0u) const;
|
||||
|
||||
[[nodiscard]] auto map_memory(VkDeviceMemory memory, size_t size, size_t offset) const
|
||||
-> std::span<std::byte>;
|
||||
|
||||
void unmap_memory(VkDeviceMemory memory);
|
||||
|
||||
/** create functions */
|
||||
[[nodiscard]] auto create_swapchain(VkSwapchainCreateInfoKHR info) const -> VkSwapchainKHR;
|
||||
|
||||
|
|
@ -108,8 +118,10 @@ public:
|
|||
|
||||
[[nodiscard]] auto create_pass(VkRenderPassCreateInfo info) const -> VkRenderPass;
|
||||
|
||||
[[nodiscard]] auto create_pipeline_layout(VkPipelineLayoutCreateInfo info) const
|
||||
-> VkPipelineLayout;
|
||||
[[nodiscard]] auto create_pipeline_layout(
|
||||
std::vector<VkDescriptorSetLayout> descriptor_set_layout,
|
||||
std::vector<VkPushConstantRange> push_constant_ranges
|
||||
) const -> VkPipelineLayout;
|
||||
|
||||
[[nodiscard]] auto create_shader_module(VkShaderModuleCreateInfo info) const -> VkShaderModule;
|
||||
|
||||
|
|
@ -120,10 +132,31 @@ public:
|
|||
[[nodiscard]] auto create_fences(VkFenceCreateInfo info, uint32_t count) const
|
||||
-> std::vector<VkFence>;
|
||||
|
||||
[[nodiscard]] auto create_buffer(VkBufferCreateInfo info) const -> VkBuffer;
|
||||
|
||||
[[nodiscard]] auto create_descriptor_set_layout(VkDescriptorSetLayoutCreateInfo info) const
|
||||
-> VkDescriptorSetLayout;
|
||||
|
||||
[[nodiscard]] auto create_desscriptor_pool(VkDescriptorPoolCreateInfo info) const
|
||||
-> VkDescriptorPool;
|
||||
|
||||
/** allocation functions */
|
||||
[[nodiscard]] auto allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory;
|
||||
|
||||
[[nodiscard]] auto allocate_command_buffers(VkCommandBufferAllocateInfo info) const
|
||||
-> std::vector<VkCommandBuffer>;
|
||||
|
||||
[[nodiscard]] auto allocate_descriptor_set(VkDescriptorSetAllocateInfo info) const
|
||||
-> VkDescriptorSet;
|
||||
|
||||
/** de-allocation functions */
|
||||
void free_memory(VkDeviceMemory memory) const;
|
||||
|
||||
void free_descriptor_set(
|
||||
VkDescriptorPool descriptor_pool,
|
||||
VkDescriptorSet descriptor_set
|
||||
) const;
|
||||
|
||||
/** destroy functions */
|
||||
void destroy_swapchain(VkSwapchainKHR swapchain) const;
|
||||
|
||||
|
|
@ -153,6 +186,12 @@ public:
|
|||
|
||||
void destroy_fences(std::span<VkFence> fences) const;
|
||||
|
||||
void destroy_buffer(VkBuffer buffer) const;
|
||||
|
||||
void destroy_descriptor_set_layout(VkDescriptorSetLayout layout) const;
|
||||
|
||||
void destroy_descriptor_pool(VkDescriptorPool pool) const;
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static auto get_object_type(const T &object) -> VkObjectType
|
||||
|
|
|
|||
|
|
@ -5,35 +5,38 @@
|
|||
namespace lt::renderer::vk {
|
||||
|
||||
Gpu::Gpu(IInstance *instance)
|
||||
: m_descriptor_indexing_features(
|
||||
{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES }
|
||||
)
|
||||
{
|
||||
auto gpus = static_cast<Instance *>(instance)->enumerate_gpus();
|
||||
|
||||
for (auto &gpu : gpus)
|
||||
{
|
||||
auto properties = VkPhysicalDeviceProperties {};
|
||||
auto features = VkPhysicalDeviceFeatures {};
|
||||
auto features = VkPhysicalDeviceFeatures2 {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||
.pNext = &m_descriptor_indexing_features
|
||||
};
|
||||
|
||||
vk_get_physical_device_properties(gpu, &properties);
|
||||
vk_get_physical_device_features(gpu, &features);
|
||||
|
||||
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
|
||||
&& features.geometryShader)
|
||||
&& features.features.geometryShader)
|
||||
{
|
||||
m_gpu = gpu;
|
||||
}
|
||||
}
|
||||
ensure(m_gpu, "Failed to find any suitable Vulkan physical device");
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Gpu::get_queue_family_properties() const -> std::vector<VkQueueFamilyProperties>
|
||||
{
|
||||
|
||||
vk_get_physical_device_memory_properties(m_gpu, &m_memory_properties);
|
||||
|
||||
auto count = uint32_t { 0u };
|
||||
vk_get_physical_device_queue_family_properties(m_gpu, &count, nullptr);
|
||||
|
||||
auto properties = std::vector<VkQueueFamilyProperties>(count);
|
||||
vk_get_physical_device_queue_family_properties(m_gpu, &count, properties.data());
|
||||
|
||||
return properties;
|
||||
m_queue_family_properties.resize(count);
|
||||
vk_get_physical_device_queue_family_properties(m_gpu, &count, m_queue_family_properties.data());
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Gpu::queue_family_supports_presentation(
|
||||
|
|
@ -67,5 +70,11 @@ Gpu::Gpu(IInstance *instance)
|
|||
return formats;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Gpu::create_device(VkDeviceCreateInfo info) const -> VkDevice
|
||||
{
|
||||
auto *device = VkDevice {};
|
||||
vkc(vk_create_device(m_gpu, &info, nullptr, &device));
|
||||
return device;
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
|
|||
|
|
@ -12,13 +12,6 @@ class Gpu: public IGpu
|
|||
public:
|
||||
Gpu(IInstance *instance);
|
||||
|
||||
[[nodiscard]] auto vk() const -> VkPhysicalDevice
|
||||
{
|
||||
return m_gpu;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_queue_family_properties() const -> std::vector<VkQueueFamilyProperties>;
|
||||
|
||||
[[nodiscard]] auto queue_family_supports_presentation(
|
||||
VkSurfaceKHR surface,
|
||||
uint32_t queue_family_idx
|
||||
|
|
@ -30,8 +23,39 @@ public:
|
|||
[[nodiscard]] auto get_surface_formats(VkSurfaceKHR surface) const
|
||||
-> std::vector<VkSurfaceFormatKHR>;
|
||||
|
||||
[[nodiscard]] auto create_device(VkDeviceCreateInfo info) const -> VkDevice;
|
||||
|
||||
[[nodiscard]] auto get_properties() const -> VkPhysicalDeviceProperties
|
||||
{
|
||||
return m_properties;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_descriptor_indexing_features() const
|
||||
-> VkPhysicalDeviceDescriptorIndexingFeatures
|
||||
{
|
||||
return m_descriptor_indexing_features;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_memory_properties() const -> VkPhysicalDeviceMemoryProperties
|
||||
{
|
||||
return m_memory_properties;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_queue_family_properties() const -> std::vector<VkQueueFamilyProperties>
|
||||
{
|
||||
return m_queue_family_properties;
|
||||
}
|
||||
|
||||
private:
|
||||
memory::NullOnMove<VkPhysicalDevice> m_gpu = VK_NULL_HANDLE;
|
||||
|
||||
VkPhysicalDeviceProperties m_properties {};
|
||||
|
||||
VkPhysicalDeviceDescriptorIndexingFeatures m_descriptor_indexing_features;
|
||||
|
||||
VkPhysicalDeviceMemoryProperties m_memory_properties {};
|
||||
|
||||
std::vector<VkQueueFamilyProperties> m_queue_family_properties;
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
|
|||
|
|
@ -29,8 +29,9 @@ PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family
|
|||
PFN_vkCreateDevice vk_create_device {};
|
||||
PFN_vkGetDeviceProcAddr vk_get_device_proc_address {};
|
||||
PFN_vkDestroyDevice vk_destroy_device {};
|
||||
PFN_vkGetPhysicalDeviceFeatures vk_get_physical_device_features {};
|
||||
PFN_vkGetPhysicalDeviceFeatures2 vk_get_physical_device_features {};
|
||||
PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties {};
|
||||
PFN_vkGetPhysicalDeviceMemoryProperties vk_get_physical_device_memory_properties {};
|
||||
|
||||
// extension instance functions
|
||||
PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label {};
|
||||
|
|
@ -86,15 +87,37 @@ PFN_vkCmdBindPipeline vk_cmd_bind_pipeline {};
|
|||
PFN_vkCmdDraw vk_cmd_draw {};
|
||||
PFN_vkCmdSetViewport vk_cmd_set_viewport {};
|
||||
PFN_vkCmdSetScissor vk_cmd_set_scissors {};
|
||||
PFN_vkCmdPushConstants vk_cmd_push_constants {};
|
||||
PFN_vkCmdCopyBuffer vk_cmd_copy_buffer {};
|
||||
|
||||
PFN_vkCreateDescriptorSetLayout vk_create_descriptor_set_layout {};
|
||||
PFN_vkDestroyDescriptorSetLayout vk_destroy_descriptor_set_layout {};
|
||||
PFN_vkCreateDescriptorPool vk_create_descriptor_pool {};
|
||||
PFN_vkDestroyDescriptorPool vk_destroy_descriptor_pool {};
|
||||
PFN_vkAllocateDescriptorSets vk_allocate_descriptor_sets {};
|
||||
PFN_vkFreeDescriptorSets vk_free_descriptor_sets {};
|
||||
|
||||
PFN_vkCreateBuffer vk_create_buffer {};
|
||||
PFN_vkDestroyBuffer vk_destroy_buffer {};
|
||||
PFN_vkGetBufferMemoryRequirements vk_get_buffer_memory_requirements {};
|
||||
PFN_vkAllocateMemory vk_allocate_memory {};
|
||||
PFN_vkBindBufferMemory vk_bind_buffer_memory {};
|
||||
PFN_vkMapMemory vk_map_memory {};
|
||||
PFN_vkUnmapMemory vk_unmap_memory {};
|
||||
PFN_vkFreeMemory vk_free_memory {};
|
||||
|
||||
PFN_vkResetCommandBuffer vk_reset_command_buffer {};
|
||||
|
||||
PFN_vkCmdBeginRendering vk_cmd_begin_rendering {};
|
||||
PFN_vkCmdEndRendering vk_cmd_end_rendering {};
|
||||
|
||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support {};
|
||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities {};
|
||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats {};
|
||||
|
||||
auto vk_create_xlib_surface_khr = PFN_vkCreateXlibSurfaceKHR {};
|
||||
auto vk_destroy_surface_khr = PFN_vkDestroySurfaceKHR {};
|
||||
|
||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
Instance::Instance()
|
||||
|
|
@ -127,6 +150,7 @@ void Instance::initialize_instance()
|
|||
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
|
||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
|
||||
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
const char *layer_name = "VK_LAYER_KHRONOS_validation";
|
||||
|
|
@ -220,10 +244,10 @@ void Instance::initialize_instance()
|
|||
memset(extensions.data(), 0, extensions.size() * sizeof(VkExtensionProperties));
|
||||
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data()));
|
||||
|
||||
// log_inf("Available vulkan instance extensions:");
|
||||
// log::info("Available vulkan instance extensions:");
|
||||
for (auto &ext : extensions)
|
||||
{
|
||||
// log_inf("\t{} @ {}", ext.extensionName, ext.specVersion);
|
||||
// log::info("\t{} @ {}", ext.extensionName, ext.specVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -269,7 +293,7 @@ void Instance::load_global_functions()
|
|||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
pfn = reinterpret_cast<T>(vk_get_instance_proc_address(nullptr, fn_name));
|
||||
ensure(pfn, "Failed to load vulkan global function: {}", fn_name);
|
||||
// log_trc("Loaded global function: {}", fn_name);
|
||||
// log::trace("Loaded global function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_create_instance, "vkCreateInstance");
|
||||
|
|
@ -283,7 +307,7 @@ void Instance::load_instance_functions()
|
|||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
pfn = reinterpret_cast<T>(vk_get_instance_proc_address(m_instance, fn_name));
|
||||
ensure(pfn, "Failed to load vulkan instance function: {}", fn_name);
|
||||
// log_trc("Loaded instance function: {}", fn_name);
|
||||
// log::trace("Loaded instance function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_destroy_instance, "vkDestroyInstance");
|
||||
|
|
@ -298,6 +322,7 @@ void Instance::load_instance_functions()
|
|||
load_fn(vk_destroy_device, "vkDestroyDevice");
|
||||
load_fn(vk_get_physical_device_features, "vkGetPhysicalDeviceFeatures");
|
||||
load_fn(vk_enumerate_device_extension_properties, "vkEnumerateDeviceExtensionProperties");
|
||||
load_fn(vk_get_physical_device_memory_properties, "vkGetPhysicalDeviceMemoryProperties");
|
||||
|
||||
load_fn(vk_cmd_begin_debug_label, "vkCmdBeginDebugUtilsLabelEXT");
|
||||
load_fn(vk_cmd_end_debug_label, "vkCmdEndDebugUtilsLabelEXT");
|
||||
|
|
@ -327,7 +352,7 @@ void Instance::load_device_functions_impl(VkDevice device)
|
|||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
pfn = reinterpret_cast<T>(vk_get_device_proc_address(device, fn_name));
|
||||
ensure(pfn, "Failed to load vulkan device function: {}", fn_name);
|
||||
// log_trc("Loaded device function: {}", fn_name);
|
||||
// log::trace("Loaded device function: {}", fn_name);
|
||||
};
|
||||
|
||||
load_fn(vk_get_device_queue, "vkGetDeviceQueue");
|
||||
|
|
@ -370,7 +395,26 @@ void Instance::load_device_functions_impl(VkDevice device)
|
|||
load_fn(vk_cmd_draw, "vkCmdDraw");
|
||||
load_fn(vk_cmd_set_viewport, "vkCmdSetViewport");
|
||||
load_fn(vk_cmd_set_scissors, "vkCmdSetScissor");
|
||||
load_fn(vk_cmd_push_constants, "vkCmdPushConstants");
|
||||
load_fn(vk_cmd_copy_buffer, "vkCmdCopyBuffer");
|
||||
load_fn(vk_create_descriptor_set_layout, "vkCreateDescriptorSetLayout");
|
||||
load_fn(vk_destroy_descriptor_set_layout, "vkDestroyDescriptorSetLayout");
|
||||
load_fn(vk_create_descriptor_pool, "vkCreateDescriptorPool");
|
||||
load_fn(vk_destroy_descriptor_pool, "vkDestroyDescriptorPool");
|
||||
load_fn(vk_allocate_descriptor_sets, "vkAllocateDescriptorSets");
|
||||
load_fn(vk_free_descriptor_sets, "vkFreeDescriptorSets");
|
||||
load_fn(vk_create_buffer, "vkCreateBuffer");
|
||||
load_fn(vk_destroy_buffer, "vkDestroyBuffer");
|
||||
load_fn(vk_allocate_memory, "vkAllocateMemory");
|
||||
load_fn(vk_bind_buffer_memory, "vkBindBufferMemory");
|
||||
load_fn(vk_map_memory, "vkMapMemory");
|
||||
load_fn(vk_unmap_memory, "vkUnmapMemory");
|
||||
load_fn(vk_free_memory, "vkFreeMemory");
|
||||
load_fn(vk_get_buffer_memory_requirements, "vkGetBufferMemoryRequirements");
|
||||
load_fn(vk_reset_command_buffer, "vkResetCommandBuffer");
|
||||
|
||||
load_fn(vk_cmd_begin_rendering, "vkCmdBeginRendering");
|
||||
load_fn(vk_cmd_end_rendering, "vkCmdEndRendering");
|
||||
}
|
||||
|
||||
auto Instance::enumerate_gpus() const -> std::vector<VkPhysicalDevice>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <ranges>
|
||||
#include <renderer/backend/vk/context/device.hpp>
|
||||
#include <renderer/backend/vk/context/gpu.hpp>
|
||||
|
|
@ -95,8 +96,8 @@ Swapchain::~Swapchain()
|
|||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
log_err("Failed to destroy swapchain:");
|
||||
log_err("\twhat: {}", exp.what());
|
||||
log::error("Failed to destroy swapchain:");
|
||||
log::error("\twhat: {}", exp.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,17 @@ public:
|
|||
return m_images.size();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_image_view(uint32_t idx) -> VkImageView
|
||||
{
|
||||
return m_image_views[idx];
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_image(uint32_t idx) -> VkImage
|
||||
{
|
||||
return m_images[idx];
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] auto create_framebuffers_for_pass(VkRenderPass pass) const
|
||||
-> std::vector<VkFramebuffer>;
|
||||
|
||||
|
|
|
|||
106
modules/renderer/private/backend/vk/data/buffer.cpp
Normal file
106
modules/renderer/private/backend/vk/data/buffer.cpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#include <renderer/backend/vk/context/device.hpp>
|
||||
#include <renderer/backend/vk/context/gpu.hpp>
|
||||
#include <renderer/backend/vk/data/buffer.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
Buffer::Buffer(IDevice *device, IGpu *gpu, const CreateInfo &info)
|
||||
: m_device(static_cast<Device *>(device))
|
||||
, m_gpu(static_cast<Gpu *>(gpu))
|
||||
, m_buffer(
|
||||
m_device,
|
||||
VkBufferCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = info.size,
|
||||
.usage = to_native_usage_flags(info.usage),
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
}
|
||||
)
|
||||
, m_memory(m_device, m_buffer, determine_allocation_info(info.usage))
|
||||
, m_size(info.size)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Buffer::map() -> std::span<std::byte> /* override */
|
||||
{
|
||||
return m_device->map_memory(m_memory, m_size, 0ul);
|
||||
}
|
||||
|
||||
void Buffer::unmap() /* override */
|
||||
{
|
||||
m_device->unmap_memory(m_memory);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Buffer::determine_allocation_info(Usage usage) const -> VkMemoryAllocateInfo
|
||||
{
|
||||
const auto requirements = m_device->get_memory_requirements(m_buffer);
|
||||
auto memory_properties = m_gpu->get_memory_properties();
|
||||
|
||||
const auto required_properties = to_native_memory_properties(usage);
|
||||
auto type = 0u;
|
||||
for (auto idx = 0; idx < memory_properties.memoryTypeCount; ++idx)
|
||||
{
|
||||
const auto property_flags = memory_properties.memoryTypes[idx].propertyFlags;
|
||||
if (has_correct_memory_type_bit(requirements.memoryTypeBits, idx)
|
||||
&& has_required_memory_properties(required_properties, property_flags))
|
||||
|
||||
{
|
||||
type = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return VkMemoryAllocateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = requirements.size,
|
||||
.memoryTypeIndex = type,
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Buffer::to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags
|
||||
{
|
||||
switch (usage)
|
||||
{
|
||||
case Usage::vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
|
||||
case Usage::index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
|
||||
case Usage::storage:
|
||||
return VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
|
||||
case Usage::staging: return VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
}
|
||||
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Buffer::to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags
|
||||
{
|
||||
switch (usage)
|
||||
{
|
||||
case Usage::vertex:
|
||||
case Usage::index:
|
||||
case Usage::storage: return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
|
||||
case Usage::staging:
|
||||
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
}
|
||||
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Buffer::has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const
|
||||
-> bool
|
||||
{
|
||||
return type_bits & (1 << type_idx);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto Buffer::has_required_memory_properties(
|
||||
uint32_t required_properties,
|
||||
uint32_t property_flags
|
||||
) const -> bool
|
||||
{
|
||||
return (property_flags & required_properties) == required_properties;
|
||||
}
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
60
modules/renderer/private/backend/vk/data/buffer.hpp
Normal file
60
modules/renderer/private/backend/vk/data/buffer.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <renderer/backend/vk/raii/raii.hpp>
|
||||
#include <renderer/frontend/data/buffer.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Buffer: public IBuffer
|
||||
{
|
||||
public:
|
||||
Buffer(class IDevice *device, class IGpu *gpu, const CreateInfo &info);
|
||||
|
||||
[[nodiscard]] auto map() -> std::span<std::byte> override;
|
||||
|
||||
void unmap() override;
|
||||
|
||||
// TODO(Light): this is to make copying possible.
|
||||
// But it should be removed in the future,
|
||||
// Right now it's not possible because: buffers can't understand CommandBuffers.
|
||||
// And I'm not sure how to properly abstract over command buffers,
|
||||
// before using other APIs...
|
||||
[[nodiscard]] auto vk()
|
||||
{
|
||||
return *m_buffer;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_size() const -> size_t override
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] auto determine_allocation_info(Usage usage) const -> VkMemoryAllocateInfo;
|
||||
|
||||
[[nodiscard]] auto to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags;
|
||||
|
||||
[[nodiscard]] auto to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags;
|
||||
|
||||
|
||||
[[nodiscard]] auto has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const
|
||||
-> bool;
|
||||
|
||||
[[nodiscard]] auto has_required_memory_properties(
|
||||
uint32_t required_properties,
|
||||
uint32_t property_flags
|
||||
) const -> bool;
|
||||
|
||||
Device *m_device {};
|
||||
|
||||
Gpu *m_gpu {};
|
||||
|
||||
raii::Buffer m_buffer;
|
||||
|
||||
raii::Memory m_memory;
|
||||
|
||||
// TODO(Light): should this reflect the allocation size instead?
|
||||
size_t m_size {};
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
9
modules/renderer/private/backend/vk/data/descriptors.hpp
Normal file
9
modules/renderer/private/backend/vk/data/descriptors.hpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
class Descriptors
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace lt::renderer::vk
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
#include <logger/logger.hpp>
|
||||
#include <renderer/backend/vk/messenger.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
|
@ -42,8 +43,8 @@ Messenger::Messenger(IInstance *instance, CreateInfo info)
|
|||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
log_err("Uncaught exception in messenger callback:");
|
||||
log_err("\twhat: {}", exp.what());
|
||||
log::error("Uncaught exception in messenger callback:");
|
||||
log::error("\twhat: {}", exp.what());
|
||||
}
|
||||
|
||||
return VK_FALSE;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
#include <memory/pointer_types/null_on_move.hpp>
|
||||
#include <renderer/backend/vk/context/device.hpp>
|
||||
#include <renderer/backend/vk/context/instance.hpp>
|
||||
#include <renderer/backend/vk/vulkan.hpp>
|
||||
|
||||
|
||||
namespace lt::renderer::vk::raii {
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
|
||||
class DebugMessenger
|
||||
{
|
||||
public:
|
||||
|
|
@ -16,13 +17,19 @@ public:
|
|||
|
||||
~DebugMessenger()
|
||||
{
|
||||
if (!m_instance)
|
||||
if (m_instance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_instance->destroy_messenger(m_object);
|
||||
}
|
||||
}
|
||||
|
||||
DebugMessenger(DebugMessenger &&) = default;
|
||||
|
||||
DebugMessenger(const DebugMessenger &) = delete;
|
||||
|
||||
auto operator=(DebugMessenger &&) -> DebugMessenger & = default;
|
||||
|
||||
auto operator=(const DebugMessenger &) -> DebugMessenger & = delete;
|
||||
|
||||
private:
|
||||
memory::NullOnMove<Instance *> m_instance {};
|
||||
|
|
@ -30,4 +37,88 @@ private:
|
|||
VkDebugUtilsMessengerEXT m_object;
|
||||
};
|
||||
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
Buffer(Device *device, VkBufferCreateInfo info)
|
||||
: m_device(device)
|
||||
, m_object(m_device->create_buffer(info))
|
||||
{
|
||||
}
|
||||
|
||||
~Buffer()
|
||||
{
|
||||
if (m_device)
|
||||
{
|
||||
m_device->destroy_buffer(m_object);
|
||||
}
|
||||
}
|
||||
|
||||
Buffer(Buffer &&) = default;
|
||||
|
||||
Buffer(const Buffer &) = delete;
|
||||
|
||||
auto operator=(Buffer &&) -> Buffer & = default;
|
||||
|
||||
auto operator=(const Buffer &) -> Buffer & = delete;
|
||||
|
||||
[[nodiscard]] auto operator*() const -> VkBuffer
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
[[nodiscard]] operator VkBuffer() const
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
private:
|
||||
memory::NullOnMove<Device *> m_device {};
|
||||
|
||||
VkBuffer m_object;
|
||||
};
|
||||
|
||||
class Memory
|
||||
{
|
||||
public:
|
||||
Memory(Device *device, VkBuffer buffer, VkMemoryAllocateInfo info)
|
||||
: m_device(device)
|
||||
, m_object(m_device->allocate_memory(info))
|
||||
{
|
||||
m_device->bind_memory(buffer, m_object);
|
||||
}
|
||||
|
||||
~Memory()
|
||||
{
|
||||
if (m_device)
|
||||
{
|
||||
m_device->free_memory(m_object);
|
||||
}
|
||||
}
|
||||
|
||||
Memory(Memory &&) = default;
|
||||
|
||||
Memory(const Memory &) = delete;
|
||||
|
||||
auto operator=(Memory &&) -> Memory & = default;
|
||||
|
||||
auto operator=(const Memory &) -> Memory & = delete;
|
||||
|
||||
[[nodiscard]] auto operator*() const -> VkDeviceMemory
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
[[nodiscard]] operator VkDeviceMemory() const
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
private:
|
||||
memory::NullOnMove<Device *> m_device {};
|
||||
|
||||
VkDeviceMemory m_object = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt::renderer::vk::raii
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <renderer/backend/vk/context/device.hpp>
|
||||
#include <renderer/backend/vk/context/swapchain.hpp>
|
||||
#include <renderer/backend/vk/renderer/pass.hpp>
|
||||
#include <renderer/data/frame_constants.hpp>
|
||||
|
||||
namespace lt::renderer::vk {
|
||||
|
||||
|
|
@ -11,16 +12,85 @@ Pass::Pass(
|
|||
const lt::assets::ShaderAsset &fragment_shader
|
||||
)
|
||||
: m_device(static_cast<Device *>(device))
|
||||
, m_layout(m_device->create_pipeline_layout(
|
||||
VkPipelineLayoutCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 0u,
|
||||
.pSetLayouts = nullptr,
|
||||
.pushConstantRangeCount = 0u,
|
||||
.pPushConstantRanges = nullptr,
|
||||
}
|
||||
))
|
||||
{
|
||||
auto binding = VkDescriptorSetLayoutBinding {
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = 1'000,
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
};
|
||||
|
||||
const auto descriptor_binding_flags = VkDescriptorBindingFlagsEXT {
|
||||
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT
|
||||
| VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT
|
||||
| VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT
|
||||
| VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT,
|
||||
};
|
||||
|
||||
constexpr auto descriptor_count = uint32_t { 1'000 };
|
||||
|
||||
auto descriptor_binding_flags_info = VkDescriptorSetLayoutBindingFlagsCreateInfoEXT {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT,
|
||||
.bindingCount = 1,
|
||||
.pBindingFlags = &descriptor_binding_flags,
|
||||
};
|
||||
|
||||
|
||||
m_vertices_descriptor_set_layout = m_device->create_descriptor_set_layout(
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.pNext = &descriptor_binding_flags_info,
|
||||
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT,
|
||||
.bindingCount = 1u,
|
||||
.pBindings = &binding,
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
auto pool_size = VkDescriptorPoolSize {
|
||||
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
.descriptorCount = descriptor_count,
|
||||
};
|
||||
|
||||
m_descriptor_pool = m_device->create_desscriptor_pool(
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.poolSizeCount = 1u,
|
||||
.pPoolSizes = &pool_size,
|
||||
}
|
||||
);
|
||||
|
||||
auto descriptor_set_variable_descriptor_count_info
|
||||
= VkDescriptorSetVariableDescriptorCountAllocateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO,
|
||||
.descriptorSetCount = 1u,
|
||||
.pDescriptorCounts = &descriptor_count,
|
||||
};
|
||||
|
||||
m_vertices_descriptor_set = m_device->allocate_descriptor_set(
|
||||
VkDescriptorSetAllocateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||
.pNext = &descriptor_set_variable_descriptor_count_info,
|
||||
.descriptorPool = m_descriptor_pool,
|
||||
.descriptorSetCount = 1u,
|
||||
.pSetLayouts = &m_vertices_descriptor_set_layout,
|
||||
}
|
||||
);
|
||||
|
||||
m_layout = m_device->create_pipeline_layout(
|
||||
std::vector<VkDescriptorSetLayout> {
|
||||
m_vertices_descriptor_set_layout,
|
||||
},
|
||||
|
||||
std::vector<VkPushConstantRange> {
|
||||
VkPushConstantRange {
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||
.offset = 0u,
|
||||
.size = sizeof(FrameConstants),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
auto *vertex_module = create_module(
|
||||
vertex_shader.unpack(lt::assets::ShaderAsset::BlobTag::code)
|
||||
);
|
||||
|
|
@ -112,17 +182,16 @@ Pass::Pass(
|
|||
.blendConstants = { 0.0f, 0.0, 0.0, 0.0 },
|
||||
};
|
||||
|
||||
|
||||
auto attachment_description = VkAttachmentDescription {
|
||||
.format = static_cast<Swapchain *>(swapchain)->get_format(),
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
};
|
||||
// auto attachment_description = VkAttachmentDescription {
|
||||
// .format =,
|
||||
// .samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
// .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
// .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
// .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||
// .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||
// .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
// .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||
// };
|
||||
|
||||
auto color_attachment_ref = VkAttachmentReference {
|
||||
.attachment = 0,
|
||||
|
|
@ -144,21 +213,18 @@ Pass::Pass(
|
|||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
};
|
||||
|
||||
m_pass = m_device->create_pass(
|
||||
VkRenderPassCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
.attachmentCount = 1u,
|
||||
.pAttachments = &attachment_description,
|
||||
.subpassCount = 1u,
|
||||
.pSubpasses = &subpass_description,
|
||||
.dependencyCount = 1u,
|
||||
.pDependencies = &pass_dependency,
|
||||
}
|
||||
);
|
||||
auto color_format = static_cast<Swapchain *>(swapchain)->get_format();
|
||||
auto rendering_info = VkPipelineRenderingCreateInfoKHR {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
||||
.colorAttachmentCount = 1u,
|
||||
.pColorAttachmentFormats = &color_format,
|
||||
|
||||
};
|
||||
|
||||
m_pipeline = m_device->create_graphics_pipeline(
|
||||
VkGraphicsPipelineCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = &rendering_info,
|
||||
.stageCount = static_cast<uint32_t>(shader_stages.size()),
|
||||
.pStages = shader_stages.data(),
|
||||
.pVertexInputState = &vertex_input,
|
||||
|
|
@ -170,15 +236,14 @@ Pass::Pass(
|
|||
.pColorBlendState = &color_blend,
|
||||
.pDynamicState = &dynamic_state,
|
||||
.layout = m_layout,
|
||||
.renderPass = m_pass,
|
||||
.renderPass = VK_NULL_HANDLE,
|
||||
.subpass = 0u,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
.basePipelineIndex = -1,
|
||||
}
|
||||
);
|
||||
|
||||
m_framebuffers = static_cast<Swapchain *>(swapchain)->create_framebuffers_for_pass(m_pass);
|
||||
|
||||
// m_framebuffers = static_cast<Swapchain *>(swapchain)->create_framebuffers_for_pass(m_pass);
|
||||
|
||||
m_device->destroy_shader_module(vertex_module);
|
||||
m_device->destroy_shader_module(fragment_module);
|
||||
|
|
@ -192,9 +257,14 @@ Pass::~Pass()
|
|||
}
|
||||
|
||||
m_device->wait_idle();
|
||||
|
||||
m_device->destroy_descriptor_set_layout(m_vertices_descriptor_set_layout);
|
||||
m_device->free_descriptor_set(m_descriptor_pool, m_vertices_descriptor_set);
|
||||
m_device->destroy_descriptor_pool(m_descriptor_pool);
|
||||
|
||||
m_device->destroy_framebuffers(m_framebuffers);
|
||||
m_device->destroy_pipeline(m_pipeline);
|
||||
m_device->destroy_pass(m_pass);
|
||||
// m_device->destroy_pass(m_pass);
|
||||
m_device->destroy_pipeline_layout(m_layout);
|
||||
}
|
||||
|
||||
|
|
@ -207,7 +277,8 @@ void Pass::replace_swapchain(const ISwapchain &swapchain)
|
|||
|
||||
m_device->wait_idle();
|
||||
m_device->destroy_framebuffers(m_framebuffers);
|
||||
m_framebuffers = static_cast<const Swapchain &>(swapchain).create_framebuffers_for_pass(m_pass);
|
||||
// m_framebuffers = static_cast<const Swapchain
|
||||
// &>(swapchain).create_framebuffers_for_pass(m_pass);
|
||||
}
|
||||
|
||||
auto Pass::create_module(lt::assets::Blob blob) -> VkShaderModule
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue