Compare commits
23 commits
main
...
ci/build_m
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d02876d12 | |||
| a74e23051c | |||
| 9909f5c430 | |||
| 6ecb268196 | |||
| 144ca1aa4f | |||
| 3520ae36a6 | |||
| 57031ee44e | |||
| 90a1a06bbe | |||
| 9662f97095 | |||
| 8f12d76401 | |||
| cb5b97dddb | |||
| 253a8216a2 | |||
| bf2bf1e1a1 | |||
| f21e6450cd | |||
| d1caf1df5b | |||
| bcfbc5c1c1 | |||
| 48bf9eb033 | |||
| 1bdfa1fac0 | |||
| 8df6e7967f | |||
| 034a6c7537 | |||
| b1bca72f6f | |||
| 306b65df94 | |||
| e59b3b8d3a |
364 changed files with 53859 additions and 14451 deletions
5
.clangd
5
.clangd
|
|
@ -1,5 +0,0 @@
|
||||||
CompileFlags:
|
|
||||||
DriverMode: cl
|
|
||||||
Add:
|
|
||||||
- /EHsc
|
|
||||||
- /std:c++latest
|
|
||||||
101
.drone.yml
101
.drone.yml
|
|
@ -13,7 +13,7 @@ steps:
|
||||||
- name: unit tests
|
- name: unit tests
|
||||||
shell: powershell
|
shell: powershell
|
||||||
commands:
|
commands:
|
||||||
- ./tools/ci/amd64/msvc/unit_tests.ps1
|
- ./tools/ci/steps/amd64/msvc/unit-tests.ps1
|
||||||
|
|
||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
|
|
@ -25,16 +25,16 @@ trigger:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: unit tests
|
- name: unit tests
|
||||||
image: ci:latest
|
image: unit_tests:latest
|
||||||
pull: if-not-exists
|
pull: if-not-exists
|
||||||
commands:
|
commands:
|
||||||
- ./tools/ci/amd64/gcc/unit_tests.sh
|
- ./tools/ci/steps/amd64/gcc/unit-tests.sh
|
||||||
|
|
||||||
- name: valgrind
|
- name: valgrind
|
||||||
image: ci:latest
|
image: valgrind:latest
|
||||||
pull: if-not-exists
|
pull: if-not-exists
|
||||||
commands:
|
commands:
|
||||||
- ./tools/ci/amd64/gcc/valgrind.sh
|
- ./tools/ci/steps/amd64/gcc/valgrind.sh
|
||||||
|
|
||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
|
|
@ -45,26 +45,11 @@ trigger:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
steps:
|
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
|
- name: leak sanitizer
|
||||||
image: ci:latest
|
image: leak_sanitizer:latest
|
||||||
pull: if-not-exists
|
pull: if-not-exists
|
||||||
commands:
|
commands:
|
||||||
- ./tools/ci/amd64/clang/lsan.sh
|
- ./tools/ci/steps/amd64/clang/lsan.sh
|
||||||
|
|
||||||
- name: memory sanitizer
|
|
||||||
image: ci:latest
|
|
||||||
pull: if-not-exists
|
|
||||||
commands:
|
|
||||||
- ./tools/ci/amd64/clang/msan.sh
|
|
||||||
|
|
||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
|
|
@ -75,80 +60,24 @@ trigger:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: clang tidy
|
- name: static_analysis
|
||||||
image: ci:latest
|
image: static_analysis:latest
|
||||||
pull: if-not-exists
|
pull: if-not-exists
|
||||||
privileged: true
|
privileged: true
|
||||||
commands:
|
commands:
|
||||||
- ./tools/ci/static_analysis/clang_tidy.sh
|
- ./tools/ci/steps/static_analysis.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
|
kind: pipeline
|
||||||
type: docker
|
type: docker
|
||||||
name: documentation — development
|
name: style
|
||||||
node:
|
|
||||||
environment: ryali
|
|
||||||
trigger:
|
trigger:
|
||||||
branch:
|
branch:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build and deploy
|
- name: clang format
|
||||||
image: documentation:latest
|
image: clang_format:latest
|
||||||
pull: if-not-exists
|
pull: if-not-exists
|
||||||
commands:
|
commands:
|
||||||
- cd docs
|
- ./tools/ci/steps/style.sh
|
||||||
- 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,8 +1,16 @@
|
||||||
cmake_minimum_required(VERSION 3.14)
|
cmake_minimum_required(VERSION 3.14)
|
||||||
project(Light)
|
project(Light)
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
|
||||||
include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/functions.cmake)
|
include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/functions.cmake)
|
||||||
include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/definitions.cmake)
|
include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/definitions.cmake)
|
||||||
include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/options.cmake)
|
include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/dependencies.cmake)
|
||||||
|
|
||||||
|
add_option(ENABLE_STATIC_ANALYSIS "Performs static analysis via clang-tidy and fails build on failing checks")
|
||||||
|
if (ENABLE_STATIC_ANALYSIS)
|
||||||
|
set(CMAKE_CXX_CLANG_TIDY "clang-tidy;--warnings-as-errors=*;--allow-no-checks")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
add_option(ENABLE_TESTS "Enables the building of the test modules")
|
||||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/modules)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/modules)
|
||||||
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/external/glad)
|
||||||
|
|
|
||||||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
# 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.
|
||||||
|
|
@ -1,4 +1,2 @@
|
||||||
# Light
|
# Light
|
||||||
See docs.light7734.com for a comprehensive project documentation
|
See docs.light7734.com for a comprehensive project documentation
|
||||||
|
|
||||||
###### “No great thing comes into being all at once, any more than a cluster of grapes or a fig. If you tell me, 'I want a fig,' I will answer that it needs time. Let it flower first, then put forth its fruit and then ripen. I say then, if the fig tree's fruit is not brought to perfection suddenly in a single hour, would you expect to gather the fruit of a person’s mind so soon and so easily? I tell you, you must not expect it.” —Epictetus, Discourses 1.15.7-8
|
|
||||||
|
|
|
||||||
58
conanfile.py
Normal file
58
conanfile.py
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
from conan import ConanFile
|
||||||
|
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout
|
||||||
|
import shutil
|
||||||
|
import os
|
||||||
|
import git
|
||||||
|
|
||||||
|
class LightRecipe(ConanFile):
|
||||||
|
name = "Light Engine"
|
||||||
|
|
||||||
|
settings = "os", "compiler", "build_type", "arch"
|
||||||
|
generators = "CMakeDeps"
|
||||||
|
|
||||||
|
options = {
|
||||||
|
"enable_tests": [True, False],
|
||||||
|
"enable_static_analysis": [True, False],
|
||||||
|
"use_mold": [True, False],
|
||||||
|
"export_compile_commands": [True, False],
|
||||||
|
}
|
||||||
|
|
||||||
|
default_options = {
|
||||||
|
"enable_tests": True,
|
||||||
|
"enable_static_analysis": False,
|
||||||
|
"use_mold": False,
|
||||||
|
"export_compile_commands": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
def requirements(self):
|
||||||
|
self.requires("imgui/1.92.0-docking")
|
||||||
|
self.requires("entt/3.15.0")
|
||||||
|
self.requires("glfw/3.4")
|
||||||
|
self.requires("stb/cci.20240531")
|
||||||
|
self.requires("yaml-cpp/0.8.0")
|
||||||
|
self.requires("lz4/1.10.0")
|
||||||
|
|
||||||
|
def layout(self):
|
||||||
|
cmake_layout(self)
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
tc = CMakeToolchain(self)
|
||||||
|
|
||||||
|
tc.variables["CMAKE_BUILD_TYPE"] = self.settings.build_type
|
||||||
|
|
||||||
|
if self.options.use_mold:
|
||||||
|
tc.cache_variables["CMAKE_LINKER_TYPE"] = "MOLD"
|
||||||
|
|
||||||
|
tc.cache_variables["CMAKE_EXPORT_COMPILE_COMMANDS"] = self.options.export_compile_commands
|
||||||
|
tc.cache_variables["ENABLE_STATIC_ANALYSIS"] = self.options.enable_static_analysis
|
||||||
|
tc.cache_variables["ENABLE_TESTS"] = self.options.enable_tests
|
||||||
|
|
||||||
|
repo = git.Repo(search_parent_directories=True)
|
||||||
|
tc.cache_variables["GIT_HASH"] = repo.head.object.hexsha
|
||||||
|
|
||||||
|
tc.generate()
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
cmake = CMake(self)
|
||||||
|
cmake.configure()
|
||||||
|
cmake.build()
|
||||||
BIN
data/assets/shaders/quads/ps.asset
Normal file
BIN
data/assets/shaders/quads/ps.asset
Normal file
Binary file not shown.
10
data/assets/shaders/quads/ps.glsl
Normal file
10
data/assets/shaders/quads/ps.glsl
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#version 440 core
|
||||||
|
|
||||||
|
in vec4 vso_FragmentColor;
|
||||||
|
|
||||||
|
out vec4 fso_FragmentColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fso_FragmentColor = vso_FragmentColor;
|
||||||
|
}
|
||||||
BIN
data/assets/shaders/quads/vs.asset
Normal file
BIN
data/assets/shaders/quads/vs.asset
Normal file
Binary file not shown.
17
data/assets/shaders/quads/vs.glsl
Normal file
17
data/assets/shaders/quads/vs.glsl
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#version 440 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 a_Position;
|
||||||
|
layout(location = 1) in vec4 a_Color;
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform ub_ViewProjection
|
||||||
|
{
|
||||||
|
mat4 viewProjection;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 vso_FragmentColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = viewProjection * a_Position;
|
||||||
|
vso_FragmentColor = a_Color;
|
||||||
|
}
|
||||||
BIN
data/assets/shaders/texture/ps.asset
Normal file
BIN
data/assets/shaders/texture/ps.asset
Normal file
Binary file not shown.
12
data/assets/shaders/texture/ps.glsl
Normal file
12
data/assets/shaders/texture/ps.glsl
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
in vec2 vso_TexCoord;
|
||||||
|
|
||||||
|
uniform sampler2D u_Texture;
|
||||||
|
|
||||||
|
out vec4 fso_FragmentColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fso_FragmentColor = texture(u_Texture, vso_TexCoord);
|
||||||
|
}
|
||||||
BIN
data/assets/shaders/texture/vs.asset
Normal file
BIN
data/assets/shaders/texture/vs.asset
Normal file
Binary file not shown.
19
data/assets/shaders/texture/vs.glsl
Normal file
19
data/assets/shaders/texture/vs.glsl
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 a_Position;
|
||||||
|
layout(location = 1) in vec2 a_TexCoord;
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform ub_ViewProjection
|
||||||
|
{
|
||||||
|
mat4 u_ViewProjection;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 vso_TexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = u_ViewProjection * a_Position;
|
||||||
|
|
||||||
|
vso_TexCoord = a_TexCoord;
|
||||||
|
}
|
||||||
|
|
||||||
BIN
data/assets/shaders/tinted_texture/ps.asset
Normal file
BIN
data/assets/shaders/tinted_texture/ps.asset
Normal file
Binary file not shown.
14
data/assets/shaders/tinted_texture/ps.glsl
Normal file
14
data/assets/shaders/tinted_texture/ps.glsl
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
in vec4 vso_Tint;
|
||||||
|
in vec2 vso_TexCoord;
|
||||||
|
|
||||||
|
uniform sampler2D u_Texture;
|
||||||
|
|
||||||
|
out vec4 fso_FragmentColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fso_FragmentColor = texture(u_Texture, vso_TexCoord) * vso_Tint;
|
||||||
|
}
|
||||||
|
|
||||||
BIN
data/assets/shaders/tinted_texture/vs.asset
Normal file
BIN
data/assets/shaders/tinted_texture/vs.asset
Normal file
Binary file not shown.
21
data/assets/shaders/tinted_texture/vs.glsl
Normal file
21
data/assets/shaders/tinted_texture/vs.glsl
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 a_Position;
|
||||||
|
layout(location = 1) in vec4 a_Tint;
|
||||||
|
layout(location = 2) in vec2 a_TexCoord;
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform ub_ViewProjection
|
||||||
|
{
|
||||||
|
mat4 u_ViewProjection;
|
||||||
|
};
|
||||||
|
|
||||||
|
out vec4 vso_Tint;
|
||||||
|
out vec2 vso_TexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = u_ViewProjection * a_Position;
|
||||||
|
|
||||||
|
vso_Tint = a_Tint;
|
||||||
|
vso_TexCoord = a_TexCoord;
|
||||||
|
}
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
The quick brown fox jumps over the lazy dog
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
#version 450 core
|
|
||||||
|
|
||||||
layout(location = 0) in vec3 in_frag_color;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 out_frag_color;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
out_frag_color = vec4(in_frag_color, 1.0);
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
|
@ -1,26 +0,0 @@
|
||||||
#version 450 core
|
|
||||||
|
|
||||||
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(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 = view_projection * vec4(positions[gl_VertexIndex], 1.0);
|
|
||||||
out_frag_color = colors[gl_VertexIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
Binary file not shown.
48
default_gui_layout.ini
Normal file
48
default_gui_layout.ini
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
[Window][Dockspace]
|
||||||
|
Pos=0,0
|
||||||
|
Size=1595,720
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Debug##Default]
|
||||||
|
ViewportPos=2078,721
|
||||||
|
ViewportId=0x9F5F46A1
|
||||||
|
Size=848,1408
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Dear ImGui Demo]
|
||||||
|
Pos=836,24
|
||||||
|
Size=759,696
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000003,1
|
||||||
|
|
||||||
|
[Window][Hierarchy]
|
||||||
|
Pos=0,24
|
||||||
|
Size=184,696
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000001,0
|
||||||
|
|
||||||
|
[Window][Properties]
|
||||||
|
Pos=836,24
|
||||||
|
Size=759,696
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000003,0
|
||||||
|
|
||||||
|
[Window][Game]
|
||||||
|
Pos=186,24
|
||||||
|
Size=648,696
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000002,0
|
||||||
|
|
||||||
|
[Window][Content Browser]
|
||||||
|
ViewportPos=1359,621
|
||||||
|
ViewportId=0x371352B7
|
||||||
|
Size=1274,1296
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Docking][Data]
|
||||||
|
DockSpace ID=0x1ED03EE2 Window=0x5B816B74 Pos=516,375 Size=1595,696 Split=X
|
||||||
|
DockNode ID=0x00000006 Parent=0x1ED03EE2 SizeRef=834,696 Split=X
|
||||||
|
DockNode ID=0x00000001 Parent=0x00000006 SizeRef=184,696 Selected=0x29EABFBD
|
||||||
|
DockNode ID=0x00000002 Parent=0x00000006 SizeRef=648,696 CentralNode=1 Selected=0x26816F31
|
||||||
|
DockNode ID=0x00000003 Parent=0x1ED03EE2 SizeRef=759,696 Selected=0x199AB496
|
||||||
|
|
||||||
5
docs/.gitignore
vendored
5
docs/.gitignore
vendored
|
|
@ -1,5 +0,0 @@
|
||||||
_build/
|
|
||||||
generated/
|
|
||||||
html/
|
|
||||||
xml/
|
|
||||||
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
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
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
Application
|
|
||||||
===================================================================================================
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 3
|
|
||||||
:caption: App
|
|
||||||
|
|
||||||
Functions
|
|
||||||
---------------------------------------------------------------------------------------------------
|
|
||||||
.. doxygenfunction:: main
|
|
||||||
|
|
||||||
Classes
|
|
||||||
---------------------------------------------------------------------------------------------------
|
|
||||||
.. doxygenclass:: lt::app::ISystem
|
|
||||||
|
|
||||||
.. doxygenstruct:: lt::app::TickInfo
|
|
||||||
|
|
||||||
.. doxygenstruct:: lt::app::TickResult
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
Renderer
|
|
||||||
===================================================================================================
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 3
|
|
||||||
:caption: App
|
|
||||||
|
|
||||||
Classes
|
|
||||||
---------------------------------------------------------------------------------------------------
|
|
||||||
.. doxygenenum:: lt::renderer::Api
|
|
||||||
|
|
||||||
.. doxygenclass:: lt::renderer::System
|
|
||||||
|
|
||||||
.. doxygenstruct:: lt::renderer::components::Sprite
|
|
||||||
|
|
@ -1,72 +1,62 @@
|
||||||
Asset Management
|
Asset Management
|
||||||
===================================================================================================
|
===================================================================================================
|
||||||
|
Layout
|
||||||
On Disk (file) Layout
|
|
||||||
---------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------
|
||||||
|
{version} | 4 bytes, ie. uint32_t
|
||||||
.. code-block:: md
|
{general metadata} | sizeof(AssetMetadata)
|
||||||
|
{specialized metadata} | sizeof(XXXAssetMetadata), eg. TextureAssetMetadata
|
||||||
{version} | 4 bytes, ie. uint32_t
|
{n} | 4 bytes, ie. uint32_t
|
||||||
{general metadata} | sizeof(AssetMetadata)
|
{blob_0...n metadata} | n * sizeof(BlobMetadata)
|
||||||
{specialized metadata} | sizeof(XXXAssetMetadata), eg. TextureAssetMetadata
|
{blob_0...n data} | variable size based on actual data
|
||||||
{n} | 4 bytes, ie. uint32_t
|
{end marker} | 8 byte, ie size_t for marking the END
|
||||||
{blob_0...n metadata} | n * sizeof(BlobMetadata)
|
|
||||||
{blob_0...n data} | variable size based on actual data
|
|
||||||
{end marker} | 8 byte, ie size_t for marking the END
|
|
||||||
|
|
||||||
Sections
|
Sections
|
||||||
---------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------
|
||||||
|
version -> The version of the asset for forward compatibility
|
||||||
.. code-block:: md
|
general metadata -> Common asset metadata such as file-path, asset-type, creator, etc.
|
||||||
|
specialized metadata -> Metadata specific to the asset, eg. texture dimensions for Textures.
|
||||||
version -> The version of the asset for forward compatibility
|
n -> The number of blobs.
|
||||||
general metadata -> Common asset metadata such as file-path, asset-type, creator, etc.
|
blob_0...n metadata -> Metadata specifying how the actual data is packed, required for unpacking.
|
||||||
specialized metadata -> Metadata specific to the asset, eg. texture dimensions for Textures.
|
blob_0...n data -> The actual data, packed and compressed to be reacdy for direct engine consumption.
|
||||||
n -> The number of blobs.
|
|
||||||
blob_0...n metadata -> Metadata specifying how the actual data is packed, required for unpacking.
|
|
||||||
blob_0...n data -> The actual data, packed and compressed to be reacdy for direct engine consumption.
|
|
||||||
|
|
||||||
Loading
|
Loading
|
||||||
---------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------
|
||||||
Loading pre-baked asset files (like .png files) for baking:
|
Each `Loader` has ONE OR MORE supported input file types (detected via the file extension): eg. StbLoader -> Can read in .jpg, .png, .bmp, etc.... files
|
||||||
|
|
||||||
|
Each `Loader` has ONLY ONE supported output asset type:
|
||||||
Each **Loader** has ONE OR MORE supported input file types (detected via the file extension): eg. StbLoader -> Can read in .jpg, .png, .bmp, etc.... files
|
|
||||||
|
|
||||||
Each **Loader** has ONLY ONE supported output asset type:
|
|
||||||
eg. StbLoader -> outputs TextureAsset
|
eg. StbLoader -> outputs TextureAsset
|
||||||
|
|
||||||
Multiple **Loader**\s MAY have as output the same asset type:
|
Multiple `Loader`s MAY have as output the same asset type:
|
||||||
eg. StbLoader -> outputs TextureAsset
|
eg. StbLoader -> outputs TextureAsset
|
||||||
eg. SomeOtherImgLoader -> outputs TextureAsset
|
eg. SomeOtherImgLoader -> outputs TextureAsset
|
||||||
|
|
||||||
Multiple **Loader**\s SHOULD NOT have as input same extension types
|
Multiple `Loader`s SHOULD NOT have as input same extension types
|
||||||
eg. .jpg, .png -> if supported, should only be supported by 1 **Loader** class
|
eg. .jpg, .png -> if supported, should only be supported by 1 `Loader` class
|
||||||
|
|
||||||
Each **Loader** SHOULD read and turn the data from a file (eg. .png for textures) into something
|
Each `Loader` SHOULD read and turn the data from a file (eg. .png for textures) into something
|
||||||
understandable by a **Packer** (not the engine itself).
|
understandable by a `Packer` (not the engine itself).
|
||||||
|
|
||||||
A **Loader** SHOULD NOT be responsible for packing the parsed file data into asset data,
|
A `Loader` SHOULD NOT be responsible for packing the parsed file data into asset data,
|
||||||
as that implies direct understanding of the layout required by the engine.
|
as that implies direct understanding of the layout required by the engine.
|
||||||
|
|
||||||
And if that layout changes, ALL **Loader**s should change accordingly;
|
And if that layout changes, ALL `Loader`s should change accordingly;
|
||||||
which makes a class that's responsible for reading files dependant on the engine's (potentially frequent) internal changes.
|
which makes a class that's responsible for reading files dependant on the engine's (potentially frequent) internal changes.
|
||||||
The logic is to reduce many-to-one dependency into a one-to-one dependency by redirecting the packing process to **Packer** classes
|
The logic is to reduce many-to-one dependency into a one-to-one dependency by redirecting the packing process to `Packer` classes
|
||||||
|
|
||||||
Packing
|
Packing
|
||||||
---------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------
|
||||||
Each **Packer** is responsible for packing ONLY ONE asset type:
|
Each `Packer` is responsible for packing ONLY ONE asset type:
|
||||||
eg. TexturePacker for packing texture assets from parsed image files.
|
eg. TexturePacker for packing texture assets from parsed image files.
|
||||||
eg. ModelPacker for packing model assets from parsed model files.
|
eg. ModelPacker for packing model assets from parsed model files.
|
||||||
|
|
||||||
Each **Packer** will output ONE OR MORE blobs of data,
|
Each `Packer` will output ONE OR MORE blobs of data,
|
||||||
and for EACH blob of data, it'll write a BlobMetadata, AFTER the specialized metadata (eg. TextureAssetMetadata)
|
and for EACH blob of data, it'll write a BlobMetadata, AFTER the specialized metadata (eg. TextureAssetMetadata)
|
||||||
|
|
||||||
A **Packer** will make use of the **Compressor** classes to compress the data,
|
A `Packer` will make use of the `Compressor` classes to compress the data,
|
||||||
and lay it out in a way that is suitable for the engine's consumption.
|
and lay it out in a way that is suitable for the engine's consumption.
|
||||||
|
|
||||||
Unpacking
|
Unpacking
|
||||||
---------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------
|
||||||
A **Parser** is responsible for parsing ONLY ONE asset type:
|
A `Parser` is responsible for parsing ONLY ONE asset type:
|
||||||
eg. TextureParser for parsing texture assets for direct engine consumption.
|
eg. TextureParser for parsing texture assets for direct engine consumption.
|
||||||
eg. ModelParser for parsing model assets for direct engine consumption.
|
eg. ModelParser for parsing model assets for direct engine consumption.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
.. architecture/resources
|
|
||||||
|
|
||||||
Resource Management
|
Resource Management
|
||||||
|
|
||||||
===================================================================================================
|
===================================================================================================
|
||||||
|
|
||||||
|
|
|
||||||
35
docs/conf.py
35
docs/conf.py
|
|
@ -1,35 +0,0 @@
|
||||||
# Configuration file for the Sphinx documentation builder.
|
|
||||||
#
|
|
||||||
# For the full list of built-in configuration values, see the documentation:
|
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
|
||||||
|
|
||||||
project = 'light'
|
|
||||||
copyright = '2025, light7734'
|
|
||||||
author = 'light7734'
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
html_theme = 'sphinx_rtd_theme'
|
|
||||||
html_static_path = ['_static']
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
.. guidelines/conventions
|
|
||||||
|
|
||||||
Coding Conventions
|
|
||||||
===================================================================================================
|
|
||||||
Any line of code added to the engine, must abide by following conventions.
|
|
||||||
They may seem arbitrary, and sometimes they are. But to achieve **consistency**, which is not an arbitrary goal, is to
|
|
||||||
follow these guidelines.
|
|
||||||
|
|
||||||
AAA
|
|
||||||
--------------------
|
|
||||||
|
|
@ -1,147 +0,0 @@
|
||||||
.. guidelines/development
|
|
||||||
|
|
||||||
Development
|
|
||||||
===================================================================================================
|
|
||||||
As a solo-project, I am not only the **developer**, but also the **manager**.
|
|
||||||
Therefore there is a need, if this project is to succeed, to have a development plan.
|
|
||||||
|
|
||||||
Such a plan should:
|
|
||||||
|
|
||||||
- Define a way to **distribute work** (across time, since there's only 1 developer).
|
|
||||||
- Define what is a **unit of work** (cycles).
|
|
||||||
- Provide a way to **track productivity**, which helps projecting the future and **detecting patterns** early on.
|
|
||||||
- Provide a **pipeline** for the work to go through and **minimize ambiguity**.
|
|
||||||
|
|
||||||
These are the **management** aspects of the project, which help the development goals to be more **pragmatic**
|
|
||||||
---by pulling my mind out of its **engineering dreamland**, and make it focus on the **broader picture**.
|
|
||||||
|
|
||||||
Cycle
|
|
||||||
---------------------------------------------------------------------------------------------------
|
|
||||||
A cycle is one **step** in development, one cycle = one ticket, and it consists of 4 stages:
|
|
||||||
|
|
||||||
1 - Make it known
|
|
||||||
- Write the commit message.
|
|
||||||
- This limits the **scope of changes** and gives you a very specific **goal** to work towards.
|
|
||||||
- If something outside of this scope really bothers you, fix and stash for a future cycle.
|
|
||||||
- Make a ticket if stash-fix is implausible ---**DO NOT** write **todo** comments.
|
|
||||||
- The message should follow the project's **commit message specifications**.
|
|
||||||
|
|
||||||
- Make a ticket.
|
|
||||||
- Version control (git) is a **development-tool**, not a **management-tool**.
|
|
||||||
- Provide a very brief description ---This may be used in the commit message's body.
|
|
||||||
|
|
||||||
2 - Make it work
|
|
||||||
- Write high-level tests that confirms the cycle's requirements are met.
|
|
||||||
- That is, specify requirements in a programming language instead of English.
|
|
||||||
- You're done when all the tests pass.
|
|
||||||
- Preferably write the tests first, but it's okay to start with the interface.
|
|
||||||
- Tests may not be necessary depending on the requirements and commit type.
|
|
||||||
|
|
||||||
- "Make it work" doesn't mean liberally producing shit code, you should:
|
|
||||||
- Follow project's **conventions**.
|
|
||||||
- Follow **best practices** and **proven swe principles**.
|
|
||||||
- Enable **warnings as errors**.
|
|
||||||
- Enable **static analysis**.
|
|
||||||
- Don't break any pre-existing-tests.
|
|
||||||
- Have the over-all picture in mind.
|
|
||||||
|
|
||||||
3 - Make it right
|
|
||||||
- Test driven refactoring
|
|
||||||
- Now you have a better picture of how things relate and work.
|
|
||||||
- Switch to a TDD-style development to do the refactoring while following swe best-practices and proven-principles.
|
|
||||||
|
|
||||||
4 - Make it fast
|
|
||||||
- This is an engine, at the end of the day, **performance** is king.
|
|
||||||
- Get a performance and/or memory profile and try to alleviate the bottlenecks.
|
|
||||||
- Avoid premature optimizations, be certain what you change has performance benefits.
|
|
||||||
|
|
||||||
|
|
||||||
Sprint
|
|
||||||
---------------------------------------------------------------------------------------------------
|
|
||||||
A sprint is the collection of all the finished cycles in one week.
|
|
||||||
It's meant to provide insight on development speed and help projecting the future.
|
|
||||||
|
|
||||||
|
|
||||||
Commit Message Specification
|
|
||||||
---------------------------------------------------------------------------------------------------
|
|
||||||
The project follows the `Conventional Commits Specification <https://www.conventionalcommits.org/en/v1.0.0-beta.4>`_.
|
|
||||||
|
|
||||||
.. code-block:: md
|
|
||||||
|
|
||||||
<type>[optional scope]: <description>
|
|
||||||
|
|
||||||
[optional body]
|
|
||||||
|
|
||||||
[optional footer]
|
|
||||||
|
|
||||||
With the following commit types:
|
|
||||||
|
|
||||||
- feat
|
|
||||||
- For adding a new feature.
|
|
||||||
- Causes a **minor** bump in version.
|
|
||||||
|
|
||||||
- fix
|
|
||||||
- For changes that fix one or more bug.
|
|
||||||
- Causes a **patch** bump in version.
|
|
||||||
|
|
||||||
- refactor
|
|
||||||
- For non feat/fix changes that improve the implementation and/or the interface.
|
|
||||||
- Causes a **patch** bump in version.
|
|
||||||
|
|
||||||
- perf
|
|
||||||
- For changes that (hopefully) improve the performance.
|
|
||||||
- Causes a **patch** bump in version.
|
|
||||||
|
|
||||||
- build
|
|
||||||
- For changes that affect the build system or external dependencies.
|
|
||||||
- Causes a **patch** bump in version.
|
|
||||||
|
|
||||||
- asset
|
|
||||||
- For changes to the files under the ``/data`` directory.
|
|
||||||
- Causes a **patch** bump in version.
|
|
||||||
|
|
||||||
- test
|
|
||||||
- For adding missing tests or correcting the existing tests.
|
|
||||||
- Does not affect the version.
|
|
||||||
|
|
||||||
- chore
|
|
||||||
- For releases, .gitignore changes, deleting unused files, etc.
|
|
||||||
- Does not affect the version.
|
|
||||||
|
|
||||||
- ci
|
|
||||||
- For changes to our CI configuration files and scripts, including files under ``/tools/ci``.
|
|
||||||
- Does not affect the version.
|
|
||||||
|
|
||||||
- docs
|
|
||||||
- For changes to the documentations.
|
|
||||||
- Does not affect the version.
|
|
||||||
|
|
||||||
Semantic Versioning
|
|
||||||
---------------------------------------------------------------------------------------------------
|
|
||||||
Coupled with conventional commit style messages, we can automajically version the project following
|
|
||||||
the **Semantic Versioning 2.0.0** specifications.
|
|
||||||
|
|
||||||
The full version identifier consits of a version core (major.minor.patch) + label + hexsha of the commit.
|
|
||||||
Using the following format:
|
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: md
|
|
||||||
|
|
||||||
<major>.<minor>.<patch>-<label>+<short_hexsha>
|
|
||||||
|
|
||||||
eg.
|
|
||||||
0.8.1-kitten+ea898
|
|
||||||
0.5.0-kitten+01d85
|
|
||||||
1.5.0-akasha+7de53
|
|
||||||
|
|
||||||
kitten refers to all pre-release (1.0.0) versions
|
|
||||||
|
|
||||||
|
|
||||||
The shortened hexsha of a commit is obtained by:
|
|
||||||
``git rev-parse --short=5 <commit_hexsha>``
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
.. guidelines/philosophy
|
|
||||||
|
|
||||||
Philosophy
|
|
||||||
===================================================================================================
|
|
||||||
|
|
||||||
| **A theory or attitude that acts as a guiding principle for behaviour.**
|
|
||||||
| --- Oxford Languages
|
|
||||||
|
|
@ -1,32 +1,6 @@
|
||||||
.. light documentation
|
A bleeding-edge, cross-platform, cross-graphics-api, minimal-dependencies modern game-engine.
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
:caption: Light Engine
|
|
||||||
|
|
||||||
light/showcase.rst
|
|
||||||
light/features.rst
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
:caption: Software Architecture
|
|
||||||
|
|
||||||
architecture/assets.rst
|
|
||||||
architecture/resource.rst
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
:caption: Development Guidelines
|
|
||||||
|
|
||||||
guidelines/philosophy.rst
|
|
||||||
guidelines/development.rst
|
|
||||||
guidelines/conventions.rst
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 3
|
|
||||||
:caption: API
|
|
||||||
|
|
||||||
api/app.rst
|
|
||||||
api/renderer.rst
|
|
||||||
|
|
||||||
|
Supported Platforms: Windows, Mac, Linux, FreeBSD
|
||||||
|
Supported GraphicsAPIs: DirectX12-Ultimate, Vulkan 1.4, Metal, OpenGL 4.6
|
||||||
|
|
||||||
|
Dependencies: stdlib, meshoptimizer
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
.. light/features
|
|
||||||
|
|
||||||
Features
|
|
||||||
===================================================================================================
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
.. light/demos
|
|
||||||
|
|
||||||
Showcase
|
|
||||||
===================================================================================================
|
|
||||||
3
external/.clang-tidy
vendored
Normal file
3
external/.clang-tidy
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Disable all checks in this subdirectory
|
||||||
|
Checks: '-*'
|
||||||
|
|
||||||
3
external/glad/CMakeLists.txt
vendored
Normal file
3
external/glad/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
add_library(glad ${CMAKE_CURRENT_SOURCE_DIR}/src/gl.c)
|
||||||
|
target_include_directories(glad PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
target_link_libraries(glad PUBLIC opengl::opengl)
|
||||||
311
external/glad/include/KHR/khrplatform.h
vendored
Normal file
311
external/glad/include/KHR/khrplatform.h
vendored
Normal file
|
|
@ -0,0 +1,311 @@
|
||||||
|
#ifndef __khrplatform_h_
|
||||||
|
#define __khrplatform_h_
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
** copy of this software and/or associated documentation files (the
|
||||||
|
** "Materials"), to deal in the Materials without restriction, including
|
||||||
|
** without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||||
|
** permit persons to whom the Materials are furnished to do so, subject to
|
||||||
|
** the following conditions:
|
||||||
|
**
|
||||||
|
** The above copyright notice and this permission notice shall be included
|
||||||
|
** in all copies or substantial portions of the Materials.
|
||||||
|
**
|
||||||
|
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Khronos platform-specific types and definitions.
|
||||||
|
*
|
||||||
|
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||||
|
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||||
|
* The last semantic modification to khrplatform.h was at commit ID:
|
||||||
|
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||||
|
*
|
||||||
|
* Adopters may modify this file to suit their platform. Adopters are
|
||||||
|
* encouraged to submit platform specific modifications to the Khronos
|
||||||
|
* group so that they can be included in future versions of this file.
|
||||||
|
* Please submit changes by filing pull requests or issues on
|
||||||
|
* the EGL Registry repository linked above.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* See the Implementer's Guidelines for information about where this file
|
||||||
|
* should be located on your system and for more details of its use:
|
||||||
|
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||||
|
*
|
||||||
|
* This file should be included as
|
||||||
|
* #include <KHR/khrplatform.h>
|
||||||
|
* by Khronos client API header files that use its types and defines.
|
||||||
|
*
|
||||||
|
* The types in khrplatform.h should only be used to define API-specific types.
|
||||||
|
*
|
||||||
|
* Types defined in khrplatform.h:
|
||||||
|
* khronos_int8_t signed 8 bit
|
||||||
|
* khronos_uint8_t unsigned 8 bit
|
||||||
|
* khronos_int16_t signed 16 bit
|
||||||
|
* khronos_uint16_t unsigned 16 bit
|
||||||
|
* khronos_int32_t signed 32 bit
|
||||||
|
* khronos_uint32_t unsigned 32 bit
|
||||||
|
* khronos_int64_t signed 64 bit
|
||||||
|
* khronos_uint64_t unsigned 64 bit
|
||||||
|
* khronos_intptr_t signed same number of bits as a pointer
|
||||||
|
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||||
|
* khronos_ssize_t signed size
|
||||||
|
* khronos_usize_t unsigned size
|
||||||
|
* khronos_float_t signed 32 bit floating point
|
||||||
|
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||||
|
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||||
|
* nanoseconds
|
||||||
|
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||||
|
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||||
|
* only be used as a base type when a client API's boolean type is
|
||||||
|
* an enum. Client APIs which use an integer or other type for
|
||||||
|
* booleans cannot use this as the base type for their boolean.
|
||||||
|
*
|
||||||
|
* Tokens defined in khrplatform.h:
|
||||||
|
*
|
||||||
|
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||||
|
*
|
||||||
|
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||||
|
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||||
|
*
|
||||||
|
* Calling convention macros defined in this file:
|
||||||
|
* KHRONOS_APICALL
|
||||||
|
* KHRONOS_APIENTRY
|
||||||
|
* KHRONOS_APIATTRIBUTES
|
||||||
|
*
|
||||||
|
* These may be used in function prototypes as:
|
||||||
|
*
|
||||||
|
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||||
|
* int arg1,
|
||||||
|
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||||
|
# define KHRONOS_STATIC 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APICALL
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This precedes the return type of the function in the function prototype.
|
||||||
|
*/
|
||||||
|
#if defined(KHRONOS_STATIC)
|
||||||
|
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||||
|
* header compatible with static linking. */
|
||||||
|
# define KHRONOS_APICALL
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
# define KHRONOS_APICALL __declspec(dllimport)
|
||||||
|
#elif defined (__SYMBIAN32__)
|
||||||
|
# define KHRONOS_APICALL IMPORT_C
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||||
|
#else
|
||||||
|
# define KHRONOS_APICALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APIENTRY
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This follows the return type of the function and precedes the function
|
||||||
|
* name in the function prototype.
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||||
|
/* Win32 but not WinCE */
|
||||||
|
# define KHRONOS_APIENTRY __stdcall
|
||||||
|
#else
|
||||||
|
# define KHRONOS_APIENTRY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* Definition of KHRONOS_APIATTRIBUTES
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
* This follows the closing parenthesis of the function prototype arguments.
|
||||||
|
*/
|
||||||
|
#if defined (__ARMCC_2__)
|
||||||
|
#define KHRONOS_APIATTRIBUTES __softfp
|
||||||
|
#else
|
||||||
|
#define KHRONOS_APIATTRIBUTES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* basic type definitions
|
||||||
|
*-----------------------------------------------------------------------*/
|
||||||
|
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using <stdint.h>
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
/*
|
||||||
|
* To support platform where unsigned long cannot be used interchangeably with
|
||||||
|
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
|
||||||
|
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
|
||||||
|
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
|
||||||
|
* unsigned long long or similar (this results in different C++ name mangling).
|
||||||
|
* To avoid changes for existing platforms, we restrict usage of intptr_t to
|
||||||
|
* platforms where the size of a pointer is larger than the size of long.
|
||||||
|
*/
|
||||||
|
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
|
||||||
|
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
|
||||||
|
#define KHRONOS_USE_INTPTR_T
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__VMS ) || defined(__sgi)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using <inttypes.h>
|
||||||
|
*/
|
||||||
|
#include <inttypes.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Win32
|
||||||
|
*/
|
||||||
|
typedef __int32 khronos_int32_t;
|
||||||
|
typedef unsigned __int32 khronos_uint32_t;
|
||||||
|
typedef __int64 khronos_int64_t;
|
||||||
|
typedef unsigned __int64 khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif defined(__sun__) || defined(__digital__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sun or Digital
|
||||||
|
*/
|
||||||
|
typedef int khronos_int32_t;
|
||||||
|
typedef unsigned int khronos_uint32_t;
|
||||||
|
#if defined(__arch64__) || defined(_LP64)
|
||||||
|
typedef long int khronos_int64_t;
|
||||||
|
typedef unsigned long int khronos_uint64_t;
|
||||||
|
#else
|
||||||
|
typedef long long int khronos_int64_t;
|
||||||
|
typedef unsigned long long int khronos_uint64_t;
|
||||||
|
#endif /* __arch64__ */
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#elif 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hypothetical platform with no float or int64 support
|
||||||
|
*/
|
||||||
|
typedef int khronos_int32_t;
|
||||||
|
typedef unsigned int khronos_uint32_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 0
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 0
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic fallback
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef int32_t khronos_int32_t;
|
||||||
|
typedef uint32_t khronos_uint32_t;
|
||||||
|
typedef int64_t khronos_int64_t;
|
||||||
|
typedef uint64_t khronos_uint64_t;
|
||||||
|
#define KHRONOS_SUPPORT_INT64 1
|
||||||
|
#define KHRONOS_SUPPORT_FLOAT 1
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types that are (so far) the same on all platforms
|
||||||
|
*/
|
||||||
|
typedef signed char khronos_int8_t;
|
||||||
|
typedef unsigned char khronos_uint8_t;
|
||||||
|
typedef signed short int khronos_int16_t;
|
||||||
|
typedef unsigned short int khronos_uint16_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||||
|
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||||
|
* to be the only LLP64 architecture in current use.
|
||||||
|
*/
|
||||||
|
#ifdef KHRONOS_USE_INTPTR_T
|
||||||
|
typedef intptr_t khronos_intptr_t;
|
||||||
|
typedef uintptr_t khronos_uintptr_t;
|
||||||
|
#elif defined(_WIN64)
|
||||||
|
typedef signed long long int khronos_intptr_t;
|
||||||
|
typedef unsigned long long int khronos_uintptr_t;
|
||||||
|
#else
|
||||||
|
typedef signed long int khronos_intptr_t;
|
||||||
|
typedef unsigned long int khronos_uintptr_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN64)
|
||||||
|
typedef signed long long int khronos_ssize_t;
|
||||||
|
typedef unsigned long long int khronos_usize_t;
|
||||||
|
#else
|
||||||
|
typedef signed long int khronos_ssize_t;
|
||||||
|
typedef unsigned long int khronos_usize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KHRONOS_SUPPORT_FLOAT
|
||||||
|
/*
|
||||||
|
* Float type
|
||||||
|
*/
|
||||||
|
typedef float khronos_float_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if KHRONOS_SUPPORT_INT64
|
||||||
|
/* Time types
|
||||||
|
*
|
||||||
|
* These types can be used to represent a time interval in nanoseconds or
|
||||||
|
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||||
|
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||||
|
* time the system booted). The Unadjusted System Time is an unsigned
|
||||||
|
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||||
|
* may be either signed or unsigned.
|
||||||
|
*/
|
||||||
|
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||||
|
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dummy value used to pad enum types to 32 bits.
|
||||||
|
*/
|
||||||
|
#ifndef KHRONOS_MAX_ENUM
|
||||||
|
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enumerated boolean type
|
||||||
|
*
|
||||||
|
* Values other than zero should be considered to be true. Therefore
|
||||||
|
* comparisons should not be made against KHRONOS_TRUE.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
KHRONOS_FALSE = 0,
|
||||||
|
KHRONOS_TRUE = 1,
|
||||||
|
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||||
|
} khronos_boolean_enum_t;
|
||||||
|
|
||||||
|
#endif /* __khrplatform_h_ */
|
||||||
8319
external/glad/include/glad/gl.h
vendored
Normal file
8319
external/glad/include/glad/gl.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
7841
external/glad/include/glad/vulkan.h
vendored
Normal file
7841
external/glad/include/glad/vulkan.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
84
external/glad/include/vk_platform.h
vendored
Normal file
84
external/glad/include/vk_platform.h
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
/* */
|
||||||
|
/* File: vk_platform.h */
|
||||||
|
/* */
|
||||||
|
/*
|
||||||
|
** Copyright 2014-2025 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef VK_PLATFORM_H_
|
||||||
|
#define VK_PLATFORM_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/*
|
||||||
|
***************************************************************************************************
|
||||||
|
* Platform-specific directives and type declarations
|
||||||
|
***************************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Platform-specific calling convention macros.
|
||||||
|
*
|
||||||
|
* Platforms should define these so that Vulkan clients call Vulkan commands
|
||||||
|
* with the same calling conventions that the Vulkan implementation expects.
|
||||||
|
*
|
||||||
|
* VKAPI_ATTR - Placed before the return type in function declarations.
|
||||||
|
* Useful for C++11 and GCC/Clang-style function attribute syntax.
|
||||||
|
* VKAPI_CALL - Placed after the return type in function declarations.
|
||||||
|
* Useful for MSVC-style calling convention syntax.
|
||||||
|
* VKAPI_PTR - Placed between the '(' and '*' in function pointer types.
|
||||||
|
*
|
||||||
|
* Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void);
|
||||||
|
* Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void);
|
||||||
|
*/
|
||||||
|
#if defined(_WIN32)
|
||||||
|
/* On Windows, Vulkan commands use the stdcall convention */
|
||||||
|
#define VKAPI_ATTR
|
||||||
|
#define VKAPI_CALL __stdcall
|
||||||
|
#define VKAPI_PTR VKAPI_CALL
|
||||||
|
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
|
||||||
|
#error "Vulkan is not supported for the 'armeabi' NDK ABI"
|
||||||
|
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
|
||||||
|
/* On Android 32-bit ARM targets, Vulkan functions use the "hardfloat" */
|
||||||
|
/* calling convention, i.e. float parameters are passed in registers. This */
|
||||||
|
/* is true even if the rest of the application passes floats on the stack, */
|
||||||
|
/* as it does by default when compiling for the armeabi-v7a NDK ABI. */
|
||||||
|
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
|
||||||
|
#define VKAPI_CALL
|
||||||
|
#define VKAPI_PTR VKAPI_ATTR
|
||||||
|
#else
|
||||||
|
/* On other platforms, use the default calling convention */
|
||||||
|
#define VKAPI_ATTR
|
||||||
|
#define VKAPI_CALL
|
||||||
|
#define VKAPI_PTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(VK_NO_STDDEF_H)
|
||||||
|
#include <stddef.h>
|
||||||
|
#endif /* !defined(VK_NO_STDDEF_H) */
|
||||||
|
|
||||||
|
#if !defined(VK_NO_STDINT_H)
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||||
|
typedef signed __int8 int8_t;
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef signed __int16 int16_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef signed __int32 int32_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef signed __int64 int64_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
#endif /* !defined(VK_NO_STDINT_H) */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif
|
||||||
17892
external/glad/src/gl.c
vendored
Normal file
17892
external/glad/src/gl.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
5537
external/glad/src/vulkan.c
vendored
Normal file
5537
external/glad/src/vulkan.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,37 +1,25 @@
|
||||||
# engine add_subdirectory(./std)
|
# engine
|
||||||
|
add_subdirectory(./base)
|
||||||
add_subdirectory(test)
|
|
||||||
|
|
||||||
add_subdirectory(./logger)
|
|
||||||
|
|
||||||
add_subdirectory(./bitwise)
|
|
||||||
|
|
||||||
add_subdirectory(./env)
|
|
||||||
|
|
||||||
add_subdirectory(./memory)
|
|
||||||
|
|
||||||
add_subdirectory(./time)
|
add_subdirectory(./time)
|
||||||
|
add_subdirectory(./logger)
|
||||||
add_subdirectory(./debug)
|
add_subdirectory(./debug)
|
||||||
|
|
||||||
add_subdirectory(./math)
|
add_subdirectory(./math)
|
||||||
|
|
||||||
add_subdirectory(./assets)
|
|
||||||
|
|
||||||
add_subdirectory(./asset_baker)
|
add_subdirectory(./asset_baker)
|
||||||
|
add_subdirectory(./asset_parser)
|
||||||
|
add_subdirectory(./asset_manager)
|
||||||
|
|
||||||
add_subdirectory(./camera)
|
add_subdirectory(./camera)
|
||||||
|
add_subdirectory(./input)
|
||||||
|
add_subdirectory(./ui)
|
||||||
|
|
||||||
add_subdirectory(./app)
|
add_subdirectory(./window)
|
||||||
|
add_subdirectory(./renderer)
|
||||||
add_subdirectory(./ecs)
|
add_subdirectory(./ecs)
|
||||||
|
|
||||||
add_subdirectory(./surface)
|
add_subdirectory(./app)
|
||||||
|
|
||||||
add_subdirectory(./input)
|
# apps
|
||||||
|
add_subdirectory(./mirror)
|
||||||
|
|
||||||
# add_subdirectory(./ui)
|
add_subdirectory(test)
|
||||||
|
|
||||||
# add_subdirectory(./renderer)
|
|
||||||
|
|
||||||
#
|
|
||||||
# add_subdirectory(./mirror)
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,21 @@
|
||||||
add_library_module(
|
add_library_module(app
|
||||||
NAME
|
application.cpp
|
||||||
app
|
layer.cpp
|
||||||
INTERFACES
|
layer_stack.cpp
|
||||||
application.cppm
|
)
|
||||||
system.cppm
|
|
||||||
SOURCES
|
|
||||||
entrypoint.cpp)
|
|
||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(app
|
||||||
app
|
PUBLIC
|
||||||
PUBLIC memory
|
renderer
|
||||||
PRIVATE lt_debug)
|
logger
|
||||||
|
ui
|
||||||
|
asset_parser
|
||||||
|
asset_manager
|
||||||
|
lt_debug
|
||||||
|
ecs
|
||||||
|
window
|
||||||
|
glad
|
||||||
|
time
|
||||||
|
opengl::opengl
|
||||||
|
EnTT::EnTT
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
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
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
203
modules/app/private/application.cpp
Normal file
203
modules/app/private/application.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
#include <app/application.hpp>
|
||||||
|
#include <app/layer.hpp>
|
||||||
|
#include <app/layer_stack.hpp>
|
||||||
|
#include <asset_manager/asset_manager.hpp>
|
||||||
|
#include <input/events/event.hpp>
|
||||||
|
#include <input/events/keyboard.hpp>
|
||||||
|
#include <input/events/window.hpp>
|
||||||
|
#include <input/input.hpp>
|
||||||
|
#include <lt_debug/assertions.hpp>
|
||||||
|
#include <ranges>
|
||||||
|
#include <renderer/blender.hpp>
|
||||||
|
#include <renderer/graphics_context.hpp>
|
||||||
|
#include <renderer/render_command.hpp>
|
||||||
|
#include <renderer/renderer.hpp>
|
||||||
|
#include <ui/ui.hpp>
|
||||||
|
#include <window/window.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
Application *Application::s_instance = nullptr;
|
||||||
|
|
||||||
|
Application::Application(): m_window(nullptr)
|
||||||
|
{
|
||||||
|
ensure(!s_instance, "Application constructed twice");
|
||||||
|
s_instance = this;
|
||||||
|
|
||||||
|
m_window = Window::create([this](auto &&PH1) { on_event(std::forward<decltype(PH1)>(PH1)); });
|
||||||
|
|
||||||
|
// create graphics context
|
||||||
|
m_graphics_context = GraphicsContext::create(
|
||||||
|
GraphicsAPI::OpenGL,
|
||||||
|
(GLFWwindow *)m_window->get_handle()
|
||||||
|
);
|
||||||
|
|
||||||
|
AssetManager::load_shader(
|
||||||
|
"LT_ENGINE_RESOURCES_TEXTURE_SHADER",
|
||||||
|
"data/assets/shaders/texture/vs.asset",
|
||||||
|
"data/assets/shaders/texture/ps.asset"
|
||||||
|
);
|
||||||
|
|
||||||
|
AssetManager::load_shader(
|
||||||
|
"LT_ENGINE_RESOURCES_TINTED_TEXTURE_SHADER",
|
||||||
|
"data/assets/shaders/tinted_texture/vs.asset",
|
||||||
|
"data/assets/shaders/tinted_texture/ps.asset"
|
||||||
|
);
|
||||||
|
|
||||||
|
AssetManager::load_shader(
|
||||||
|
"LT_ENGINE_RESOURCES_QUAD_SHADER",
|
||||||
|
"data/assets/shaders/quads/vs.asset",
|
||||||
|
"data/assets/shaders/quads/ps.asset"
|
||||||
|
);
|
||||||
|
|
||||||
|
m_renderer = Renderer::create(
|
||||||
|
(GLFWwindow *)m_window->get_handle(),
|
||||||
|
lt::GraphicsContext::get_shared_context(),
|
||||||
|
Renderer::CreateInfo {
|
||||||
|
.quad_renderer_shader = AssetManager::get_shader("LT_ENGINE_RESOURCES_QUAD_SHADER"),
|
||||||
|
.texture_renderer_shader = AssetManager::get_shader(
|
||||||
|
"LT_ENGINE_RESOURCES_TEXTURE_SHADER"
|
||||||
|
),
|
||||||
|
.tinted_texture_renderer_shader = AssetManager::get_shader(
|
||||||
|
"LT_ENGINE_RESOURCES_TINTED_"
|
||||||
|
"TEXTURE_SHADER"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
ensure(m_graphics_context, "lWindow::lWindow: failed to create 'GraphicsContext'");
|
||||||
|
|
||||||
|
m_user_interface = UserInterface::create(
|
||||||
|
(GLFWwindow *)m_window->get_handle(),
|
||||||
|
lt::GraphicsContext::get_shared_context()
|
||||||
|
);
|
||||||
|
|
||||||
|
m_layer_stack = create_scope<LayerStack>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::~Application()
|
||||||
|
{
|
||||||
|
/** This is required to make forward-declarations possible:
|
||||||
|
* https://stackoverflow.com/questions/34072862/why-is-error-invalid-application-of-sizeof-to-an-incomplete-type-using-uniqu
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::game_loop()
|
||||||
|
{
|
||||||
|
m_window->set_visibility(true);
|
||||||
|
|
||||||
|
while (!m_window->is_closed())
|
||||||
|
{
|
||||||
|
update_layers();
|
||||||
|
render_layers();
|
||||||
|
render_user_interface();
|
||||||
|
poll_events();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::quit()
|
||||||
|
{
|
||||||
|
s_instance->m_window->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::update_layers()
|
||||||
|
{
|
||||||
|
for (auto &it : *m_layer_stack)
|
||||||
|
{
|
||||||
|
// narrowing double -> float
|
||||||
|
it->on_update(static_cast<float>(m_timer.elapsed_time().count()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(Light): each layer should have their own "delta time"
|
||||||
|
m_timer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::render_layers()
|
||||||
|
{
|
||||||
|
m_renderer->begin_frame();
|
||||||
|
|
||||||
|
for (auto &it : *m_layer_stack)
|
||||||
|
{
|
||||||
|
it->on_render();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_renderer->end_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::render_user_interface()
|
||||||
|
{
|
||||||
|
m_user_interface->begin();
|
||||||
|
|
||||||
|
for (auto &it : *m_layer_stack)
|
||||||
|
{
|
||||||
|
it->on_user_interface_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_user_interface->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::poll_events()
|
||||||
|
{
|
||||||
|
m_window->poll_events();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::on_event(const Event &event)
|
||||||
|
{
|
||||||
|
// window
|
||||||
|
if (event.has_category(WindowEventCategory))
|
||||||
|
{
|
||||||
|
m_window->on_event(event);
|
||||||
|
|
||||||
|
if (event.get_event_type() == EventType::WindowResized)
|
||||||
|
{
|
||||||
|
m_renderer->on_window_resize(dynamic_cast<const WindowResizedEvent &>(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// input
|
||||||
|
if (event.has_category(InputEventCategory))
|
||||||
|
{
|
||||||
|
Input::instance().on_event(event);
|
||||||
|
|
||||||
|
if (!Input::instance().is_receiving_game_events())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &it : std::ranges::reverse_view(*m_layer_stack))
|
||||||
|
{
|
||||||
|
if (it->on_event(event))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto Application::sanity_check() const -> bool
|
||||||
|
{
|
||||||
|
log_inf("Checking application sanity...");
|
||||||
|
ensure(s_instance, "Application not constructed!?");
|
||||||
|
ensure(m_window, "Window is not initialized");
|
||||||
|
ensure(m_user_interface, "User interface is not initialized");
|
||||||
|
ensure(m_graphics_context, "Graphics context is not initialized");
|
||||||
|
ensure(m_renderer, "Renderer is not initialized");
|
||||||
|
ensure(m_layer_stack, "Layer_stack is not initialized");
|
||||||
|
ensure(!m_layer_stack->is_empty(), "Layer_stack is empty");
|
||||||
|
|
||||||
|
log_inf("Logging application state...");
|
||||||
|
this->log_debug_data();
|
||||||
|
m_graphics_context->log_debug_data();
|
||||||
|
m_user_interface->log_debug_data();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::log_debug_data() const
|
||||||
|
{
|
||||||
|
log_inf("Platform::");
|
||||||
|
log_inf(" Platform name: {}", constants::platform_name);
|
||||||
|
log_inf(" Platform identifier: {}", std::to_underlying(constants::platform));
|
||||||
|
log_inf(" CWD: {}", std::filesystem::current_path().generic_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
47
modules/app/private/layer.cpp
Normal file
47
modules/app/private/layer.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include <app/layer.hpp>
|
||||||
|
#include <input/events/char.hpp>
|
||||||
|
#include <input/events/event.hpp>
|
||||||
|
#include <input/events/keyboard.hpp>
|
||||||
|
#include <input/events/mouse.hpp>
|
||||||
|
#include <input/events/window.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
Layer::Layer(std::string name): m_layer_name(std::move(name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Layer::on_event(const Event &event) -> bool
|
||||||
|
{
|
||||||
|
switch (event.get_event_type())
|
||||||
|
{
|
||||||
|
case EventType::MouseMoved: return on_mouse_moved(dynamic_cast<const MouseMovedEvent &>(event));
|
||||||
|
case EventType::ButtonPressed:
|
||||||
|
return on_button_pressed(dynamic_cast<const ButtonPressedEvent &>(event));
|
||||||
|
case EventType::ButtonReleased:
|
||||||
|
return on_button_released(dynamic_cast<const ButtonReleasedEvent &>(event));
|
||||||
|
case EventType::WheelScrolled:
|
||||||
|
return on_wheel_scrolled(dynamic_cast<const WheelScrolledEvent &>(event));
|
||||||
|
|
||||||
|
case EventType::KeyPressed: return on_key_pressed(dynamic_cast<const KeyPressedEvent &>(event));
|
||||||
|
case EventType::KeyRepeated: return on_key_repeat(dynamic_cast<const KeyRepeatEvent &>(event));
|
||||||
|
case EventType::KeyReleased:
|
||||||
|
return on_key_released(dynamic_cast<const KeyReleasedEvent &>(event));
|
||||||
|
case EventType::SetChar: return on_set_char(dynamic_cast<const SetCharEvent &>(event));
|
||||||
|
|
||||||
|
case EventType::WindowClosed:
|
||||||
|
return on_window_closed(dynamic_cast<const WindowClosedEvent &>(event));
|
||||||
|
case EventType::WindowResized:
|
||||||
|
return on_window_resized(dynamic_cast<const WindowResizedEvent &>(event));
|
||||||
|
case EventType::WindowMoved:
|
||||||
|
return on_window_moved(dynamic_cast<const WindowMovedEvent &>(event));
|
||||||
|
case EventType::WindowLostFocus:
|
||||||
|
return on_window_lost_focus(dynamic_cast<const WindowLostFocusEvent &>(event));
|
||||||
|
case EventType::WindowGainFocus:
|
||||||
|
return on_window_gain_focus(dynamic_cast<const WindowGainFocusEvent &>(event));
|
||||||
|
|
||||||
|
default: ensure(false, "Invalid event: {}", event.get_info_lt_log());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
18
modules/app/private/layer_stack.cpp
Normal file
18
modules/app/private/layer_stack.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include <app/layer.hpp>
|
||||||
|
#include <app/layer_stack.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
void LayerStack::attach_layer(Ref<Layer> layer)
|
||||||
|
{
|
||||||
|
log_trc("Attaching layer [{}]", layer->get_name());
|
||||||
|
m_layers.emplace_back(std::move(layer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayerStack::detach_layer(const Ref<Layer> &layer)
|
||||||
|
{
|
||||||
|
log_trc("Detaching layer [{}]", layer->get_name());
|
||||||
|
m_layers.erase(std::find(m_layers.begin(), m_layers.end(), layer));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
77
modules/app/public/application.hpp
Normal file
77
modules/app/public/application.hpp
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <time/timer.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
class Renderer;
|
||||||
|
class Window;
|
||||||
|
class Event;
|
||||||
|
class GraphicsContext;
|
||||||
|
class UserInterface;
|
||||||
|
class LayerStack;
|
||||||
|
|
||||||
|
extern Scope<class Application> create_application();
|
||||||
|
|
||||||
|
class Application
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Application(const Application &) = delete;
|
||||||
|
|
||||||
|
Application(Application &&) = delete;
|
||||||
|
|
||||||
|
auto operator=(const Application &) -> Application & = delete;
|
||||||
|
|
||||||
|
auto operator=(Application &&) -> Application & = delete;
|
||||||
|
|
||||||
|
virtual ~Application();
|
||||||
|
|
||||||
|
[[nodiscard]] auto sanity_check() const -> bool;
|
||||||
|
|
||||||
|
void game_loop();
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_window() -> Window &
|
||||||
|
{
|
||||||
|
return *m_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_layer_stack() -> LayerStack &
|
||||||
|
{
|
||||||
|
return *m_layer_stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void quit();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Application();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void update_layers();
|
||||||
|
|
||||||
|
void render_layers();
|
||||||
|
|
||||||
|
void render_user_interface();
|
||||||
|
|
||||||
|
void poll_events();
|
||||||
|
|
||||||
|
void on_event(const Event &event);
|
||||||
|
|
||||||
|
void log_debug_data() const;
|
||||||
|
|
||||||
|
Timer m_timer;
|
||||||
|
|
||||||
|
Scope<Window> m_window;
|
||||||
|
|
||||||
|
Scope<UserInterface> m_user_interface;
|
||||||
|
|
||||||
|
Scope<GraphicsContext> m_graphics_context;
|
||||||
|
|
||||||
|
Scope<Renderer> m_renderer;
|
||||||
|
|
||||||
|
Scope<LayerStack> m_layer_stack;
|
||||||
|
|
||||||
|
static Application *s_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
27
modules/app/public/entrypoint.hpp
Normal file
27
modules/app/public/entrypoint.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <app/application.hpp>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) // NOLINT
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::ignore = argc;
|
||||||
|
std::ignore = argv;
|
||||||
|
|
||||||
|
auto application = lt::Scope<lt::Application> {};
|
||||||
|
|
||||||
|
application = lt::create_application();
|
||||||
|
|
||||||
|
lt::ensure(application, "Failed to create application");
|
||||||
|
lt::ensure(application->sanity_check(), "Failed to verify the sanity of the application");
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
116
modules/app/public/layer.hpp
Normal file
116
modules/app/public/layer.hpp
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
class Event;
|
||||||
|
|
||||||
|
class MouseMovedEvent;
|
||||||
|
class ButtonPressedEvent;
|
||||||
|
class ButtonReleasedEvent;
|
||||||
|
class WheelScrolledEvent;
|
||||||
|
class KeyPressedEvent;
|
||||||
|
class KeyRepeatEvent;
|
||||||
|
class KeyReleasedEvent;
|
||||||
|
class SetCharEvent;
|
||||||
|
class WindowClosedEvent;
|
||||||
|
class WindowResizedEvent;
|
||||||
|
class WindowMovedEvent;
|
||||||
|
class WindowLostFocusEvent;
|
||||||
|
class WindowGainFocusEvent;
|
||||||
|
|
||||||
|
class Layer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Layer(std::string name);
|
||||||
|
|
||||||
|
virtual ~Layer() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_name() const -> const std::string &
|
||||||
|
{
|
||||||
|
return m_layer_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void on_update(float deltaTime)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void on_user_interface_update()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void on_render()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
auto on_event(const Event &event) -> bool;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string m_layer_name;
|
||||||
|
|
||||||
|
virtual auto on_mouse_moved(const MouseMovedEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_button_pressed(const ButtonPressedEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_button_released(const ButtonReleasedEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_wheel_scrolled(const WheelScrolledEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_key_pressed(const KeyPressedEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_key_repeat(const KeyRepeatEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_key_released(const KeyReleasedEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_set_char(const SetCharEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_window_closed(const WindowClosedEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_window_resized(const WindowResizedEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_window_moved(const WindowMovedEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_window_lost_focus(const WindowLostFocusEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual auto on_window_gain_focus(const WindowGainFocusEvent & /*event*/) -> bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
50
modules/app/public/layer_stack.hpp
Normal file
50
modules/app/public/layer_stack.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
class Layer;
|
||||||
|
class Event;
|
||||||
|
|
||||||
|
class LayerStack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename Layer_T, typename... Args>
|
||||||
|
void emplace_layer(Args &&...args)
|
||||||
|
{
|
||||||
|
attach_layer(create_ref<Layer_T>(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
void attach_layer(Ref<Layer> layer);
|
||||||
|
|
||||||
|
void detach_layer(const Ref<Layer> &layer);
|
||||||
|
|
||||||
|
[[nodiscard]] auto is_empty() const -> bool
|
||||||
|
{
|
||||||
|
return m_layers.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto begin() -> std::vector<Ref<Layer>>::iterator
|
||||||
|
{
|
||||||
|
return m_layers.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto end() -> std::vector<Ref<Layer>>::iterator
|
||||||
|
{
|
||||||
|
return m_layers.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto rbegin() -> std::vector<Ref<Layer>>::reverse_iterator
|
||||||
|
{
|
||||||
|
return m_layers.rbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto rend() -> std::vector<Ref<Layer>>::reverse_iterator
|
||||||
|
{
|
||||||
|
return m_layers.rend();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Ref<Layer>> m_layers;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
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)
|
|
||||||
*/
|
|
||||||
export struct TickInfo
|
|
||||||
{
|
|
||||||
using Timepoint_T = std::chrono::time_point<std::chrono::steady_clock>;
|
|
||||||
|
|
||||||
using Duration_T = std::chrono::duration<double>;
|
|
||||||
|
|
||||||
/** Duration since previous tick's end_time to current tick's start_time. */
|
|
||||||
Duration_T delta_time {};
|
|
||||||
|
|
||||||
/** Maximum duration the system is expected to finish ticking in.
|
|
||||||
*
|
|
||||||
* if end_time - start_time > budget -> the system exceeded its ticking budget.
|
|
||||||
* else end_time - start_time < budget -> the system ticked properly.
|
|
||||||
*
|
|
||||||
* In other words, end_time is expected to be less than start_time + budget.
|
|
||||||
*/
|
|
||||||
Duration_T budget {};
|
|
||||||
|
|
||||||
/** Exact time which ticking started. */
|
|
||||||
Timepoint_T start_time;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Information about how a system's tick performed */
|
|
||||||
export struct TickResult
|
|
||||||
{
|
|
||||||
using Timepoint_T = std::chrono::time_point<std::chrono::steady_clock>;
|
|
||||||
|
|
||||||
using Duration_T = std::chrono::duration<double>;
|
|
||||||
|
|
||||||
/** The info supplied to the system for ticking. */
|
|
||||||
TickInfo info;
|
|
||||||
|
|
||||||
/** Equivalent to end_time - info.start_time. */
|
|
||||||
Duration_T duration {};
|
|
||||||
|
|
||||||
/** Exact time which ticking ended. */
|
|
||||||
Timepoint_T end_time;
|
|
||||||
};
|
|
||||||
|
|
||||||
export struct SystemDiagnosis
|
|
||||||
{
|
|
||||||
enum class Severity : std::uint8_t
|
|
||||||
{
|
|
||||||
verbose,
|
|
||||||
info,
|
|
||||||
warning,
|
|
||||||
error,
|
|
||||||
fatal,
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string message;
|
|
||||||
|
|
||||||
std::string code;
|
|
||||||
|
|
||||||
Severity severity;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class SystemStats
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void push_diagnosis(SystemDiagnosis &&diagnosis)
|
|
||||||
{
|
|
||||||
auto diag = m_diagnosis.emplace_back(std::move(diagnosis));
|
|
||||||
|
|
||||||
log::debug("message: {}", diag.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto empty_diagnosis() const -> bool
|
|
||||||
{
|
|
||||||
return m_diagnosis.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<SystemDiagnosis> m_diagnosis;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class ISystem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ISystem() = default;
|
|
||||||
|
|
||||||
virtual ~ISystem() = default;
|
|
||||||
|
|
||||||
ISystem(ISystem &&) = default;
|
|
||||||
|
|
||||||
ISystem(const ISystem &) = delete;
|
|
||||||
|
|
||||||
auto operator=(ISystem &&) -> ISystem & = default;
|
|
||||||
|
|
||||||
auto operator=(const ISystem &) -> ISystem & = delete;
|
|
||||||
|
|
||||||
virtual void on_register() = 0;
|
|
||||||
|
|
||||||
virtual void on_unregister() = 0;
|
|
||||||
|
|
||||||
virtual void tick(TickInfo tick) = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_last_tick_result() const -> const TickResult & = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::app
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
add_library_module(NAME libasset_baker INTERFACES bakers.cppm)
|
add_executable_module(
|
||||||
target_link_libraries(libasset_baker PUBLIC assets logger lt_debug)
|
asset_baker entrypoint/baker.cpp
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(asset_baker entrypoint.cpp)
|
target_link_libraries(
|
||||||
target_link_libraries(asset_baker PRIVATE libasset_baker)
|
asset_baker
|
||||||
|
PRIVATE asset_parser
|
||||||
|
PRIVATE stb::stb
|
||||||
|
PRIVATE logger
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
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,44 +0,0 @@
|
||||||
import assets.shader;
|
|
||||||
import logger;
|
|
||||||
import bakers;
|
|
||||||
import std;
|
|
||||||
|
|
||||||
|
|
||||||
auto main(int argc, char *argv[]) -> std::int32_t
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (argc != 2)
|
|
||||||
{
|
|
||||||
throw std::logic_error("Argc should be 2 -- exe dir (implicit) and target dir");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &directory_iterator :
|
|
||||||
std::filesystem::recursive_directory_iterator(argv[1])) // NOLINT
|
|
||||||
{
|
|
||||||
if (directory_iterator.is_directory())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto &in_path = directory_iterator.path();
|
|
||||||
const auto out_path = std::format("{}.asset", in_path.c_str());
|
|
||||||
|
|
||||||
if (in_path.extension() == ".vert")
|
|
||||||
{
|
|
||||||
bake_shader(in_path, out_path, lt::assets::ShaderAsset::Type::vertex);
|
|
||||||
}
|
|
||||||
else if (in_path.extension() == ".frag")
|
|
||||||
{
|
|
||||||
bake_shader(in_path, out_path, lt::assets::ShaderAsset::Type::fragment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
catch (const std::exception &exp)
|
|
||||||
{
|
|
||||||
lt::log::critical("Terminating due to uncaught exception:");
|
|
||||||
lt::log::critical("\texception.what: {}:", exp.what());
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
100
modules/asset_baker/private/entrypoint/baker.cpp
Normal file
100
modules/asset_baker/private/entrypoint/baker.cpp
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
#include <asset_baker/bakers.hpp>
|
||||||
|
#include <asset_parser/assets/text.hpp>
|
||||||
|
#include <asset_parser/assets/texture.hpp>
|
||||||
|
#include <asset_parser/parser.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <logger/logger.hpp>
|
||||||
|
|
||||||
|
void try_packing_texture(
|
||||||
|
const std::filesystem::path &in_path,
|
||||||
|
const std::filesystem::path &out_path
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto texture_loader = lt::TextureLoaderFactory::create(in_path.extension().string());
|
||||||
|
if (!texture_loader)
|
||||||
|
{
|
||||||
|
// Don't log anything; this is expected.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Assets::TextureAsset::pack(texture_loader->load(in_path), out_path);
|
||||||
|
|
||||||
|
log_inf("Packed a texture asset:");
|
||||||
|
log_inf("\tloader : {}", texture_loader->get_name());
|
||||||
|
log_inf("\tin path: {}", in_path.string());
|
||||||
|
log_inf("\tout path: {}", out_path.string());
|
||||||
|
}
|
||||||
|
catch (const std::exception &exp)
|
||||||
|
{
|
||||||
|
log_err("Failed to pack texture asset:");
|
||||||
|
log_err("\tloader : {}", texture_loader->get_name());
|
||||||
|
log_err("\tin path : {}", in_path.string());
|
||||||
|
log_err("\tout path: {}", out_path.string());
|
||||||
|
log_err("\texp.what: {}", exp.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_packing_text(const std::filesystem::path &in_path, const std::filesystem::path &out_path)
|
||||||
|
{
|
||||||
|
auto text_loader = lt::TextLoaderFactory::create(in_path.extension().string());
|
||||||
|
if (!text_loader)
|
||||||
|
{
|
||||||
|
// Don't log anything; this is expected.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Assets::TextAsset::pack(text_loader->load(in_path), out_path);
|
||||||
|
|
||||||
|
log_inf("Packed a text asset:");
|
||||||
|
log_inf("\tloader : {}", text_loader->get_name());
|
||||||
|
log_inf("\tin path: {}", in_path.string());
|
||||||
|
log_inf("\tout path: {}", out_path.string());
|
||||||
|
}
|
||||||
|
catch (const std::exception &exp)
|
||||||
|
{
|
||||||
|
log_err("Failed to pack a text asset:");
|
||||||
|
log_err("\tloader : {}", text_loader->get_name());
|
||||||
|
log_err("\tin path : {}", in_path.string());
|
||||||
|
log_err("\tout path: {}", out_path.string());
|
||||||
|
log_err("\texp.what: {}", exp.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto main(int argc, char *argv[]) -> int32_t
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
throw std::logic_error("Argc should be 2 -- exe dir (implicit) and target dir");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &directory_iterator :
|
||||||
|
std::filesystem::recursive_directory_iterator(argv[1])) // NOLINT
|
||||||
|
{
|
||||||
|
if (directory_iterator.is_directory())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &in_path = directory_iterator.path();
|
||||||
|
|
||||||
|
auto out_path = in_path;
|
||||||
|
out_path.replace_extension(".asset");
|
||||||
|
|
||||||
|
try_packing_texture(in_path, out_path);
|
||||||
|
try_packing_text(in_path, out_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,63 +1,184 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <asset_parser/assets/text.hpp>
|
||||||
|
#include <asset_parser/assets/texture.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <logger/logger.hpp>
|
||||||
|
#include <string_view>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
inline void bake_shader(
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
const std::filesystem::path &in_path,
|
#include <stb_image.h>
|
||||||
const std::filesystem::path &out_path,
|
|
||||||
lt::assets::ShaderAsset::Type type
|
namespace lt {
|
||||||
)
|
|
||||||
|
class Loader
|
||||||
{
|
{
|
||||||
using lt::assets::ShaderAsset;
|
public:
|
||||||
using enum lt::assets::ShaderAsset::Type;
|
[[nodiscard]] virtual auto get_name() const -> std::string_view = 0;
|
||||||
|
|
||||||
auto glsl_path = in_path.string();
|
Loader() = default;
|
||||||
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.
|
Loader(Loader &&) = default;
|
||||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
|
||||||
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);
|
Loader(const Loader &) = delete;
|
||||||
lt::debug::ensure(
|
|
||||||
stream.is_open(),
|
|
||||||
"Failed to open compiled {} shader at: {}",
|
|
||||||
type == vertex ? "vert" : "frag",
|
|
||||||
spv_path
|
|
||||||
);
|
|
||||||
|
|
||||||
stream.seekg(0, std::ios::end);
|
auto operator=(Loader &&) -> Loader & = default;
|
||||||
const auto size = stream.tellg();
|
|
||||||
|
|
||||||
auto bytes = std::vector<std::byte>(size);
|
auto operator=(const Loader &) -> Loader & = delete;
|
||||||
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(
|
virtual ~Loader() = default;
|
||||||
out_path,
|
|
||||||
lt::assets::AssetMetadata {
|
private:
|
||||||
.version = lt::assets::current_version,
|
};
|
||||||
.type = ShaderAsset::asset_type_identifier,
|
|
||||||
},
|
class TextureLoader: public Loader
|
||||||
ShaderAsset::Metadata {
|
{
|
||||||
.type = type,
|
public:
|
||||||
},
|
TextureLoader() = default;
|
||||||
std::move(bytes)
|
|
||||||
);
|
[[nodiscard]] virtual auto load(std::filesystem::path file_path) const
|
||||||
}
|
-> Assets::TextureAsset::PackageData
|
||||||
|
= 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class StbLoader: public TextureLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StbLoader() = default;
|
||||||
|
|
||||||
|
void load(std::filesystem::path path);
|
||||||
|
|
||||||
|
[[nodiscard]] static auto get_supported_extensions() -> std::unordered_set<std::string_view>
|
||||||
|
{
|
||||||
|
return { ".png" };
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_name() const -> std::string_view override
|
||||||
|
{
|
||||||
|
return "StbLoader";
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto load(std::filesystem::path file_path) const
|
||||||
|
-> Assets::TextureAsset::PackageData override
|
||||||
|
{
|
||||||
|
auto width = int {};
|
||||||
|
auto height = int {};
|
||||||
|
auto channels = int {};
|
||||||
|
|
||||||
|
auto *pixels = stbi_load(file_path.string().c_str(), &width, &height, &channels, 4);
|
||||||
|
if (!pixels)
|
||||||
|
{
|
||||||
|
throw std::runtime_error {
|
||||||
|
std::format("Failed to load image file at: {} using stbi_load", file_path.string()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto metadata = Assets::Asset::Metadata {
|
||||||
|
.type = Assets::Asset::Type::Texture,
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto texture_metadata = Assets::TextureAsset::Metadata {
|
||||||
|
.format = Assets::TextureAsset::Format::RGBA8,
|
||||||
|
.num_components = static_cast<uint32_t>(channels),
|
||||||
|
.pixel_size = {
|
||||||
|
static_cast<uint32_t>(width),
|
||||||
|
static_cast<uint32_t>(height),
|
||||||
|
{},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
auto pixels_blob = Assets::Blob {};
|
||||||
|
pixels_blob.resize(static_cast<size_t>(width) * height * channels);
|
||||||
|
|
||||||
|
// TODO(Light): figure out if it's possible to directly populate a blob with stbi functions
|
||||||
|
memcpy(pixels_blob.data(), pixels, pixels_blob.size());
|
||||||
|
stbi_image_free(pixels);
|
||||||
|
|
||||||
|
return Assets::TextureAsset::PackageData {
|
||||||
|
.metadata = metadata,
|
||||||
|
.texture_metadata = texture_metadata,
|
||||||
|
.pixels = std::move(pixels_blob),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextureLoaderFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static auto create(std::string_view file_extension) -> std::unique_ptr<TextureLoader>
|
||||||
|
{
|
||||||
|
if (StbLoader::get_supported_extensions().contains(file_extension))
|
||||||
|
{
|
||||||
|
return std::make_unique<StbLoader>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextLoader: Loader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]] static auto get_supported_extensions() -> std::unordered_set<std::string_view>
|
||||||
|
{
|
||||||
|
return { ".glsl", ".txt", ".hlsl" };
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_name() const -> std::string_view override
|
||||||
|
{
|
||||||
|
return "TextLoader";
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto load(const std::filesystem::path &file_path) const
|
||||||
|
-> Assets::TextAsset::PackageData
|
||||||
|
{
|
||||||
|
auto stream = std::ifstream { file_path, std::ios::binary };
|
||||||
|
if (!stream.good())
|
||||||
|
{
|
||||||
|
throw std::runtime_error {
|
||||||
|
std::format(
|
||||||
|
"Failed to open ifstream for text loading of file: {}",
|
||||||
|
file_path.string()
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto file_size = std::filesystem::file_size(file_path);
|
||||||
|
|
||||||
|
auto text_blob = Assets::Blob(file_size);
|
||||||
|
|
||||||
|
stream.read((char *)(text_blob.data()), static_cast<long>(file_size)); // NOLINT
|
||||||
|
|
||||||
|
const auto metadata = Assets::Asset::Metadata {
|
||||||
|
.type = Assets::Asset::Type::Text,
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto text_metadata = Assets::TextAsset::Metadata {
|
||||||
|
.lines = {},
|
||||||
|
};
|
||||||
|
|
||||||
|
return Assets::TextAsset::PackageData {
|
||||||
|
.metadata = metadata,
|
||||||
|
.text_metadata = {},
|
||||||
|
.text_blob = std::move(text_blob),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextLoaderFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static auto create(std::string_view file_extension) -> std::unique_ptr<TextLoader>
|
||||||
|
{
|
||||||
|
if (TextLoader::get_supported_extensions().contains(file_extension))
|
||||||
|
{
|
||||||
|
return std::make_unique<TextLoader>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
|
|
|
||||||
9
modules/asset_manager/CMakeLists.txt
Normal file
9
modules/asset_manager/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
add_library_module(asset_manager
|
||||||
|
asset_manager.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
asset_manager
|
||||||
|
PUBLIC asset_parser
|
||||||
|
PRIVATE renderer
|
||||||
|
)
|
||||||
92
modules/asset_manager/private/asset_manager.cpp
Normal file
92
modules/asset_manager/private/asset_manager.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include <asset_manager/asset_manager.hpp>
|
||||||
|
#include <asset_parser/assets/text.hpp>
|
||||||
|
#include <asset_parser/assets/texture.hpp>
|
||||||
|
#include <logger/logger.hpp>
|
||||||
|
#include <renderer/graphics_context.hpp>
|
||||||
|
#include <renderer/shader.hpp>
|
||||||
|
#include <renderer/texture.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
/* static */ auto AssetManager::instance() -> AssetManager &
|
||||||
|
{
|
||||||
|
static auto instance = AssetManager {};
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetManager::load_shader_impl(
|
||||||
|
const std::string &name,
|
||||||
|
const std::filesystem::path &vertex_path,
|
||||||
|
const std::filesystem::path &pixel_path
|
||||||
|
)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
log_trc("Loading shader:");
|
||||||
|
log_trc("\tname : {}", name);
|
||||||
|
log_trc("\tvertex path: {}", vertex_path.string());
|
||||||
|
log_trc("\tpixel path : {}", pixel_path.string());
|
||||||
|
|
||||||
|
m_shaders[name] = Ref<Shader>(Shader::create(
|
||||||
|
get_or_load_text_asset(vertex_path.string()),
|
||||||
|
get_or_load_text_asset(pixel_path),
|
||||||
|
GraphicsContext::get_shared_context()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
catch (const std::exception &exp)
|
||||||
|
{
|
||||||
|
log_err("Failed to load shader:");
|
||||||
|
log_err("\tname : {}", name);
|
||||||
|
log_err("\tvertex path: {}", vertex_path.string());
|
||||||
|
log_err("\tpixel path : {}", pixel_path.string());
|
||||||
|
log_err("\texception : {}", exp.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetManager::load_texture_impl(const std::string &name, const std::filesystem::path &path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
log_trc("Loading texture:");
|
||||||
|
log_trc("\tname: {}", name);
|
||||||
|
log_trc("\tpath: {}", path.string());
|
||||||
|
|
||||||
|
m_textures[name] = Ref<Texture>(
|
||||||
|
Texture::create(get_or_load_texture_asset(path), GraphicsContext::get_shared_context())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (const std::exception &exp)
|
||||||
|
{
|
||||||
|
log_err("Failed to load texture:");
|
||||||
|
log_err("\tname : {}", name);
|
||||||
|
log_err("\tpath : {}", path.string());
|
||||||
|
log_err("\texception: {}", exp.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AssetManager::get_or_load_text_asset(const std::filesystem::path &path)
|
||||||
|
-> Ref<Assets::TextAsset>
|
||||||
|
{
|
||||||
|
const auto key = std::filesystem::canonical(path).string();
|
||||||
|
if (!m_text_assets.contains(key))
|
||||||
|
{
|
||||||
|
m_text_assets.emplace(key, create_ref<Assets::TextAsset>(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_text_assets[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto AssetManager::get_or_load_texture_asset(const std::filesystem::path &path)
|
||||||
|
-> Ref<Assets::TextureAsset>
|
||||||
|
{
|
||||||
|
const auto key = std::filesystem::canonical(path).string();
|
||||||
|
if (!m_texture_assets.contains(key))
|
||||||
|
{
|
||||||
|
m_texture_assets.emplace(key, create_ref<Assets::TextureAsset>(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_texture_assets[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
78
modules/asset_manager/public/asset_manager.hpp
Normal file
78
modules/asset_manager/public/asset_manager.hpp
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace Assets {
|
||||||
|
|
||||||
|
class TextAsset;
|
||||||
|
|
||||||
|
class TextureAsset;
|
||||||
|
|
||||||
|
} // namespace Assets
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
class Shader;
|
||||||
|
class Texture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asset is the data on the disk.
|
||||||
|
* Resource is the data on the gpu/cpu
|
||||||
|
*
|
||||||
|
* eg. TextureAsset is the file on the disk
|
||||||
|
* eg. Texture is the representation of it in the GPU
|
||||||
|
*/
|
||||||
|
class AssetManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void load_shader(
|
||||||
|
const std::string &name,
|
||||||
|
const std::filesystem::path &vertex_path,
|
||||||
|
const std::filesystem::path &pixel_path
|
||||||
|
)
|
||||||
|
{
|
||||||
|
instance().load_shader_impl(name, vertex_path, pixel_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_texture(const std::string &name, const std::filesystem::path &path)
|
||||||
|
{
|
||||||
|
instance().load_texture_impl(name, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto get_shader(const std::string &name) -> Ref<Shader>
|
||||||
|
{
|
||||||
|
return instance().m_shaders[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto get_texture(const std::string &name) -> Ref<Texture>
|
||||||
|
{
|
||||||
|
return instance().m_textures[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AssetManager() = default;
|
||||||
|
|
||||||
|
static auto instance() -> AssetManager &;
|
||||||
|
|
||||||
|
void load_shader_impl(
|
||||||
|
const std::string &name,
|
||||||
|
const std::filesystem::path &vertex_path,
|
||||||
|
const std::filesystem::path &pixel_path
|
||||||
|
);
|
||||||
|
|
||||||
|
void load_texture_impl(const std::string &name, const std::filesystem::path &path);
|
||||||
|
|
||||||
|
auto get_or_load_text_asset(const std::filesystem::path &path) -> Ref<Assets::TextAsset>;
|
||||||
|
|
||||||
|
auto get_or_load_texture_asset(const std::filesystem::path &path) -> Ref<Assets::TextureAsset>;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, Ref<Assets::TextAsset>> m_text_assets;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, Ref<Assets::TextureAsset>> m_texture_assets;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, Ref<Shader>> m_shaders;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, Ref<Texture>> m_textures;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
11
modules/asset_parser/CMakeLists.txt
Normal file
11
modules/asset_parser/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
add_library_module(asset_parser
|
||||||
|
parser.cpp
|
||||||
|
assets/texture.cpp
|
||||||
|
assets/text.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
asset_parser
|
||||||
|
PRIVATE LZ4::lz4_static
|
||||||
|
PRIVATE logger
|
||||||
|
)
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <asset_parser/assets/text.hpp>
|
#include <asset_parser/assets/text.hpp>
|
||||||
|
#include <lz4.h>
|
||||||
|
|
||||||
namespace Assets {
|
namespace Assets {
|
||||||
|
|
||||||
|
|
|
||||||
165
modules/asset_parser/private/assets/texture.cpp
Normal file
165
modules/asset_parser/private/assets/texture.cpp
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
#include <asset_parser/assets/texture.hpp>
|
||||||
|
#include <lz4.h>
|
||||||
|
|
||||||
|
namespace Assets {
|
||||||
|
|
||||||
|
/* static */ void TextureAsset::pack(const PackageData &data, const std::filesystem::path &out_path)
|
||||||
|
{
|
||||||
|
const auto &[metadata, texture_metadata, pixels] = data;
|
||||||
|
|
||||||
|
auto stream = std::ofstream { out_path, std::ios::binary | std::ios::trunc };
|
||||||
|
if (!stream.is_open())
|
||||||
|
{
|
||||||
|
throw std::runtime_error {
|
||||||
|
std::format("Failed to open ofstream for packing texture at: {}", out_path.string())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
stream.seekp(0);
|
||||||
|
|
||||||
|
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
stream.write((char *)¤t_version, sizeof(current_version));
|
||||||
|
|
||||||
|
stream.write((char *)&metadata, sizeof(metadata));
|
||||||
|
stream.write((char *)&texture_metadata, sizeof(texture_metadata));
|
||||||
|
|
||||||
|
constexpr auto number_of_blobs = uint32_t { 1 };
|
||||||
|
stream.write((char *)&number_of_blobs, sizeof(number_of_blobs));
|
||||||
|
|
||||||
|
auto pixels_metadata = BlobMetadata {
|
||||||
|
.tag = BlobMetadata::Tag::color,
|
||||||
|
.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
|
||||||
|
.compression_type = CompressionType::None,
|
||||||
|
.compressed_size = pixels.size(),
|
||||||
|
.uncompressed_size = pixels.size(),
|
||||||
|
};
|
||||||
|
|
||||||
|
stream.write((char *)&pixels_metadata, sizeof(pixels_metadata));
|
||||||
|
stream.write((char *)&pixels[0], static_cast<long>(pixels.size()));
|
||||||
|
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureAsset::TextureAsset(const std::filesystem::path &path)
|
||||||
|
{
|
||||||
|
m_stream = std::ifstream { path, std::ios::binary };
|
||||||
|
if (!m_stream.is_open())
|
||||||
|
{
|
||||||
|
throw std::runtime_error {
|
||||||
|
std::format("Failed to open ifstream for loading texture asset at: {}", path.string())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
m_stream.read((char *)&version, sizeof(version));
|
||||||
|
m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
|
||||||
|
m_stream.read((char *)&m_metadata, sizeof(m_metadata));
|
||||||
|
|
||||||
|
auto num_blobs = uint32_t {};
|
||||||
|
m_stream.read((char *)&num_blobs, sizeof(num_blobs));
|
||||||
|
if (num_blobs != 1)
|
||||||
|
{
|
||||||
|
throw std::runtime_error {
|
||||||
|
std::format("Failed to load texture asset: invalid number of blobs: {}", num_blobs)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stream.read((char *)&m_pixel_blob_metadata, sizeof(m_pixel_blob_metadata));
|
||||||
|
if (m_pixel_blob_metadata.tag != BlobMetadata::Tag::color)
|
||||||
|
{
|
||||||
|
throw std::runtime_error {
|
||||||
|
std::format(
|
||||||
|
"Failed to load texture asset: invalid blob tag, expected {}, got {}",
|
||||||
|
std::to_underlying(BlobMetadata::Tag::color),
|
||||||
|
std::to_underlying(m_pixel_blob_metadata.tag)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureAsset::unpack_blob(
|
||||||
|
BlobMetadata::Tag tag,
|
||||||
|
std::byte *destination,
|
||||||
|
size_t destination_capacity
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (tag != BlobMetadata::Tag::color)
|
||||||
|
{
|
||||||
|
throw std::runtime_error {
|
||||||
|
std::format("Invalid tag for unpack_blob of TextureAsset: {}", std::to_underlying(tag))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stream.seekg(static_cast<long>(m_pixel_blob_metadata.offset));
|
||||||
|
switch (m_pixel_blob_metadata.compression_type)
|
||||||
|
{
|
||||||
|
case Assets::CompressionType::None:
|
||||||
|
if (m_pixel_blob_metadata.uncompressed_size != m_pixel_blob_metadata.compressed_size)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Failed to unpack blob from TextureAsset: "
|
||||||
|
"compressed/uncompressed size mismatch for no compression "
|
||||||
|
"type"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pixel_blob_metadata.uncompressed_size > destination_capacity)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Failed to unpack blob from TextureAsset: "
|
||||||
|
"uncompressed_size > destination_capacity, unpacking "
|
||||||
|
"would result in segfault"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_stream.is_open())
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Failed to unpack blob from TextureAsset: ifstream is "
|
||||||
|
"closed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stream.read(
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
(char *)destination,
|
||||||
|
static_cast<long>(m_pixel_blob_metadata.uncompressed_size)
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::format(
|
||||||
|
"Failed to unpack blob from TextureAsset: unsupported "
|
||||||
|
"compression type: {}",
|
||||||
|
std::to_underlying(m_pixel_blob_metadata.compression_type)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto TextureAsset::get_asset_metadata() const -> const Asset::Metadata &
|
||||||
|
{
|
||||||
|
return m_asset_metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto TextureAsset::get_metadata() const -> const Metadata &
|
||||||
|
{
|
||||||
|
return m_metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto TextureAsset::get_blob_metadata(BlobMetadata::Tag tag) const
|
||||||
|
-> const BlobMetadata &
|
||||||
|
{
|
||||||
|
if (tag != BlobMetadata::Tag::color)
|
||||||
|
{
|
||||||
|
throw std::runtime_error { std::format(
|
||||||
|
"Invalid tag for get_blob_metadata of TextureAsset: {}",
|
||||||
|
std::to_underlying(tag)
|
||||||
|
) };
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_pixel_blob_metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Assets
|
||||||
62
modules/asset_parser/private/parser.cpp
Normal file
62
modules/asset_parser/private/parser.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
#include <asset_parser/parser.hpp>
|
||||||
|
#include <format>
|
||||||
|
#include <fstream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace Assets {
|
||||||
|
|
||||||
|
// void Asset::unpack(std::byte *destination)
|
||||||
|
// {
|
||||||
|
// if (!m_stream.is_open())
|
||||||
|
// {
|
||||||
|
// throw std::logic_error {
|
||||||
|
// "Failed to unpack asset: "
|
||||||
|
// "ifstream is closed",
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// switch (m_metadata.blob_compression_type)
|
||||||
|
// {
|
||||||
|
// case CompressionType::None:
|
||||||
|
// if (m_metadata.packed_size != m_metadata.unpacked_size)
|
||||||
|
// {
|
||||||
|
// throw std::logic_error {
|
||||||
|
// "Failed to unpack asset: "
|
||||||
|
// "compression type set to none but packed/unpacked sizes differ",
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// m_stream.read(
|
||||||
|
// std::bit_cast<char *>(destination),
|
||||||
|
// static_cast<long>(m_metadata.packed_size)
|
||||||
|
// );
|
||||||
|
// m_stream.close();
|
||||||
|
//
|
||||||
|
// case CompressionType::LZ4:
|
||||||
|
// m_stream.close();
|
||||||
|
// throw std::logic_error {
|
||||||
|
// "Failed to unpack asset: "
|
||||||
|
// "LZ4 compression is not implemented yet",
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// case CompressionType::LZ4HC:
|
||||||
|
// m_stream.close();
|
||||||
|
// throw std::logic_error {
|
||||||
|
// "Failed to unpack asset: "
|
||||||
|
// "LZ4HC compression is not implemented yet",
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// default:
|
||||||
|
// m_stream.close();
|
||||||
|
// throw std::logic_error {
|
||||||
|
// std::format(
|
||||||
|
// "Failed to unpack asset: "
|
||||||
|
// "Compression type was not recognized: {}",
|
||||||
|
// std::to_underlying(m_metadata.blob_compression_type)
|
||||||
|
// ),
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
} // namespace Assets
|
||||||
58
modules/asset_parser/public/assets/text.hpp
Normal file
58
modules/asset_parser/public/assets/text.hpp
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <asset_parser/compressors/compressors.hpp>
|
||||||
|
#include <asset_parser/parser.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <logger/logger.hpp>
|
||||||
|
|
||||||
|
namespace Assets {
|
||||||
|
|
||||||
|
class TextAsset: public Asset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Metadata
|
||||||
|
{
|
||||||
|
uint32_t lines {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Data required to pack a text asset */
|
||||||
|
struct PackageData
|
||||||
|
{
|
||||||
|
Asset::Metadata metadata;
|
||||||
|
|
||||||
|
Metadata text_metadata;
|
||||||
|
|
||||||
|
Blob text_blob;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pack(const PackageData &data, const std::filesystem::path &out_path);
|
||||||
|
|
||||||
|
TextAsset(const std::filesystem::path &path);
|
||||||
|
|
||||||
|
void unpack_blob(
|
||||||
|
BlobMetadata::Tag tag,
|
||||||
|
std::byte *destination,
|
||||||
|
size_t destination_capacity
|
||||||
|
) const;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_metadata() const -> const Metadata &;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t version {};
|
||||||
|
|
||||||
|
Asset::Metadata m_asset_metadata {};
|
||||||
|
|
||||||
|
Metadata m_metadata {};
|
||||||
|
|
||||||
|
BlobMetadata m_text_blob_metadata {};
|
||||||
|
|
||||||
|
mutable std::ifstream m_stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Assets
|
||||||
64
modules/asset_parser/public/assets/texture.hpp
Normal file
64
modules/asset_parser/public/assets/texture.hpp
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <asset_parser/compressors/compressors.hpp>
|
||||||
|
#include <asset_parser/parser.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <logger/logger.hpp>
|
||||||
|
|
||||||
|
namespace Assets {
|
||||||
|
|
||||||
|
class TextureAsset: public Asset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Format : uint32_t // NOLINT(performance-enum-size)
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
RGBA8,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Metadata
|
||||||
|
{
|
||||||
|
Format format;
|
||||||
|
|
||||||
|
uint32_t num_components;
|
||||||
|
|
||||||
|
std::array<uint32_t, 3> pixel_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Data required to pack a texture asset */
|
||||||
|
struct PackageData
|
||||||
|
{
|
||||||
|
Asset::Metadata metadata;
|
||||||
|
|
||||||
|
Metadata texture_metadata;
|
||||||
|
|
||||||
|
Blob pixels;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pack(const PackageData &data, const std::filesystem::path &out_path);
|
||||||
|
|
||||||
|
TextureAsset(const std::filesystem::path &path);
|
||||||
|
|
||||||
|
void unpack_blob(BlobMetadata::Tag tag, std::byte *destination, size_t destination_capacity);
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_metadata() const -> const Metadata &;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t version {};
|
||||||
|
|
||||||
|
Asset::Metadata m_asset_metadata {};
|
||||||
|
|
||||||
|
Metadata m_metadata {};
|
||||||
|
|
||||||
|
BlobMetadata m_pixel_blob_metadata {};
|
||||||
|
|
||||||
|
std::ifstream m_stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Assets
|
||||||
14
modules/asset_parser/public/compressors/compressors.hpp
Normal file
14
modules/asset_parser/public/compressors/compressors.hpp
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Assets {
|
||||||
|
|
||||||
|
enum class CompressionType : uint32_t // NOLINT(performance-enum-size)
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
LZ4,
|
||||||
|
LZ4HC,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
68
modules/asset_parser/public/parser.hpp
Normal file
68
modules/asset_parser/public/parser.hpp
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <asset_parser/compressors/compressors.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <logger/logger.hpp>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Assets {
|
||||||
|
|
||||||
|
constexpr auto current_version = uint32_t { 1 };
|
||||||
|
|
||||||
|
struct BlobMetadata
|
||||||
|
{
|
||||||
|
enum class Tag : uint8_t
|
||||||
|
{
|
||||||
|
text,
|
||||||
|
color,
|
||||||
|
depth,
|
||||||
|
vertices,
|
||||||
|
indices,
|
||||||
|
};
|
||||||
|
|
||||||
|
Tag tag;
|
||||||
|
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
CompressionType compression_type;
|
||||||
|
|
||||||
|
size_t compressed_size;
|
||||||
|
|
||||||
|
size_t uncompressed_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
using Blob = std::vector<std::byte>;
|
||||||
|
|
||||||
|
class Asset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Type : uint32_t // NOLINT(performance-enum-size)
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Texture,
|
||||||
|
Text,
|
||||||
|
Mesh,
|
||||||
|
Material,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Metadata
|
||||||
|
{
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
Asset() = default;
|
||||||
|
|
||||||
|
/** Directly unpacks from disk to the destination.
|
||||||
|
*
|
||||||
|
* @note The destination MUST have at least blob_metadata.unpacked_size bytes available for
|
||||||
|
* writing, otherwise segfault could occur!
|
||||||
|
*/
|
||||||
|
void unpack_blob(BlobMetadata::Tag blob_tag, std::byte *destination);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Assets
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
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,43 +0,0 @@
|
||||||
export module assets.metadata;
|
|
||||||
import std;
|
|
||||||
|
|
||||||
export namespace lt::assets {
|
|
||||||
|
|
||||||
using Type_T = std::array<const char, 16>;
|
|
||||||
|
|
||||||
using Tag_T = std::uint8_t;
|
|
||||||
|
|
||||||
using Version = std::uint8_t;
|
|
||||||
|
|
||||||
using Blob = std::vector<std::byte>;
|
|
||||||
|
|
||||||
constexpr auto current_version = Version { 1u };
|
|
||||||
|
|
||||||
enum class CompressionType : std::uint8_t
|
|
||||||
{
|
|
||||||
none,
|
|
||||||
lz4,
|
|
||||||
lz4_hc,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AssetMetadata
|
|
||||||
{
|
|
||||||
Version version;
|
|
||||||
|
|
||||||
Type_T type;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BlobMetadata
|
|
||||||
{
|
|
||||||
Tag_T tag;
|
|
||||||
|
|
||||||
std::size_t offset;
|
|
||||||
|
|
||||||
CompressionType compression_type;
|
|
||||||
|
|
||||||
std::size_t compressed_size;
|
|
||||||
|
|
||||||
std::size_t uncompressed_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::assets
|
|
||||||
|
|
@ -1,232 +0,0 @@
|
||||||
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 {
|
|
||||||
|
|
||||||
constexpr auto total_metadata_size = //
|
|
||||||
sizeof(AssetMetadata::type) //
|
|
||||||
+ sizeof(AssetMetadata::version) //
|
|
||||||
+ sizeof(ShaderAsset::Metadata::type) //
|
|
||||||
+ sizeof(BlobMetadata::tag) //
|
|
||||||
+ sizeof(BlobMetadata::offset) //
|
|
||||||
+ sizeof(BlobMetadata::compression_type) //
|
|
||||||
+ sizeof(BlobMetadata::compressed_size) //
|
|
||||||
+ sizeof(BlobMetadata::uncompressed_size);
|
|
||||||
|
|
||||||
ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|
||||||
{
|
|
||||||
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<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(),
|
|
||||||
total_metadata_size,
|
|
||||||
file_size
|
|
||||||
);
|
|
||||||
|
|
||||||
m_stream.seekg(0, std::ifstream::beg);
|
|
||||||
read(m_asset_metadata.type);
|
|
||||||
read(m_asset_metadata.version);
|
|
||||||
read(m_metadata.type);
|
|
||||||
read(m_code_blob_metadata.tag);
|
|
||||||
read(m_code_blob_metadata.offset);
|
|
||||||
read(m_code_blob_metadata.compression_type);
|
|
||||||
read(m_code_blob_metadata.compressed_size);
|
|
||||||
read(m_code_blob_metadata.uncompressed_size);
|
|
||||||
|
|
||||||
debug::ensure(
|
|
||||||
m_asset_metadata.type == asset_type_identifier,
|
|
||||||
"Failed to open shader asset at: {}, incorrect asset type: {} != {}",
|
|
||||||
path.string(),
|
|
||||||
m_asset_metadata.type,
|
|
||||||
asset_type_identifier
|
|
||||||
);
|
|
||||||
|
|
||||||
debug::ensure(
|
|
||||||
m_asset_metadata.version == current_version,
|
|
||||||
"Failed to open shader asset at: {}, version mismatch: {} != {}",
|
|
||||||
path.string(),
|
|
||||||
m_asset_metadata.version,
|
|
||||||
current_version
|
|
||||||
);
|
|
||||||
|
|
||||||
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)
|
|
||||||
);
|
|
||||||
|
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
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(),
|
|
||||||
file_size,
|
|
||||||
m_code_blob_metadata.offset,
|
|
||||||
m_code_blob_metadata.compressed_size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ void ShaderAsset::pack(
|
|
||||||
const std::filesystem::path &destination,
|
|
||||||
AssetMetadata asset_metadata,
|
|
||||||
Metadata metadata,
|
|
||||||
Blob code_blob
|
|
||||||
)
|
|
||||||
{
|
|
||||||
auto stream = std::ofstream {
|
|
||||||
destination,
|
|
||||||
std::ios::binary | std::ios::trunc,
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto code_blob_metadata = BlobMetadata {
|
|
||||||
.tag = std::to_underlying(BlobTag::code),
|
|
||||||
.offset = total_metadata_size,
|
|
||||||
.compression_type = CompressionType::none,
|
|
||||||
.compressed_size = code_blob.size(),
|
|
||||||
.uncompressed_size = code_blob.size(),
|
|
||||||
};
|
|
||||||
|
|
||||||
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));
|
|
||||||
};
|
|
||||||
write(asset_metadata.type);
|
|
||||||
write(asset_metadata.version);
|
|
||||||
write(metadata.type);
|
|
||||||
write(code_blob_metadata.tag);
|
|
||||||
write(code_blob_metadata.offset);
|
|
||||||
write(code_blob_metadata.compression_type);
|
|
||||||
write(code_blob_metadata.compressed_size);
|
|
||||||
write(code_blob_metadata.uncompressed_size);
|
|
||||||
stream.write(std::bit_cast<char *>(code_blob.data()), static_cast<long long>(code_blob.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShaderAsset::unpack_to(BlobTag tag, std::span<std::byte> destination) const
|
|
||||||
{
|
|
||||||
debug::ensure(
|
|
||||||
tag == BlobTag::code,
|
|
||||||
"Invalid blob tag for shader asset: {}",
|
|
||||||
std::to_underlying(tag)
|
|
||||||
);
|
|
||||||
|
|
||||||
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<std::size_t>(destination.data()),
|
|
||||||
destination.size(),
|
|
||||||
m_code_blob_metadata.uncompressed_size
|
|
||||||
);
|
|
||||||
|
|
||||||
m_stream.seekg(static_cast<long long>(m_code_blob_metadata.offset));
|
|
||||||
m_stream.read(
|
|
||||||
std::bit_cast<char *>(destination.data()),
|
|
||||||
static_cast<long long>(m_code_blob_metadata.uncompressed_size)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto ShaderAsset::unpack(BlobTag tag) const -> Blob
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
return blob;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace lt::assets
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
import assets.metadata;
|
|
||||||
import assets.shader;
|
|
||||||
import test.test;
|
|
||||||
import test.expects;
|
|
||||||
import std;
|
|
||||||
|
|
||||||
using ::lt::assets::AssetMetadata;
|
|
||||||
using ::lt::assets::BlobMetadata;
|
|
||||||
using ::lt::assets::ShaderAsset;
|
|
||||||
using ::lt::test::Case;
|
|
||||||
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/" };
|
|
||||||
|
|
||||||
Suite raii = "shader_raii"_suite = [] {
|
|
||||||
std::filesystem::current_path(test_data_path);
|
|
||||||
std::filesystem::create_directories(tmp_path);
|
|
||||||
|
|
||||||
Case { "happy path won't throw" } = [] {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
Case { "many won't freeze/throw" } = [] {
|
|
||||||
};
|
|
||||||
|
|
||||||
Case { "unhappy path throws" } = [] {
|
|
||||||
expect_throw([] { ShaderAsset { "random_path" }; });
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-interfaces-global-init)
|
|
||||||
Suite packing = "shader_pack"_suite = [] {
|
|
||||||
Case { "" } = [] {
|
|
||||||
const auto out_path = tmp_path / "shader_packing";
|
|
||||||
auto dummy_blob = lt::assets::Blob {};
|
|
||||||
for (auto idx : std::views::iota(0, 255))
|
|
||||||
{
|
|
||||||
dummy_blob.emplace_back(static_cast<std::byte>(idx));
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto expected_size = //
|
|
||||||
sizeof(AssetMetadata::type) //
|
|
||||||
+ sizeof(AssetMetadata::version) //
|
|
||||||
+ sizeof(ShaderAsset::Metadata::type) //
|
|
||||||
+ sizeof(BlobMetadata::tag) //
|
|
||||||
+ sizeof(BlobMetadata::offset) //
|
|
||||||
+ sizeof(BlobMetadata::compression_type) //
|
|
||||||
+ sizeof(BlobMetadata::compressed_size) //
|
|
||||||
+ sizeof(BlobMetadata::uncompressed_size) //
|
|
||||||
+ dummy_blob.size();
|
|
||||||
|
|
||||||
ShaderAsset::pack(
|
|
||||||
out_path,
|
|
||||||
lt::assets::AssetMetadata {
|
|
||||||
.version = lt::assets::current_version,
|
|
||||||
.type = ShaderAsset::asset_type_identifier,
|
|
||||||
},
|
|
||||||
ShaderAsset::Metadata {
|
|
||||||
.type = ShaderAsset::Type::vertex,
|
|
||||||
},
|
|
||||||
std::move(dummy_blob)
|
|
||||||
);
|
|
||||||
|
|
||||||
auto stream = std::ifstream {
|
|
||||||
out_path,
|
|
||||||
std::ios::binary,
|
|
||||||
};
|
|
||||||
expect_true(stream.is_open());
|
|
||||||
|
|
||||||
stream.seekg(0, std::ios::end);
|
|
||||||
const auto file_size = static_cast<std::size_t>(stream.tellg());
|
|
||||||
expect_eq(file_size, expected_size);
|
|
||||||
stream.close();
|
|
||||||
|
|
||||||
auto shader_asset = ShaderAsset { out_path };
|
|
||||||
|
|
||||||
const auto &asset_metadata = shader_asset.get_asset_metadata();
|
|
||||||
expect_eq(asset_metadata.type, ShaderAsset::asset_type_identifier);
|
|
||||||
expect_eq(asset_metadata.version, lt::assets::current_version);
|
|
||||||
|
|
||||||
const auto &metadata = shader_asset.get_metadata();
|
|
||||||
expect_eq(metadata.type, ShaderAsset::Type::vertex);
|
|
||||||
|
|
||||||
auto blob = shader_asset.unpack(ShaderAsset::BlobTag::code);
|
|
||||||
expect_eq(blob.size(), 255);
|
|
||||||
|
|
||||||
for (auto idx : std::views::iota(0, 255))
|
|
||||||
{
|
|
||||||
expect_eq(blob[idx], static_cast<std::byte>(idx));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
2
modules/base/CMakeLists.txt
Normal file
2
modules/base/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
add_library_module(base)
|
||||||
|
target_precompile_headers(base INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/private/pch.hpp)
|
||||||
36
modules/base/private/pch.hpp
Normal file
36
modules/base/private/pch.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <base/base.hpp>
|
||||||
|
|
||||||
|
/* windows */
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define NOMINMAX
|
||||||
|
#include <Windows.h>
|
||||||
|
#undef NOMINMAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Stdlib */
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <atomic>
|
||||||
|
#include <bitset>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <math.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <span>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <thread>
|
||||||
|
#include <time.h>
|
||||||
|
#include <tuple>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
91
modules/base/public/base.hpp
Normal file
91
modules/base/public/base.hpp
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
// Ref (Ref)
|
||||||
|
template<typename t>
|
||||||
|
using Ref = std::shared_ptr<t>;
|
||||||
|
|
||||||
|
template<typename t, typename... Args>
|
||||||
|
constexpr Ref<t> create_ref(Args &&...args)
|
||||||
|
{
|
||||||
|
return std::make_shared<t>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename t>
|
||||||
|
constexpr Ref<t> make_ref(t *rawPointer)
|
||||||
|
{
|
||||||
|
return std::shared_ptr<t>(rawPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scope (std::unique_ptr)
|
||||||
|
template<typename t>
|
||||||
|
using Scope = std::unique_ptr<t>;
|
||||||
|
|
||||||
|
template<typename t, typename... Args>
|
||||||
|
constexpr std::unique_ptr<t> create_scope(Args &&...args)
|
||||||
|
{
|
||||||
|
return std::make_unique<t>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename t>
|
||||||
|
constexpr std::unique_ptr<t> make_scope(t *rawPointer)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<t>(rawPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
|
|
||||||
|
#define lt_win(x) // windows
|
||||||
|
#define lt_lin(x) // linux
|
||||||
|
#define lt_mac(x) // mac
|
||||||
|
|
||||||
|
enum class Platform : uint8_t
|
||||||
|
{
|
||||||
|
windows,
|
||||||
|
|
||||||
|
/** Named like so because "linux" is a built-in identifier. */
|
||||||
|
gnu,
|
||||||
|
|
||||||
|
mac,
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace constants {
|
||||||
|
|
||||||
|
#if defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
|
#define lt_win(x)
|
||||||
|
constexpr auto platform = Platform::windows;
|
||||||
|
constexpr auto platform_name = "windows";
|
||||||
|
|
||||||
|
#undef LIGHT_PLATFORM_WINDOWS
|
||||||
|
|
||||||
|
#elif defined(LIGHT_PLATFORM_LINUX)
|
||||||
|
#define lt_lin(x) x
|
||||||
|
constexpr auto platform = Platform::gnu;
|
||||||
|
constexpr auto platform_name = "linux";
|
||||||
|
|
||||||
|
#elif defined(LIGHT_PLATFORM_MAC)
|
||||||
|
#define lt_mac(x) x
|
||||||
|
constexpr auto platform = Platform::mac;
|
||||||
|
constexpr auto platform_name = "mac";
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unsupported platform: Unknown"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace constants
|
||||||
|
|
||||||
|
/* bit-wise */
|
||||||
|
constexpr auto bit(auto x)
|
||||||
|
{
|
||||||
|
return 1 << x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* token */
|
||||||
|
#define lt_pair_token_value_to_name(token) { token, #token }
|
||||||
|
#define lt_pair_token_name_to_value(token) { #token, token }
|
||||||
|
#define lt_token_name(token) #token
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
add_library_module(NAME bitwise INTERFACES operations.cppm)
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
export module bitwise;
|
|
||||||
import std;
|
|
||||||
|
|
||||||
namespace lt::bitwise {
|
|
||||||
|
|
||||||
/* bit-wise */
|
|
||||||
constexpr auto bit(std::uint32_t x) -> std::uint32_t
|
|
||||||
{
|
|
||||||
return 1u << x;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace lt::bitwise
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
add_library_module(NAME camera INTERFACES components.cppm)
|
add_library_module(camera camera.cpp scene.cpp)
|
||||||
|
|
||||||
target_link_libraries(camera PUBLIC math)
|
target_link_libraries(camera PUBLIC math)
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
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
|
|
||||||
6
modules/camera/private/camera.cpp
Normal file
6
modules/camera/private/camera.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include <camera/camera.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
83
modules/camera/private/scene.cpp
Normal file
83
modules/camera/private/scene.cpp
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
#include <camera/scene.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
|
||||||
35
modules/camera/public/camera.hpp
Normal file
35
modules/camera/public/camera.hpp
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#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
|
||||||
29
modules/camera/public/component.hpp
Normal file
29
modules/camera/public/component.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#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
|
||||||
100
modules/camera/public/scene.hpp
Normal file
100
modules/camera/public/scene.hpp
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
#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,2 +1,3 @@
|
||||||
add_library_module(NAME lt_debug INTERFACES instrumentor.cppm assertions.cppm)
|
add_library_module(lt_debug instrumentor.cpp)
|
||||||
target_link_libraries(lt_debug PUBLIC logger)
|
target_link_libraries(lt_debug PUBLIC logger)
|
||||||
|
target_precompile_headers(lt_debug PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/private/pch.hpp)
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
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
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
71
modules/debug/private/instrumentor.cpp
Normal file
71
modules/debug/private/instrumentor.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
#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
|
||||||
3
modules/debug/private/pch.hpp
Normal file
3
modules/debug/private/pch.hpp
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <lt_debug/assertions.hpp>
|
||||||
36
modules/debug/public/assertions.hpp
Normal file
36
modules/debug/public/assertions.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <logger/logger.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
struct FailedAssertion: std::exception
|
||||||
|
{
|
||||||
|
FailedAssertion(const char *file, int line)
|
||||||
|
{
|
||||||
|
log_crt("Assertion failed in: {} (line {})", file, line);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Expression_T, typename... Args>
|
||||||
|
constexpr void ensure(Expression_T &&expression, std::format_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
if (!static_cast<bool>(expression))
|
||||||
|
{
|
||||||
|
Logger::log(LogLvl::critical, fmt, std::forward<Args>(args)...);
|
||||||
|
throw ::lt::FailedAssertion(__FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Expression_T>
|
||||||
|
constexpr void ensure(Expression_T &&expression, const char *message)
|
||||||
|
{
|
||||||
|
if (!static_cast<bool>(expression))
|
||||||
|
{
|
||||||
|
Logger::log(LogLvl::critical, message);
|
||||||
|
throw ::lt::FailedAssertion(__FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
77
modules/debug/public/instrumentor.hpp
Normal file
77
modules/debug/public/instrumentor.hpp
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
#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,5 +1,5 @@
|
||||||
add_library_module(NAME ecs INTERFACES sparse_set.cppm registry.cppm
|
add_library_module(ecs entity.cpp scene.cpp uuid.cpp serializer.cpp)
|
||||||
entity.cppm)
|
target_link_libraries(ecs
|
||||||
target_link_libraries(ecs PUBLIC logger lt_debug memory)
|
PUBLIC logger lt_debug EnTT::EnTT renderer input camera
|
||||||
|
PRIVATE yaml-cpp::yaml-cpp asset_manager
|
||||||
add_test_module(ecs sparse_set.test.cpp registry.test.cpp)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
export module ecs.entity;
|
|
||||||
import debug.assertions;
|
|
||||||
import memory.reference;
|
|
||||||
import ecs.registry;
|
|
||||||
import std;
|
|
||||||
|
|
||||||
namespace lt::ecs {
|
|
||||||
|
|
||||||
/** High-level entity convenience wrapper */
|
|
||||||
export class Entity
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Entity(memory::Ref<Registry> registry, EntityId identifier)
|
|
||||||
: m_registry(std::move(registry))
|
|
||||||
, m_identifier(identifier)
|
|
||||||
{
|
|
||||||
debug::ensure(m_registry, "Failed to create Entity ({}): null registry", m_identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Component_T>
|
|
||||||
auto add(Component_T component) -> Component_T &
|
|
||||||
{
|
|
||||||
return m_registry->add(m_identifier, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Component_T>
|
|
||||||
auto get() -> Component_T &
|
|
||||||
{
|
|
||||||
return m_registry->get<Component_T>(m_identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Component_T>
|
|
||||||
auto get() const -> const Component_T &
|
|
||||||
{
|
|
||||||
return m_registry->get<Component_T>(m_identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get_registry() -> memory::Ref<Registry>
|
|
||||||
{
|
|
||||||
return m_registry;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto id() const -> EntityId
|
|
||||||
{
|
|
||||||
return m_identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
memory::Ref<Registry> m_registry;
|
|
||||||
|
|
||||||
EntityId m_identifier;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace lt::ecs
|
|
||||||
10
modules/ecs/private/entity.cpp
Normal file
10
modules/ecs/private/entity.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <ecs/entity.hpp>
|
||||||
|
#include <ecs/scene.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
Entity::Entity(entt::entity handle, Scene *scene): m_handle(handle), m_scene(scene)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
110
modules/ecs/private/scene.cpp
Normal file
110
modules/ecs/private/scene.cpp
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
#include <camera/component.hpp>
|
||||||
|
#include <ecs/components.hpp>
|
||||||
|
#include <ecs/entity.hpp>
|
||||||
|
#include <ecs/scene.hpp>
|
||||||
|
#include <renderer/renderer.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
void Scene::on_create()
|
||||||
|
{
|
||||||
|
/* native scripts */
|
||||||
|
{
|
||||||
|
m_registry.view<NativeScriptComponent>().each([](NativeScriptComponent &nsc) {
|
||||||
|
if (nsc.instance == nullptr)
|
||||||
|
{
|
||||||
|
nsc.instance = nsc.CreateInstance();
|
||||||
|
nsc.instance->on_create();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::on_update(float deltaTime)
|
||||||
|
{
|
||||||
|
/* native scripts */
|
||||||
|
{
|
||||||
|
m_registry.view<NativeScriptComponent>().each([=](NativeScriptComponent &nsc) {
|
||||||
|
nsc.instance->on_update(deltaTime);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::on_render(const Ref<Framebuffer> &targetFrameBuffer /* = nullptr */)
|
||||||
|
{
|
||||||
|
auto *sceneCamera = (Camera *)nullptr;
|
||||||
|
auto *sceneCameraTransform = (TransformComponent *)nullptr;
|
||||||
|
|
||||||
|
/* scene camera */
|
||||||
|
{
|
||||||
|
m_registry.group(entt::get<TransformComponent, CameraComponent>)
|
||||||
|
.each([&](TransformComponent &transformComp, CameraComponent &cameraComp) {
|
||||||
|
if (cameraComp.isPrimary)
|
||||||
|
{
|
||||||
|
sceneCamera = &cameraComp.camera;
|
||||||
|
sceneCameraTransform = &transformComp;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* draw quads */
|
||||||
|
{
|
||||||
|
if (sceneCamera)
|
||||||
|
{
|
||||||
|
Renderer::begin_scene(sceneCamera, *sceneCameraTransform, targetFrameBuffer);
|
||||||
|
|
||||||
|
m_registry.group(entt::get<TransformComponent, SpriteRendererComponent>)
|
||||||
|
.each([](TransformComponent &transformComp,
|
||||||
|
SpriteRendererComponent &spriteRendererComp) {
|
||||||
|
Renderer::draw_quad(
|
||||||
|
transformComp,
|
||||||
|
spriteRendererComp.tint,
|
||||||
|
spriteRendererComp.texture
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Renderer::end_scene();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Scene::create_entity(const std::string &name, const TransformComponent &transform) -> Entity
|
||||||
|
{
|
||||||
|
return create_entity_with_uuid(name, UUID(), transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Scene::get_entity_by_tag(const std::string &tag) -> Entity
|
||||||
|
{
|
||||||
|
// TagComponent tagComp(tag);
|
||||||
|
// entt::entity entity = entt::to_entity(m_registry, tagComp);
|
||||||
|
auto entity = Entity {};
|
||||||
|
|
||||||
|
m_registry.view<TagComponent>().each([&](TagComponent &tagComp) {
|
||||||
|
// if (tagComp.tag == tag)
|
||||||
|
// entity = entity(entt::to_entity(m_registry, tagComp), this);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (entity.is_valid())
|
||||||
|
{
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure(false, "Scene::get_entity_by_tag: failed to find entity by tag: {}", tag);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Scene::create_entity_with_uuid(
|
||||||
|
const std::string &name,
|
||||||
|
UUID uuid,
|
||||||
|
const TransformComponent &transform
|
||||||
|
) -> Entity
|
||||||
|
{
|
||||||
|
auto entity = Entity { m_registry.create(), this };
|
||||||
|
entity.add_component<TagComponent>(name);
|
||||||
|
entity.add_component<TransformComponent>(transform);
|
||||||
|
entity.add_component<UUIDComponent>(uuid);
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue