Compare commits
7 commits
main
...
ci/msan_fi
| Author | SHA1 | Date | |
|---|---|---|---|
| f9b1ac8c84 | |||
| 368ea7e1d0 | |||
| 8c0dbdd52a | |||
| 5a922cac71 | |||
| 2f7c729f88 | |||
| bcb1acbf75 | |||
| 6aa03cc05b |
226 changed files with 7498 additions and 11049 deletions
|
|
@ -1,17 +0,0 @@
|
|||
# How wide to allow formatted cmake files
|
||||
line_width: 80
|
||||
|
||||
# How many spaces to tab for indent
|
||||
tab_size: 4
|
||||
|
||||
dangle_parens: true
|
||||
|
||||
# Additional FLAGS and KWARGS for custom commands
|
||||
additional_commands:
|
||||
foo:
|
||||
flags: [BAR, BAZ]
|
||||
kwargs:
|
||||
HEADERS : '*'
|
||||
SOURCES : '*'
|
||||
DEPENDS : '*'
|
||||
|
||||
286
.drone.yml
286
.drone.yml
|
|
@ -1,42 +1,42 @@
|
|||
---
|
||||
kind: pipeline
|
||||
type: exec
|
||||
name: amd64 — msvc
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
platform:
|
||||
os: windows
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: unit tests
|
||||
shell: powershell
|
||||
commands:
|
||||
- ./tools/ci/amd64/msvc/unit_tests.ps1
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: amd64 — gcc
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
|
||||
steps:
|
||||
- name: unit tests
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/amd64/gcc/unit_tests.sh
|
||||
|
||||
- name: valgrind
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/amd64/gcc/valgrind.sh
|
||||
|
||||
---
|
||||
# ---
|
||||
# kind: pipeline
|
||||
# type: exec
|
||||
# name: amd64 — msvc
|
||||
# trigger:
|
||||
# branch:
|
||||
# - main
|
||||
# platform:
|
||||
# os: windows
|
||||
# arch: amd64
|
||||
#
|
||||
# steps:
|
||||
# - name: unit tests
|
||||
# shell: powershell
|
||||
# commands:
|
||||
# - ./tools/ci/amd64/msvc/unit_tests.ps1
|
||||
#
|
||||
# ---
|
||||
# kind: pipeline
|
||||
# type: docker
|
||||
# name: amd64 — gcc
|
||||
# trigger:
|
||||
# branch:
|
||||
# - main
|
||||
#
|
||||
# steps:
|
||||
# - name: unit tests
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/amd64/gcc/unit_tests.sh
|
||||
#
|
||||
# - name: valgrind
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/amd64/gcc/valgrind.sh
|
||||
#
|
||||
# ---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: amd64 — clang
|
||||
|
|
@ -45,110 +45,114 @@ trigger:
|
|||
- main
|
||||
|
||||
steps:
|
||||
- name: code coverage
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
environment:
|
||||
CODECOV_TOKEN:
|
||||
from_secret: CODECOV_TOKEN
|
||||
commands:
|
||||
- ./tools/ci/amd64/clang/coverage.sh
|
||||
|
||||
- name: leak sanitizer
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/amd64/clang/lsan.sh
|
||||
|
||||
# - name: code coverage
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# environment:
|
||||
# CODECOV_TOKEN:
|
||||
# from_secret: CODECOV_TOKEN
|
||||
# commands:
|
||||
# - ./tools/ci/amd64/clang/coverage.sh
|
||||
#
|
||||
# - name: leak sanitizer
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/amd64/clang/lsan.sh
|
||||
#
|
||||
- name: memory sanitizer
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/amd64/clang/msan.sh
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: static analysis
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
|
||||
steps:
|
||||
- name: clang tidy
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
privileged: true
|
||||
commands:
|
||||
- ./tools/ci/static_analysis/clang_tidy.sh
|
||||
|
||||
- name: shell check
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/static_analysis/shell_check.sh
|
||||
|
||||
- name: clang format
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/static_analysis/clang_format.sh
|
||||
|
||||
- name: cmake format
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/static_analysis/cmake_format.sh
|
||||
|
||||
- name: shell format
|
||||
image: ci:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- ./tools/ci/static_analysis/shell_format.sh
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: documentation — development
|
||||
node:
|
||||
environment: ryali
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
|
||||
steps:
|
||||
- name: build and deploy
|
||||
image: documentation:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- cd docs
|
||||
- sphinx-build -M html . .
|
||||
|
||||
- rm -rf /light_docs_dev/*
|
||||
- mv ./html/* /light_docs_dev/
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: documentation — production
|
||||
node:
|
||||
environment: ryali
|
||||
trigger:
|
||||
event:
|
||||
- tag
|
||||
|
||||
steps:
|
||||
- name: build and deploy
|
||||
image: documentation:latest
|
||||
pull: if-not-exists
|
||||
commands:
|
||||
- cd docs
|
||||
- mkdir generated
|
||||
- touch generated/changelogs.rst
|
||||
- touch generated/api.rst
|
||||
- sphinx-build -M html . .
|
||||
|
||||
- rm -rf /light_docs/*
|
||||
- mv ./html/* /light_docs/
|
||||
|
||||
#
|
||||
# ---
|
||||
# kind: pipeline
|
||||
# type: docker
|
||||
# name: static analysis
|
||||
# trigger:
|
||||
# branch:
|
||||
# - main
|
||||
#
|
||||
# steps:
|
||||
# - name: clang tidy
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# privileged: true
|
||||
# commands:
|
||||
# - ./tools/ci/static_analysis/clang_tidy.sh
|
||||
#
|
||||
# - name: shell check
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/static_analysis/shell_check.sh
|
||||
#
|
||||
# - name: clang format
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/static_analysis/clang_format.sh
|
||||
#
|
||||
# - name: cmake format
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/static_analysis/cmake_format.sh
|
||||
#
|
||||
# - name: shell format
|
||||
# image: ci:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - ./tools/ci/static_analysis/shell_format.sh
|
||||
#
|
||||
# ---
|
||||
# kind: pipeline
|
||||
# type: docker
|
||||
# name: documentation — development
|
||||
# node:
|
||||
# environment: ryali
|
||||
# trigger:
|
||||
# branch:
|
||||
# - main
|
||||
#
|
||||
# steps:
|
||||
# - name: build and deploy
|
||||
# image: documentation:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - pwd
|
||||
# - cd docs
|
||||
# - mkdir generated
|
||||
# - touch generated/changelogs.rst
|
||||
# - touch generated/api.rst
|
||||
# - sphinx-build -M html . .
|
||||
#
|
||||
# - rm -rf /light_docs_dev/*
|
||||
# - mv ./html/* /light_docs_dev/
|
||||
#
|
||||
# ---
|
||||
#
|
||||
# kind: pipeline
|
||||
# type: docker
|
||||
# name: documentation — production
|
||||
# node:
|
||||
# environment: ryali
|
||||
# trigger:
|
||||
# event:
|
||||
# - tag
|
||||
#
|
||||
# steps:
|
||||
# - name: build and deploy
|
||||
# image: documentation:latest
|
||||
# pull: if-not-exists
|
||||
# commands:
|
||||
# - cd docs
|
||||
# - mkdir generated
|
||||
# - touch generated/changelogs.rst
|
||||
# - touch generated/api.rst
|
||||
# - sphinx-build -M html . .
|
||||
#
|
||||
# - rm -rf /light_docs/*
|
||||
# - mv ./html/* /light_docs/
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,10 +1,4 @@
|
|||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_EPXORT_COMPILE_COMMANDS TRUE)
|
||||
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444")
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
set(CMAKE_CXX_MODULE_STD 1)
|
||||
|
||||
cmake_minimum_required(VERSION 4.1)
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(Light)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/functions.cmake)
|
||||
|
|
|
|||
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.
|
||||
14
CONTRIBUTING.md
Normal file
14
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# How to contribute to Light Engine
|
||||
|
||||
Thanks for putting in the time to contribute to this project <3
|
||||
|
||||
## Coding conventions
|
||||
|
||||
For the time being, don't worry too much about the conventions...
|
||||
|
||||
Try to read other parts of the code and you'll get the hang of it
|
||||
|
||||
I have to learn clang-format, then everyone contributing can use it to format their code
|
||||
|
||||
|
||||
###### happy coding-
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
#version 450 core
|
||||
|
||||
layout(push_constant) uniform pc
|
||||
{
|
||||
mat4 view_projection;
|
||||
};
|
||||
|
||||
|
||||
struct VertexData
|
||||
{
|
||||
vec3 position;
|
||||
vec3 color;
|
||||
};
|
||||
|
||||
// readonly SSBO containing the vertex data
|
||||
layout(set = 0, binding = 0, std430) readonly buffer vertex_data {
|
||||
VertexData data[];
|
||||
};
|
||||
|
||||
vec3 position(int idx)
|
||||
{
|
||||
return data[idx].position;
|
||||
}
|
||||
|
||||
vec3 color(int idx)
|
||||
{
|
||||
return data[idx].color;
|
||||
}
|
||||
|
||||
layout(location = 0) out vec3 out_frag_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = view_projection * vec4(position(gl_VertexIndex), 1.0);
|
||||
out_frag_color = color(gl_VertexIndex);
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,25 +1,21 @@
|
|||
#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)
|
||||
vec2 positions[3] = vec2[](
|
||||
vec2(0.0, -0.5),
|
||||
vec2(0.5, 0.5),
|
||||
vec2(-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)
|
||||
vec3(1.0, 0.0, 0.0),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
vec3(0.0, 0.0, 1.0)
|
||||
);
|
||||
|
||||
layout(location = 0) out vec3 out_frag_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = view_projection * vec4(positions[gl_VertexIndex], 1.0);
|
||||
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
|
||||
out_frag_color = colors[gl_VertexIndex];
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
3
docs/.gitignore
vendored
3
docs/.gitignore
vendored
|
|
@ -1,4 +1,3 @@
|
|||
_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
|
||||
14
docs/conf.py
14
docs/conf.py
|
|
@ -13,21 +13,13 @@ 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'
|
||||
extensions = []
|
||||
|
||||
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
|
||||
|
||||
|
|
|
|||
68
docs/generate_changelog.py
Normal file
68
docs/generate_changelog.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
from git import Repo
|
||||
import re
|
||||
|
||||
repo = Repo(search_parent_directories=True)
|
||||
assert not repo.bare
|
||||
|
||||
file_path = "generated/changelog.rst"
|
||||
|
||||
messages = []
|
||||
short_shas = []
|
||||
hex_shas = []
|
||||
logs = []
|
||||
|
||||
remote_url = "https://git.light7734.com/light7734/light/commit"
|
||||
def format_log(commit_type, message, major, minor, patch, short_sha, hex_sha):
|
||||
href = f"{remote_url}/{hex_sha}"
|
||||
version = f"{major}.{minor}.{patch}-kitten+{short_sha}";
|
||||
link = f"`{version} <{remote_url}/{hex_sha}>`__"
|
||||
return f"| **{message}** ({link})"
|
||||
|
||||
for commit in repo.iter_commits():
|
||||
messages.append(commit.summary)
|
||||
short_shas.append(repo.git.rev_parse(commit.hexsha, short=5))
|
||||
hex_shas.append(commit.hexsha)
|
||||
|
||||
ver_major = 0
|
||||
ver_minor = 0
|
||||
ver_patch = 0
|
||||
|
||||
idx = len(messages)
|
||||
for message in reversed(messages):
|
||||
idx = idx - 1;
|
||||
|
||||
commit_type = re.match("^(feat|fix|refactor|perf|build|asset|test|chore|ci|docs)", message)
|
||||
if not commit_type:
|
||||
continue
|
||||
|
||||
match commit_type.group(0):
|
||||
case "feat":
|
||||
ver_minor = ver_minor + 1
|
||||
ver_patch = 0
|
||||
|
||||
case "fix":
|
||||
ver_patch = ver_patch + 1
|
||||
|
||||
case "refactor":
|
||||
ver_patch = ver_patch + 1
|
||||
|
||||
case "perf":
|
||||
ver_patch = ver_patch + 1
|
||||
|
||||
case "build":
|
||||
ver_patch = ver_patch + 1
|
||||
|
||||
case "asset":
|
||||
ver_patch = ver_patch + 1
|
||||
|
||||
logs.append(format_log(commit_type, message, ver_major, ver_minor, ver_patch, short_shas[idx], hex_shas[idx]))
|
||||
|
||||
with open(file_path, "w") as f:
|
||||
f.write(".. changelogs\n\n\n")
|
||||
f.write("Changelogs\n")
|
||||
f.write("==================================================\n\n")
|
||||
|
||||
f.write("KITTEN\n")
|
||||
f.write("--------------------------------------------------\n\n")
|
||||
for log in reversed(logs):
|
||||
f.write(log + '\n')
|
||||
|
|
@ -1,46 +1,49 @@
|
|||
.. guidelines/development
|
||||
|
||||
Development Strategy
|
||||
Development
|
||||
===================================================================================================
|
||||
Defines:
|
||||
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.
|
||||
|
||||
- A **unit of work**.
|
||||
- A **pipeline** for making changes ---should **minimize ambiguity**.
|
||||
- A way for **distributing work** and **tracking productivity**.
|
||||
Such a plan should:
|
||||
|
||||
An **unpragmatic strategy** is utterly useless. It should pull our minds out from the **engineering dreamland**, and make us focus on the **product delivery**.
|
||||
- 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**.
|
||||
|
||||
.. note::
|
||||
**Forgejo issues** is used as the project-management tool.
|
||||
No need for fancy boards or 3rd party apps. Simple tags, titles, milestones, etc... should suffice.
|
||||
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, 1 cycle == 1 issue, and it consists of 4 stages:
|
||||
A cycle is one **step** in development, one cycle = one ticket, and it consists of 4 stages:
|
||||
|
||||
1 - Make it known
|
||||
- Write the commit title.
|
||||
- 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 an issue.
|
||||
- Git is a **version-control** tool, not a **project-management** tool.
|
||||
- Preferably, provide a very brief description ---This may be used in the commit message's body.
|
||||
- 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.
|
||||
- Tests may not be necessary depending on the requirements and commit type.
|
||||
|
||||
- **Make it work** doesn't mean liberally producing substandard code, you should:
|
||||
- "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 existing tests.
|
||||
- Have the overall picture in mind.
|
||||
- Don't break any pre-existing-tests.
|
||||
- Have the over-all picture in mind.
|
||||
|
||||
3 - Make it right
|
||||
- Test driven refactoring
|
||||
|
|
@ -52,14 +55,12 @@ A cycle is one **step** in development, 1 cycle == 1 issue, and it consists of 4
|
|||
- 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**.
|
||||
They start from **Monday mornings**, and end on **Sunday nights**,
|
||||
where we'll do a **12hr coding marathon** (streamed on Discord) to wrap everything up.
|
||||
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.
|
||||
|
||||
Sprints begin by **defining** what cycles/issues are expected to be done.
|
||||
And end by **reflecting** on the results, which may **affect** our future approach.
|
||||
|
||||
Commit Message Specification
|
||||
---------------------------------------------------------------------------------------------------
|
||||
|
|
@ -115,10 +116,6 @@ With the following commit types:
|
|||
- For changes to the documentations.
|
||||
- Does not affect the version.
|
||||
|
||||
.. note::
|
||||
|
||||
Since we're in beta, any commit might change the api, no need for ! (breaking) tags.
|
||||
|
||||
Semantic Versioning
|
||||
---------------------------------------------------------------------------------------------------
|
||||
Coupled with conventional commit style messages, we can automajically version the project following
|
||||
|
|
@ -142,3 +139,9 @@ Using the following format:
|
|||
|
||||
The shortened hexsha of a commit is obtained by:
|
||||
``git rev-parse --short=5 <commit_hexsha>``
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@
|
|||
guidelines/conventions.rst
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
:caption: API
|
||||
:maxdepth: 2
|
||||
:caption: Generated Docs
|
||||
|
||||
api/app.rst
|
||||
api/renderer.rst
|
||||
generated/api.rst
|
||||
generated/changelog.rst
|
||||
|
||||
|
||||
|
|
|
|||
35
docs/make.bat
Normal file
35
docs/make.bat
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
|
|
@ -1,259 +1,26 @@
|
|||
add_module(NAME logger INTERFACES logger.cppm TESTS logger.test.cpp)
|
||||
add_module(NAME bitwise INTERFACES operations.cppm)
|
||||
add_module(NAME env INTERFACES constants.cppm)
|
||||
add_module(NAME memory INTERFACES null_on_move.cppm reference.cppm scope.cppm)
|
||||
add_module(NAME time INTERFACES timer.cppm TESTS timer.test.cpp)
|
||||
# engine
|
||||
add_subdirectory(./std)
|
||||
add_subdirectory(./bitwise)
|
||||
add_subdirectory(./env)
|
||||
add_subdirectory(./memory)
|
||||
add_subdirectory(./time)
|
||||
add_subdirectory(./logger)
|
||||
add_subdirectory(./debug)
|
||||
add_subdirectory(./math)
|
||||
#
|
||||
add_subdirectory(./asset_baker)
|
||||
add_subdirectory(./assets)
|
||||
#
|
||||
add_subdirectory(./camera)
|
||||
add_subdirectory(./input)
|
||||
# add_subdirectory(./ui)
|
||||
#
|
||||
add_subdirectory(./surface)
|
||||
add_subdirectory(./renderer)
|
||||
add_subdirectory(./ecs)
|
||||
#
|
||||
add_subdirectory(./app)
|
||||
|
||||
add_module(
|
||||
NAME
|
||||
test
|
||||
INTERFACES
|
||||
test.cppm
|
||||
expects.cppm
|
||||
registry.cppm
|
||||
SOURCES
|
||||
entrypoint.cpp
|
||||
DEPENDENCIES
|
||||
logger
|
||||
TESTS
|
||||
test.test.cpp
|
||||
)
|
||||
|
||||
add_module(
|
||||
NAME
|
||||
lt_debug
|
||||
ROOT_DIR
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/debug
|
||||
INTERFACES
|
||||
instrumentor.cppm
|
||||
assertions.cppm
|
||||
DEPENDENCIES
|
||||
logger
|
||||
)
|
||||
|
||||
add_module(
|
||||
NAME
|
||||
math
|
||||
INTERFACES
|
||||
algebra.cppm
|
||||
mat4.cppm
|
||||
trig.cppm
|
||||
vec2.cppm
|
||||
vec3.cppm
|
||||
vec4.cppm
|
||||
components.cppm
|
||||
)
|
||||
|
||||
add_module(
|
||||
NAME
|
||||
assets
|
||||
INTERFACES
|
||||
shader.cppm
|
||||
metadata.cppm
|
||||
DEPENDENCIES
|
||||
logger
|
||||
lt_debug
|
||||
TESTS
|
||||
shader.test.cpp
|
||||
)
|
||||
|
||||
add_module(
|
||||
NAME
|
||||
asset_baker
|
||||
ROOT_DIR
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/asset_baker
|
||||
INTERFACES
|
||||
bakers.cppm
|
||||
ENTRYPOINT
|
||||
entrypoint.cpp
|
||||
DEPENDENCIES
|
||||
assets
|
||||
logger
|
||||
lt_debug
|
||||
TESTS
|
||||
bakers.test.cpp
|
||||
)
|
||||
|
||||
# add_executable(asset_baker entrypoint.cpp) target_link_libraries(asset_baker
|
||||
# PRIVATE libasset_baker)
|
||||
|
||||
add_module(NAME camera INTERFACES components.cppm DEPENDENCIES math)
|
||||
|
||||
add_module(
|
||||
NAME
|
||||
app
|
||||
INTERFACES
|
||||
application.cppm
|
||||
system.cppm
|
||||
DEPENDENCIES
|
||||
memory
|
||||
PRIVATE_DEPENDENCIES
|
||||
lt_debug
|
||||
)
|
||||
|
||||
add_module(
|
||||
NAME
|
||||
ecs
|
||||
INTERFACES
|
||||
sparse_set.cppm
|
||||
registry.cppm
|
||||
entity.cppm
|
||||
DEPENDENCIES
|
||||
logger
|
||||
lt_debug
|
||||
memory
|
||||
TESTS
|
||||
registry.test.cpp
|
||||
sparse_set.test.cpp
|
||||
)
|
||||
|
||||
add_module(NAME input_codes INTERFACES input_codes.cppm)
|
||||
|
||||
if(WIN32)
|
||||
add_module(
|
||||
NAME
|
||||
surface
|
||||
INTERFACES
|
||||
constants.cppm
|
||||
system.cppm
|
||||
requests.cppm
|
||||
events.cppm
|
||||
components.cppm
|
||||
SOURCES
|
||||
platform_windows.cpp
|
||||
DEPENDENCIES
|
||||
ecs
|
||||
app
|
||||
math
|
||||
memory
|
||||
input_codes
|
||||
PRIVATE_DEPENDENCIES
|
||||
logger
|
||||
lt_debug
|
||||
time
|
||||
)
|
||||
|
||||
elseif(UNIX)
|
||||
add_module(
|
||||
NAME
|
||||
surface
|
||||
INTERFACES
|
||||
constants.cppm
|
||||
system.cppm
|
||||
requests.cppm
|
||||
events.cppm
|
||||
components.cppm
|
||||
SOURCES
|
||||
platform_linux.cpp
|
||||
DEPENDENCIES
|
||||
ecs
|
||||
app
|
||||
math
|
||||
memory
|
||||
input_codes
|
||||
PRIVATE_DEPENDENCIES
|
||||
X11
|
||||
logger
|
||||
lt_debug
|
||||
time
|
||||
TESTS
|
||||
system.test.cpp
|
||||
)
|
||||
|
||||
else()
|
||||
message(FATAL "Failed to generate cmake: unsupported platform")
|
||||
|
||||
endif()
|
||||
|
||||
add_module(
|
||||
NAME
|
||||
input
|
||||
INTERFACES
|
||||
system.cppm
|
||||
components.cppm
|
||||
events.cppm
|
||||
DEPENDENCIES
|
||||
input_codes
|
||||
surface
|
||||
math
|
||||
logger
|
||||
TESTS
|
||||
system.test.cpp
|
||||
)
|
||||
|
||||
find_package(Vulkan REQUIRED)
|
||||
message("Vulkan Libraries are: ${Vulkan_LIBRARIES}")
|
||||
add_module(
|
||||
NAME
|
||||
renderer
|
||||
INTERFACES
|
||||
data.cppm
|
||||
system.cppm
|
||||
frontends.cppm
|
||||
components.cppm
|
||||
factory.cppm
|
||||
vk/api_wrapper.cppm
|
||||
vk/device.cppm
|
||||
vk/gpu.cppm
|
||||
vk/instance.cppm
|
||||
vk/surface.cppm
|
||||
vk/swapchain.cppm
|
||||
vk/buffer.cppm
|
||||
vk/pass.cppm
|
||||
vk/renderer.cppm
|
||||
vk/debugger.cppm
|
||||
DEPENDENCIES
|
||||
app
|
||||
ecs
|
||||
memory
|
||||
assets
|
||||
time
|
||||
bitwise
|
||||
camera
|
||||
${Vulkan_LIBRARIES}
|
||||
Vulkan::Vulkan
|
||||
PRIVATE_DEPENDENCIES
|
||||
surface
|
||||
TESTS
|
||||
_tests/buffer.cpp
|
||||
_tests/debugger.cpp
|
||||
_tests/device.cpp
|
||||
_tests/pass.cpp
|
||||
TEST_INTERFACES
|
||||
_tests/utils.cppm
|
||||
# _tests/renderer.cpp _tests/surface.cpp _tests/system.cpp
|
||||
)
|
||||
|
||||
add_module(
|
||||
NAME
|
||||
mirror
|
||||
ROOT_DIR
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mirror
|
||||
INTERFACES
|
||||
system.cppm
|
||||
DEPENDENCIES
|
||||
memory
|
||||
app
|
||||
time
|
||||
input
|
||||
surface
|
||||
renderer
|
||||
camera
|
||||
# TESTS system.test.cpp
|
||||
)
|
||||
|
||||
add_executable(exectest ${CMAKE_CURRENT_SOURCE_DIR}/mirror/entrypoint.cpp)
|
||||
|
||||
target_link_libraries(
|
||||
exectest
|
||||
PRIVATE mirror
|
||||
app
|
||||
time
|
||||
input
|
||||
surface
|
||||
renderer
|
||||
camera
|
||||
)
|
||||
|
||||
# add_executable_module(mirror entrypoint/mirror.cpp)
|
||||
# target_link_libraries(mirror PRIVATE libmirror input)
|
||||
# apps
|
||||
add_subdirectory(./mirror)
|
||||
add_subdirectory(test)
|
||||
|
|
|
|||
5
modules/app/CMakeLists.txt
Normal file
5
modules/app/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
add_library_module(app application.cpp)
|
||||
target_link_libraries(
|
||||
app
|
||||
PUBLIC memory
|
||||
PRIVATE lt_debug)
|
||||
|
|
@ -1,94 +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;
|
||||
};
|
||||
|
||||
} // 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
|
||||
55
modules/app/private/application.cpp
Normal file
55
modules/app/private/application.cpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#include <app/application.hpp>
|
||||
#include <app/system.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
|
||||
namespace lt::app {
|
||||
|
||||
void Application::game_loop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
for (auto &system : m_systems)
|
||||
{
|
||||
const auto &last_tick = system->get_last_tick_result();
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
|
||||
system->tick(
|
||||
TickInfo {
|
||||
.delta_time = now - last_tick.end_time,
|
||||
.budget = std::chrono::milliseconds { 10 },
|
||||
.start_time = now,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for (auto &system : m_systems_to_be_registered)
|
||||
{
|
||||
m_systems.emplace_back(system)->on_register();
|
||||
}
|
||||
|
||||
for (auto &system : m_systems_to_be_unregistered)
|
||||
{
|
||||
m_systems.erase(
|
||||
std::remove(m_systems.begin(), m_systems.end(), system),
|
||||
m_systems.end()
|
||||
);
|
||||
}
|
||||
|
||||
if (m_systems.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Application::register_system(memory::Ref<app::ISystem> system)
|
||||
{
|
||||
m_systems.emplace_back(std::move(system));
|
||||
}
|
||||
|
||||
void Application::unregister_system(memory::Ref<app::ISystem> system)
|
||||
{
|
||||
m_systems_to_be_unregistered.emplace_back(std::move(system));
|
||||
}
|
||||
|
||||
} // namespace lt::app
|
||||
47
modules/app/public/application.hpp
Normal file
47
modules/app/public/application.hpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
|
||||
namespace lt::app {
|
||||
|
||||
class ISystem;
|
||||
|
||||
extern memory::Scope<class Application> create_application();
|
||||
|
||||
/** The main application class.
|
||||
* Think of this like an aggregate of systems, you register systems through this interface.
|
||||
* Then they'll tick every "application frame".
|
||||
*/
|
||||
class Application
|
||||
{
|
||||
public:
|
||||
Application(const Application &) = delete;
|
||||
|
||||
Application(Application &&) = delete;
|
||||
|
||||
auto operator=(const Application &) -> Application & = delete;
|
||||
|
||||
auto operator=(Application &&) -> Application & = delete;
|
||||
|
||||
virtual ~Application() = default;
|
||||
|
||||
void game_loop();
|
||||
|
||||
void register_system(memory::Ref<app::ISystem> system);
|
||||
|
||||
void unregister_system(memory::Ref<app::ISystem> system);
|
||||
|
||||
protected:
|
||||
Application() = default;
|
||||
|
||||
private:
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems;
|
||||
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems_to_be_unregistered;
|
||||
|
||||
std::vector<memory::Ref<app::ISystem>> m_systems_to_be_registered;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt::app
|
||||
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>
|
||||
#include <memory/scope.hpp>
|
||||
|
||||
auto main(int argc, char *argv[]) -> int32_t
|
||||
try
|
||||
{
|
||||
std::ignore = argc;
|
||||
std::ignore = argv;
|
||||
|
||||
auto application = lt::memory::Scope<lt::app::Application> {};
|
||||
application = lt::app::create_application();
|
||||
if (!application)
|
||||
{
|
||||
throw std::runtime_error { "Failed to create application\n" };
|
||||
}
|
||||
|
||||
application->game_loop();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
log_crt("Terminating due to uncaught exception:");
|
||||
log_crt("\texception.what(): {}", exp.what());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
export module app.system;
|
||||
import logger;
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
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
|
||||
struct TickInfo
|
||||
{
|
||||
using Timepoint_T = std::chrono::time_point<std::chrono::steady_clock>;
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ export struct TickInfo
|
|||
};
|
||||
|
||||
/** Information about how a system's tick performed */
|
||||
export struct TickResult
|
||||
struct TickResult
|
||||
{
|
||||
using Timepoint_T = std::chrono::time_point<std::chrono::steady_clock>;
|
||||
|
||||
|
|
@ -46,9 +46,10 @@ export struct TickResult
|
|||
Timepoint_T end_time;
|
||||
};
|
||||
|
||||
export struct SystemDiagnosis
|
||||
|
||||
struct SystemDiagnosis
|
||||
{
|
||||
enum class Severity : std::uint8_t
|
||||
enum class Severity : uint8_t
|
||||
{
|
||||
verbose,
|
||||
info,
|
||||
|
|
@ -64,14 +65,14 @@ export struct SystemDiagnosis
|
|||
Severity severity;
|
||||
};
|
||||
|
||||
export class SystemStats
|
||||
class SystemStats
|
||||
{
|
||||
public:
|
||||
void push_diagnosis(SystemDiagnosis &&diagnosis)
|
||||
{
|
||||
auto &diag = m_diagnosis.emplace_back(std::move(diagnosis));
|
||||
auto diag = m_diagnosis.emplace_back(std::move(diagnosis));
|
||||
|
||||
log::info("message: {}", std::string { diag.message });
|
||||
log_dbg("message: {}", diag.message);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto empty_diagnosis() const -> bool
|
||||
|
|
@ -83,7 +84,7 @@ private:
|
|||
std::vector<SystemDiagnosis> m_diagnosis;
|
||||
};
|
||||
|
||||
export class ISystem
|
||||
class ISystem
|
||||
{
|
||||
public:
|
||||
ISystem() = default;
|
||||
6
modules/asset_baker/CMakeLists.txt
Normal file
6
modules/asset_baker/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
add_library_module(libasset_baker bakers.cpp)
|
||||
target_link_libraries(libasset_baker PUBLIC assets logger lt_debug tbb)
|
||||
add_test_module(libasset_baker bakers.test.cpp)
|
||||
|
||||
add_executable_module(asset_baker entrypoint/baker.cpp)
|
||||
target_link_libraries(asset_baker PRIVATE libasset_baker)
|
||||
2
modules/asset_baker/private/bakers.test.cpp
Normal file
2
modules/asset_baker/private/bakers.test.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#include <asset_baker/bakers.hpp>
|
||||
#include <test/test.hpp>
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
import assets.shader;
|
||||
import logger;
|
||||
import bakers;
|
||||
import std;
|
||||
#include <asset_baker/bakers.hpp>
|
||||
#include <assets/shader.hpp>
|
||||
|
||||
|
||||
auto main(int argc, char *argv[]) -> std::int32_t
|
||||
auto main(int argc, char *argv[]) -> int32_t
|
||||
try
|
||||
{
|
||||
if (argc != 2)
|
||||
|
|
@ -33,12 +30,12 @@ try
|
|||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
lt::log::critical("Terminating due to uncaught exception:");
|
||||
lt::log::critical("\texception.what: {}:", exp.what());
|
||||
log_crt("Terminating due to uncaught exception:");
|
||||
log_crt("\texception.what: {}:", exp.what());
|
||||
|
||||
return 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
export module bakers;
|
||||
#pragma once
|
||||
|
||||
import debug.assertions;
|
||||
import assets.metadata;
|
||||
import assets.shader;
|
||||
import logger;
|
||||
import std;
|
||||
#include <assets/shader.hpp>
|
||||
|
||||
export void bake_shader(
|
||||
inline void bake_shader(
|
||||
const std::filesystem::path &in_path,
|
||||
const std::filesystem::path &out_path,
|
||||
lt::assets::ShaderAsset::Type type
|
||||
|
|
@ -15,27 +11,29 @@ export void bake_shader(
|
|||
using lt::assets::ShaderAsset;
|
||||
using enum lt::assets::ShaderAsset::Type;
|
||||
|
||||
auto glsl_path = std::string { in_path.string() };
|
||||
auto glsl_path = in_path.string();
|
||||
auto spv_path = std::format("{}.spv", glsl_path);
|
||||
lt::log::trace(
|
||||
log_trc(
|
||||
"Compiling {} shader {} -> {}",
|
||||
type == vertex ? "vertex" : "fragment",
|
||||
std::string { glsl_path },
|
||||
std::string { spv_path }
|
||||
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());
|
||||
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(
|
||||
lt::ensure(
|
||||
stream.is_open(),
|
||||
"Failed to open compiled {} shader at: {}",
|
||||
type == vertex ? "vert" : "frag",
|
||||
|
|
@ -48,7 +46,7 @@ export void bake_shader(
|
|||
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());
|
||||
log_dbg("BYTES: {}", bytes.size());
|
||||
stream.close();
|
||||
std::filesystem::remove(spv_path);
|
||||
|
||||
162
modules/asset_parser/private/assets/text.cpp
Normal file
162
modules/asset_parser/private/assets/text.cpp
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
#include <asset_parser/assets/text.hpp>
|
||||
|
||||
namespace Assets {
|
||||
|
||||
/* static */ void TextAsset::pack(const PackageData &data, const std::filesystem::path &out_path)
|
||||
{
|
||||
const auto &[metadata, text_metadata, text] = 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 Text 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 *)&text_metadata, sizeof(text_metadata));
|
||||
|
||||
constexpr auto number_of_blobs = uint32_t { 1 };
|
||||
stream.write((char *)&number_of_blobs, sizeof(number_of_blobs));
|
||||
|
||||
auto textblob_metadata = BlobMetadata {
|
||||
.tag = BlobMetadata::Tag::text,
|
||||
.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
|
||||
.compression_type = CompressionType::None,
|
||||
.compressed_size = text.size(),
|
||||
.uncompressed_size = text.size(),
|
||||
};
|
||||
|
||||
stream.write((char *)&textblob_metadata, sizeof(textblob_metadata));
|
||||
stream.write((char *)text.data(), static_cast<long>(text.size()));
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
|
||||
}
|
||||
|
||||
TextAsset::TextAsset(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 Text 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 Text asset: invalid number of blobs: {}", num_blobs)
|
||||
};
|
||||
}
|
||||
|
||||
m_stream.read((char *)&m_text_blob_metadata, sizeof(m_text_blob_metadata));
|
||||
if (m_text_blob_metadata.tag != BlobMetadata::Tag::text)
|
||||
{
|
||||
throw std::runtime_error {
|
||||
std::format(
|
||||
"Failed to load Text asset: invalid blob tag, expected {}, got {}",
|
||||
std::to_underlying(BlobMetadata::Tag::text),
|
||||
std::to_underlying(m_text_blob_metadata.tag)
|
||||
),
|
||||
};
|
||||
}
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
|
||||
}
|
||||
|
||||
void TextAsset::unpack_blob(
|
||||
BlobMetadata::Tag tag,
|
||||
std::byte *destination,
|
||||
size_t destination_capacity
|
||||
) const
|
||||
{
|
||||
if (tag != BlobMetadata::Tag::text)
|
||||
{
|
||||
throw std::runtime_error {
|
||||
std::format("Invalid tag for unpack_blob of TextAsset: {}", std::to_underlying(tag))
|
||||
};
|
||||
}
|
||||
|
||||
m_stream.seekg(static_cast<long>(m_text_blob_metadata.offset));
|
||||
switch (m_text_blob_metadata.compression_type)
|
||||
{
|
||||
case Assets::CompressionType::None:
|
||||
if (m_text_blob_metadata.uncompressed_size != m_text_blob_metadata.compressed_size)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Failed to unpack blob from TextAsset: "
|
||||
"compressed/uncompressed size mismatch for no compression "
|
||||
"type"
|
||||
);
|
||||
}
|
||||
|
||||
if (m_text_blob_metadata.uncompressed_size > destination_capacity)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Failed to unpack blob from TextAsset: "
|
||||
"uncompressed_size > destination_capacity, unpacking "
|
||||
"would result in segfault"
|
||||
);
|
||||
}
|
||||
|
||||
if (!m_stream.is_open())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Failed to unpack blob from TextAsset: ifstream is "
|
||||
"closed"
|
||||
);
|
||||
}
|
||||
|
||||
m_stream.read(
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
||||
(char *)destination,
|
||||
static_cast<long>(m_text_blob_metadata.uncompressed_size)
|
||||
);
|
||||
|
||||
return;
|
||||
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
std::format(
|
||||
"Failed to unpack blob from TextAsset: unsupported "
|
||||
"compression type: {}",
|
||||
std::to_underlying(m_text_blob_metadata.compression_type)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] auto TextAsset::get_asset_metadata() const -> const Asset::Metadata &
|
||||
{
|
||||
return m_asset_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto TextAsset::get_metadata() const -> const Metadata &
|
||||
{
|
||||
return m_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto TextAsset::get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &
|
||||
{
|
||||
if (tag != BlobMetadata::Tag::text)
|
||||
{
|
||||
throw std::runtime_error { std::format(
|
||||
"Invalid tag for get_blob_metadata of TextAsset: {}",
|
||||
std::to_underlying(tag)
|
||||
) };
|
||||
}
|
||||
|
||||
return m_text_blob_metadata;
|
||||
}
|
||||
|
||||
} // namespace Assets
|
||||
5
modules/assets/CMakeLists.txt
Normal file
5
modules/assets/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
add_library_module(assets shader.cpp)
|
||||
|
||||
target_link_libraries(assets PUBLIC logger lt_debug)
|
||||
|
||||
add_test_module(assets shader.test.cpp)
|
||||
|
|
@ -1,80 +1,4 @@
|
|||
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
|
||||
|
||||
#include <assets/shader.hpp>
|
||||
|
||||
namespace lt::assets {
|
||||
|
||||
|
|
@ -90,14 +14,14 @@ constexpr auto total_metadata_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());
|
||||
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(
|
||||
const auto file_size = static_cast<size_t>(m_stream.tellg());
|
||||
ensure(
|
||||
file_size > total_metadata_size,
|
||||
"Failed to open shader asset at: {}, file smaller than metadata: {} < {}",
|
||||
path.string(),
|
||||
|
|
@ -115,7 +39,7 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
read(m_code_blob_metadata.compressed_size);
|
||||
read(m_code_blob_metadata.uncompressed_size);
|
||||
|
||||
debug::ensure(
|
||||
ensure(
|
||||
m_asset_metadata.type == asset_type_identifier,
|
||||
"Failed to open shader asset at: {}, incorrect asset type: {} != {}",
|
||||
path.string(),
|
||||
|
|
@ -123,7 +47,7 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
asset_type_identifier
|
||||
);
|
||||
|
||||
debug::ensure(
|
||||
ensure(
|
||||
m_asset_metadata.version == current_version,
|
||||
"Failed to open shader asset at: {}, version mismatch: {} != {}",
|
||||
path.string(),
|
||||
|
|
@ -131,21 +55,21 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
current_version
|
||||
);
|
||||
|
||||
debug::ensure(
|
||||
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(
|
||||
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(
|
||||
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(),
|
||||
|
|
@ -175,7 +99,7 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
.uncompressed_size = code_blob.size(),
|
||||
};
|
||||
|
||||
debug::ensure(stream.is_open(), "Failed to pack shader asset to {}", destination.string());
|
||||
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));
|
||||
};
|
||||
|
|
@ -192,18 +116,14 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
|
|||
|
||||
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)
|
||||
);
|
||||
ensure(tag == BlobTag::code, "Invalid blob tag for shader asset: {}", std::to_underlying(tag));
|
||||
|
||||
debug::ensure(
|
||||
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()),
|
||||
std::bit_cast<size_t>(destination.data()),
|
||||
destination.size(),
|
||||
m_code_blob_metadata.uncompressed_size
|
||||
);
|
||||
|
|
@ -217,11 +137,7 @@ void ShaderAsset::unpack_to(BlobTag tag, std::span<std::byte> destination) const
|
|||
|
||||
[[nodiscard]] auto ShaderAsset::unpack(BlobTag tag) const -> Blob
|
||||
{
|
||||
debug::ensure(
|
||||
tag == BlobTag::code,
|
||||
"Invalid blob tag for shader asset: {}",
|
||||
std::to_underlying(tag)
|
||||
);
|
||||
ensure(tag == BlobTag::code, "Invalid blob tag for shader asset: {}", std::to_underlying(tag));
|
||||
|
||||
auto blob = Blob(m_code_blob_metadata.uncompressed_size);
|
||||
unpack_to(tag, blob);
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
import assets.metadata;
|
||||
import assets.shader;
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import std;
|
||||
#include <assets/shader.hpp>
|
||||
#include <ranges>
|
||||
#include <test/test.hpp>
|
||||
|
||||
using ::lt::assets::AssetMetadata;
|
||||
using ::lt::assets::BlobMetadata;
|
||||
|
|
@ -12,7 +10,6 @@ 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/" };
|
||||
|
|
@ -73,7 +70,7 @@ Suite packing = "shader_pack"_suite = [] {
|
|||
expect_true(stream.is_open());
|
||||
|
||||
stream.seekg(0, std::ios::end);
|
||||
const auto file_size = static_cast<std::size_t>(stream.tellg());
|
||||
const auto file_size = static_cast<size_t>(stream.tellg());
|
||||
expect_eq(file_size, expected_size);
|
||||
stream.close();
|
||||
|
||||
3
modules/assets/public/compressors/lz4.hpp
Normal file
3
modules/assets/public/compressors/lz4.hpp
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
// TO BE DOOO
|
||||
|
|
@ -1,19 +1,18 @@
|
|||
export module assets.metadata;
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
export namespace lt::assets {
|
||||
namespace lt::assets {
|
||||
|
||||
using Type_T = std::array<const char, 16>;
|
||||
|
||||
using Tag_T = std::uint8_t;
|
||||
using Tag_T = uint8_t;
|
||||
|
||||
using Version = std::uint8_t;
|
||||
using Version = uint8_t;
|
||||
|
||||
using Blob = std::vector<std::byte>;
|
||||
|
||||
constexpr auto current_version = Version { 1u };
|
||||
|
||||
enum class CompressionType : std::uint8_t
|
||||
enum class CompressionType : uint8_t
|
||||
{
|
||||
none,
|
||||
lz4,
|
||||
|
|
@ -31,13 +30,13 @@ struct BlobMetadata
|
|||
{
|
||||
Tag_T tag;
|
||||
|
||||
std::size_t offset;
|
||||
size_t offset;
|
||||
|
||||
CompressionType compression_type;
|
||||
|
||||
std::size_t compressed_size;
|
||||
size_t compressed_size;
|
||||
|
||||
std::size_t uncompressed_size;
|
||||
size_t uncompressed_size;
|
||||
};
|
||||
|
||||
} // namespace lt::assets
|
||||
74
modules/assets/public/shader.hpp
Normal file
74
modules/assets/public/shader.hpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
|
||||
#include <assets/metadata.hpp>
|
||||
|
||||
namespace lt::assets {
|
||||
|
||||
class ShaderAsset
|
||||
{
|
||||
public:
|
||||
static constexpr auto asset_type_identifier = Type_T { "SHADER_________" };
|
||||
|
||||
enum class BlobTag : Tag_T
|
||||
{
|
||||
code,
|
||||
};
|
||||
|
||||
enum class Type : uint8_t
|
||||
{
|
||||
vertex,
|
||||
fragment,
|
||||
geometry,
|
||||
compute,
|
||||
};
|
||||
|
||||
struct Metadata
|
||||
{
|
||||
Type type;
|
||||
};
|
||||
|
||||
static void pack(
|
||||
const std::filesystem::path &destination,
|
||||
AssetMetadata asset_metadata,
|
||||
Metadata metadata,
|
||||
Blob code_blob
|
||||
);
|
||||
|
||||
ShaderAsset(const std::filesystem::path &path);
|
||||
|
||||
void unpack_to(BlobTag tag, std::span<std::byte> destination) const;
|
||||
|
||||
[[nodiscard]] auto unpack(BlobTag tag) const -> Blob;
|
||||
|
||||
[[nodiscard]] auto get_asset_metadata() const -> const AssetMetadata &
|
||||
{
|
||||
return m_asset_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_metadata() const -> const Metadata &
|
||||
{
|
||||
return m_metadata;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_blob_metadata(BlobTag tag) const -> const BlobMetadata &
|
||||
{
|
||||
ensure(
|
||||
tag == BlobTag::code,
|
||||
"Invalid blob tag for shader asset: {}",
|
||||
std::to_underlying(tag)
|
||||
);
|
||||
|
||||
return m_code_blob_metadata;
|
||||
}
|
||||
|
||||
private:
|
||||
AssetMetadata m_asset_metadata {};
|
||||
|
||||
Metadata m_metadata {};
|
||||
|
||||
BlobMetadata m_code_blob_metadata {};
|
||||
|
||||
mutable std::ifstream m_stream;
|
||||
};
|
||||
|
||||
} // namespace lt::assets
|
||||
1
modules/bitwise/CMakeLists.txt
Normal file
1
modules/bitwise/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
add_library_module(bitwise)
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
export module bitwise;
|
||||
import std;
|
||||
|
||||
namespace lt::bitwise {
|
||||
|
||||
/* bit-wise */
|
||||
export constexpr auto bit(std::uint32_t x) -> std::uint32_t
|
||||
{
|
||||
return 1u << x;
|
||||
}
|
||||
|
||||
} // namespace lt::bitwise
|
||||
13
modules/bitwise/public/operations.hpp
Normal file
13
modules/bitwise/public/operations.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace lt::bitwise {
|
||||
|
||||
/* bit-wise */
|
||||
constexpr auto bit(uint32_t x) -> uint32_t
|
||||
{
|
||||
return 1u << x;
|
||||
}
|
||||
|
||||
} // namespace lt::bitwise
|
||||
3
modules/camera/CMakeLists.txt
Normal file
3
modules/camera/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
add_library_module(camera camera.cpp scene.cpp)
|
||||
|
||||
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 {
|
||||
|
||||
|
||||
}
|
||||
84
modules/camera/private/scene.cpp
Normal file
84
modules/camera/private/scene.cpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
#include <camera/camera.hpp>
|
||||
#include <camera/component.hpp>
|
||||
#include <math/algebra.hpp>
|
||||
#include <math/trig.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
SceneCamera::SceneCamera()
|
||||
: m_orthographic_specification { .size = 1000.0f, .near_plane = -1.0f, .far_plane = 10000.0f }
|
||||
, m_perspective_specification { .vertical_fov = math::radians(45.0f),
|
||||
.near_plane = 0.01f,
|
||||
.far_plane = 10000.0f }
|
||||
, m_aspect_ratio(16.0f / 9.0f)
|
||||
|
||||
{
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_viewport_size(unsigned int width, unsigned int height)
|
||||
{
|
||||
m_aspect_ratio = static_cast<float>(width) / static_cast<float>(height);
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_projection_type(ProjectionType projection_type)
|
||||
{
|
||||
m_projection_type = projection_type;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_orthographic_size(float size)
|
||||
{
|
||||
m_orthographic_specification.size = size;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_orthographic_far_plane(float far_plane)
|
||||
{
|
||||
m_orthographic_specification.far_plane = far_plane;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_orthographic_near_plane(float near_plane)
|
||||
{
|
||||
m_orthographic_specification.near_plane = near_plane;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_perspective_vertical_fov(float vertical_fov)
|
||||
{
|
||||
m_perspective_specification.vertical_fov = vertical_fov;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_perspective_far_plane(float far_plane)
|
||||
{
|
||||
m_perspective_specification.far_plane = far_plane;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::set_perspective_near_plane(float near_plane)
|
||||
{
|
||||
m_perspective_specification.near_plane = near_plane;
|
||||
calculate_projection();
|
||||
}
|
||||
|
||||
void SceneCamera::calculate_projection()
|
||||
{
|
||||
// TODO(Light): implement ortho perspective
|
||||
if (m_projection_type == ProjectionType::Orthographic)
|
||||
{
|
||||
// throw std::runtime_error { "ortho perspective not supported yet" };
|
||||
}
|
||||
|
||||
// defaults to perspective for now...
|
||||
m_projection = math::perspective(
|
||||
m_perspective_specification.vertical_fov,
|
||||
m_aspect_ratio,
|
||||
m_perspective_specification.near_plane,
|
||||
m_perspective_specification.far_plane
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace lt
|
||||
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
|
||||
4
modules/debug/CMakeLists.txt
Normal file
4
modules/debug/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
add_library_module(lt_debug instrumentor.cpp)
|
||||
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,146 +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;
|
||||
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);
|
||||
}
|
||||
} // namespace lt::debug
|
||||
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 <format>
|
||||
#include <logger/logger.hpp>
|
||||
#include <source_location>
|
||||
|
||||
namespace lt {
|
||||
|
||||
template<typename Expression_T, typename... Args_T>
|
||||
struct ensure
|
||||
{
|
||||
ensure(
|
||||
const Expression_T &expression,
|
||||
std::format_string<Args_T...> fmt,
|
||||
Args_T &&...args,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
)
|
||||
{
|
||||
if (!static_cast<bool>(expression))
|
||||
{
|
||||
throw std::runtime_error { std::format(
|
||||
"exception: {}\nlocation: {}:{}",
|
||||
std::format(fmt, std::forward<Args_T>(args)...),
|
||||
location.file_name(),
|
||||
location.line()
|
||||
) };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Expression_T, typename... Args_T>
|
||||
ensure(Expression_T, std::format_string<Args_T...>, Args_T &&...)
|
||||
-> ensure<Expression_T, Args_T...>;
|
||||
|
||||
} // namespace lt
|
||||
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()
|
||||
4
modules/ecs/CMakeLists.txt
Normal file
4
modules/ecs/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
add_library_module(ecs sparse_set.cpp)
|
||||
target_link_libraries(ecs PUBLIC logger lt_debug memory)
|
||||
|
||||
add_test_module(ecs sparse_set.test.cpp registry.test.cpp)
|
||||
|
|
@ -1,17 +1,19 @@
|
|||
import ecs.registry;
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import std;
|
||||
#include <ecs/registry.hpp>
|
||||
#include <ranges>
|
||||
#include <test/expects.hpp>
|
||||
#include <test/test.hpp>
|
||||
|
||||
using ::lt::ecs::EntityId;
|
||||
using ::lt::ecs::Registry;
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::expect_eq;
|
||||
using ::lt::test::expect_false;
|
||||
using ::lt::test::expect_true;
|
||||
using ::lt::test::expect_unreachable;
|
||||
using ::lt::test::Suite;
|
||||
using ::lt::test::operator""_suite;
|
||||
using lt::test::Case;
|
||||
using lt::test::expect_unreachable;
|
||||
using lt::test::Suite;
|
||||
|
||||
using lt::test::expect_eq;
|
||||
|
||||
using lt::test::expect_false;
|
||||
using lt::test::expect_true;
|
||||
|
||||
using lt::ecs::EntityId;
|
||||
using lt::ecs::Registry;
|
||||
|
||||
struct Component
|
||||
{
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
import ecs.sparse_set;
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import std;
|
||||
#include <ecs/sparse_set.hpp>
|
||||
#include <ranges>
|
||||
#include <test/expects.hpp>
|
||||
#include <test/test.hpp>
|
||||
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::expect_eq;
|
||||
using ::lt::test::expect_false;
|
||||
using ::lt::test::expect_ne;
|
||||
using ::lt::test::expect_throw;
|
||||
using ::lt::test::expect_true;
|
||||
using ::lt::test::Suite;
|
||||
using ::lt::test::operator""_suite;
|
||||
using lt::test::Case;
|
||||
using lt::test::Suite;
|
||||
|
||||
using lt::test::expect_eq;
|
||||
using lt::test::expect_false;
|
||||
using lt::test::expect_ne;
|
||||
using lt::test::expect_throw;
|
||||
using lt::test::expect_true;
|
||||
|
||||
using Set = lt::ecs::SparseSet<int>;
|
||||
constexpr auto capacity = 100;
|
||||
|
|
@ -1,20 +1,19 @@
|
|||
export module ecs.entity;
|
||||
import debug.assertions;
|
||||
import memory.reference;
|
||||
import ecs.registry;
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
|
||||
namespace lt::ecs {
|
||||
|
||||
/** High-level entity convenience wrapper */
|
||||
export class Entity
|
||||
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);
|
||||
ensure(m_registry, "Failed to create Entity ({}): null registry", m_identifier);
|
||||
}
|
||||
|
||||
template<typename Component_T>
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
export module ecs.registry;
|
||||
import debug.assertions;
|
||||
import ecs.sparse_set;
|
||||
import memory.scope;
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
#include <ecs/sparse_set.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
|
||||
namespace lt::ecs {
|
||||
|
||||
export using EntityId = std::uint32_t;
|
||||
using EntityId = uint32_t;
|
||||
|
||||
export constexpr auto null_entity = std::numeric_limits<EntityId>::max();
|
||||
constexpr auto null_entity = std::numeric_limits<EntityId>::max();
|
||||
|
||||
/** A registry of components, the heart of an ECS architecture.
|
||||
*
|
||||
|
|
@ -23,7 +22,7 @@ export constexpr auto null_entity = std::numeric_limits<EntityId>::max();
|
|||
* @ref https://github.com/skypjack/entt
|
||||
* @ref https://github.com/SanderMertens/flecs
|
||||
*/
|
||||
export class Registry
|
||||
class Registry
|
||||
{
|
||||
public:
|
||||
using UnderlyingSparseSet_T = TypeErasedSparseSet<EntityId>;
|
||||
|
|
@ -190,25 +189,25 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] auto get_entity_count() const -> std::size_t
|
||||
[[nodiscard]] auto get_entity_count() const -> size_t
|
||||
{
|
||||
return static_cast<std::size_t>(m_entity_count);
|
||||
return static_cast<size_t>(m_entity_count);
|
||||
}
|
||||
|
||||
private:
|
||||
using TypeId = std::size_t;
|
||||
using TypeId = size_t;
|
||||
|
||||
static consteval auto hash_cstr(const char *str) -> TypeId
|
||||
{
|
||||
constexpr auto fnv_offset_basis = std::size_t { 14695981039346656037ull };
|
||||
constexpr auto fnv_prime = std::size_t { 1099511628211ull };
|
||||
constexpr auto fnv_offset_basis = size_t { 14695981039346656037ull };
|
||||
constexpr auto fnv_prime = size_t { 1099511628211ull };
|
||||
|
||||
auto hash = fnv_offset_basis;
|
||||
|
||||
for (const auto &ch : std::string_view { str })
|
||||
{
|
||||
hash *= fnv_prime;
|
||||
hash ^= static_cast<std::uint8_t>(ch);
|
||||
hash ^= static_cast<uint8_t>(ch);
|
||||
}
|
||||
|
||||
return hash;
|
||||
|
|
@ -242,7 +241,7 @@ private:
|
|||
|
||||
auto *base_set = m_sparsed_sets[type_id].get();
|
||||
auto *derived_set = dynamic_cast<SparseSet<T, EntityId> *>(base_set);
|
||||
debug::ensure(derived_set, "Failed to downcast to derived set");
|
||||
ensure(derived_set, "Failed to downcast to derived set");
|
||||
|
||||
return *derived_set;
|
||||
}
|
||||
|
|
@ -251,16 +250,11 @@ private:
|
|||
|
||||
TypeId m_entity_count;
|
||||
|
||||
/** MSVC DOES NOT SUPPORT FLAT MAP!!
|
||||
* IT"S YEAR ~2026, great...
|
||||
* using ::std::map for the time being.
|
||||
*/
|
||||
std::flat_map<TypeId, memory::Scope<UnderlyingSparseSet_T>> m_sparsed_sets;
|
||||
|
||||
std::map<TypeId, memory::Scope<UnderlyingSparseSet_T>> m_sparsed_sets;
|
||||
std::flat_map<TypeId, Callback_T> m_on_construct_hooks;
|
||||
|
||||
std::map<TypeId, Callback_T> m_on_construct_hooks;
|
||||
|
||||
std::map<TypeId, Callback_T> m_on_destruct_hooks;
|
||||
std::flat_map<TypeId, Callback_T> m_on_destruct_hooks;
|
||||
};
|
||||
|
||||
} // namespace lt::ecs
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
export module ecs.sparse_set;
|
||||
import debug.assertions;
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
namespace lt::ecs {
|
||||
|
||||
/**
|
||||
*
|
||||
* @ref https://programmingpraxis.com/2012/03/09/sparse-sets/
|
||||
*/
|
||||
export template<typename Identifier_T = std::uint32_t>
|
||||
template<typename Identifier_T = uint32_t>
|
||||
class TypeErasedSparseSet
|
||||
{
|
||||
public:
|
||||
|
|
@ -26,19 +25,19 @@ public:
|
|||
virtual void remove(Identifier_T identifier) = 0;
|
||||
};
|
||||
|
||||
export template<typename Value_T, typename Identifier_T = std::uint32_t>
|
||||
template<typename Value_T, typename Identifier_T = uint32_t>
|
||||
class SparseSet: public TypeErasedSparseSet<Identifier_T>
|
||||
{
|
||||
public:
|
||||
using Dense_T = std::pair<Identifier_T, Value_T>;
|
||||
|
||||
static constexpr auto max_capacity = std::size_t { 1'000'000 };
|
||||
static constexpr auto max_capacity = size_t { 1'000'000 };
|
||||
|
||||
static constexpr auto null_identifier = std::numeric_limits<Identifier_T>().max();
|
||||
|
||||
explicit SparseSet(std::size_t initial_capacity = 1)
|
||||
explicit SparseSet(size_t initial_capacity = 1)
|
||||
{
|
||||
debug::ensure(
|
||||
ensure(
|
||||
initial_capacity <= max_capacity,
|
||||
"Failed to create SparseSet: capacity too large ({} > {})",
|
||||
initial_capacity,
|
||||
|
|
@ -53,16 +52,13 @@ public:
|
|||
{
|
||||
if (m_sparse.size() < identifier + 1)
|
||||
{
|
||||
auto new_capacity = std::max(
|
||||
static_cast<std::size_t>(identifier + 1),
|
||||
m_sparse.size() * 2
|
||||
);
|
||||
auto new_capacity = std::max(static_cast<size_t>(identifier + 1), m_sparse.size() * 2);
|
||||
new_capacity = std::min(new_capacity, max_capacity);
|
||||
|
||||
// log::debug("Increasing sparse vector size:", m_dead_count);
|
||||
// log::debug("\tdead_count: {}", m_dead_count);
|
||||
// log::debug("\talive_count: {}", m_alive_count);
|
||||
// log::debug("\tsparse.size: {} -> {}", m_sparse.size(), new_capacity);
|
||||
// log_dbg("Increasing sparse vector size:", m_dead_count);
|
||||
// log_dbg("\tdead_count: {}", m_dead_count);
|
||||
// log_dbg("\talive_count: {}", m_alive_count);
|
||||
// log_dbg("\tsparse.size: {} -> {}", m_sparse.size(), new_capacity);
|
||||
|
||||
m_sparse.resize(new_capacity, null_identifier);
|
||||
}
|
||||
|
|
@ -149,12 +145,12 @@ public:
|
|||
return std::forward<Self_T>(self).m_dense[std::forward<Self_T>(self).m_sparse[identifier]];
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_size() const noexcept -> std::size_t
|
||||
[[nodiscard]] auto get_size() const noexcept -> size_t
|
||||
{
|
||||
return m_alive_count;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_capacity() const noexcept -> std::size_t
|
||||
[[nodiscard]] auto get_capacity() const noexcept -> size_t
|
||||
{
|
||||
return m_sparse.capacity();
|
||||
}
|
||||
|
|
@ -169,9 +165,9 @@ private:
|
|||
|
||||
std::vector<Identifier_T> m_sparse;
|
||||
|
||||
std::size_t m_alive_count {};
|
||||
size_t m_alive_count {};
|
||||
|
||||
std::size_t m_dead_count {};
|
||||
size_t m_dead_count {};
|
||||
};
|
||||
|
||||
} // namespace lt::ecs
|
||||
1
modules/env/CMakeLists.txt
vendored
Normal file
1
modules/env/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
add_library_module(env)
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
export module env;
|
||||
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
namespace lt {
|
||||
|
||||
enum class Platform : std::uint8_t
|
||||
enum class Platform : uint8_t
|
||||
{
|
||||
/** The GNU/Linux platform.
|
||||
* Tested on the following distros: arch-x86_64
|
||||
|
|
@ -26,7 +24,7 @@ enum class Platform : std::uint8_t
|
|||
};
|
||||
|
||||
/** The compiler that was used for compiling the project. */
|
||||
enum class Compiler : std::uint8_t
|
||||
enum class Compiler : uint8_t
|
||||
{
|
||||
clang,
|
||||
gcc,
|
||||
4
modules/input/CMakeLists.txt
Normal file
4
modules/input/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
add_library_module(input system.cpp)
|
||||
target_link_libraries(input PUBLIC surface math logger tbb)
|
||||
|
||||
add_test_module(input system.test.cpp)
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
export module input.events;
|
||||
|
||||
import input.codes;
|
||||
import math.vec2;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt::input {
|
||||
|
||||
export class AnalogEvent
|
||||
{
|
||||
public:
|
||||
AnalogEvent(Key key, math::uvec2 pointer_position)
|
||||
: m_key(key)
|
||||
, m_pointer_position(pointer_position)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_key() const -> Key
|
||||
{
|
||||
return m_key;
|
||||
};
|
||||
|
||||
[[nodiscard]] auto get_pointer_position() const -> math::uvec2
|
||||
{
|
||||
return m_pointer_position;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
const auto &[x, y] = m_pointer_position;
|
||||
return std::format("input::AnalogEvent: {} @ {}, {}", std::to_underlying(m_key), x, y);
|
||||
}
|
||||
|
||||
private:
|
||||
Key m_key;
|
||||
|
||||
math::uvec2 m_pointer_position;
|
||||
};
|
||||
|
||||
} // namespace lt::input
|
||||
|
|
@ -1,66 +1,9 @@
|
|||
export module input.system;
|
||||
export import :components;
|
||||
import logger;
|
||||
import app.system;
|
||||
import debug.assertions;
|
||||
import ecs.registry;
|
||||
import memory.reference;
|
||||
import surface.system;
|
||||
import surface.events;
|
||||
import math.vec2;
|
||||
import std;
|
||||
#include <input/components.hpp>
|
||||
#include <input/system.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
|
||||
namespace lt::input {
|
||||
|
||||
export class System: public app::ISystem
|
||||
{
|
||||
public:
|
||||
System(memory::Ref<ecs::Registry> registry);
|
||||
|
||||
void tick(app::TickInfo tick) override;
|
||||
|
||||
void on_register() override;
|
||||
|
||||
void on_unregister() override;
|
||||
|
||||
[[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override
|
||||
{
|
||||
return m_last_tick_result;
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_event(const surface::SurfaceComponent::Event &event);
|
||||
|
||||
void on_surface_lost_focus();
|
||||
|
||||
void on_key_press(const lt::surface::KeyPressedEvent &event);
|
||||
|
||||
void on_key_release(const lt::surface::KeyReleasedEvent &event);
|
||||
|
||||
void on_pointer_move(const lt::surface::MouseMovedEvent &event);
|
||||
|
||||
void on_button_press(const lt::surface::ButtonPressedEvent &event);
|
||||
|
||||
void on_button_release(const lt::surface::ButtonReleasedEvent &event);
|
||||
|
||||
memory::Ref<ecs::Registry> m_registry;
|
||||
|
||||
std::array<bool, 512> m_keys {};
|
||||
|
||||
std::array<bool, 512> m_buttons {};
|
||||
|
||||
math::vec2 m_pointer_position;
|
||||
|
||||
app::TickResult m_last_tick_result {};
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt::input
|
||||
|
||||
|
||||
module :private;
|
||||
namespace lt::input {
|
||||
|
||||
template<class... Ts>
|
||||
struct overloads: Ts...
|
||||
{
|
||||
|
|
@ -69,7 +12,7 @@ struct overloads: Ts...
|
|||
|
||||
System::System(memory::Ref<ecs::Registry> registry): m_registry(std::move(registry))
|
||||
{
|
||||
debug::ensure(m_registry, "Failed to initialize input system: null registry");
|
||||
ensure(m_registry, "Failed to initialize input system: null registry");
|
||||
}
|
||||
|
||||
void System::tick(app::TickInfo tick)
|
||||
|
|
@ -90,7 +33,7 @@ void System::tick(app::TickInfo tick)
|
|||
// instead of brute-force checking all of them.
|
||||
for (auto &action : input.m_actions)
|
||||
{
|
||||
auto code = std::to_underlying(action.trigger.mapped_keycode);
|
||||
auto code = action.trigger.mapped_keycode;
|
||||
if (code < m_keys.size() && m_keys[code])
|
||||
{
|
||||
if (action.state == InputAction::State::triggered)
|
||||
|
|
@ -156,28 +99,32 @@ void System::on_surface_lost_focus()
|
|||
|
||||
void System::on_key_press(const lt::surface::KeyPressedEvent &event)
|
||||
{
|
||||
if (std::to_underlying(event.get_key()) > m_keys.size())
|
||||
if (event.get_key() > m_keys.size())
|
||||
{
|
||||
log::debug("Key code larger than key container size, implement platform-dependant "
|
||||
"key-code-mapping!");
|
||||
log_dbg(
|
||||
"Key code larger than key container size, implement platform-dependant "
|
||||
"key-code-mapping!"
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_keys[std::to_underlying(event.get_key())] = true;
|
||||
m_keys[event.get_key()] = true;
|
||||
}
|
||||
|
||||
void System::on_key_release(const lt::surface::KeyReleasedEvent &event)
|
||||
{
|
||||
if (std::to_underlying(event.get_key()) > m_keys.size())
|
||||
if (event.get_key() > m_keys.size())
|
||||
{
|
||||
log::debug("Key code larger than key container size, implement platform-dependant "
|
||||
"key-code-mapping!");
|
||||
log_dbg(
|
||||
"Key code larger than key container size, implement platform-dependant "
|
||||
"key-code-mapping!"
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_keys[std::to_underlying(event.get_key())] = false;
|
||||
m_keys[event.get_key()] = false;
|
||||
}
|
||||
|
||||
void System::on_pointer_move(const lt::surface::MouseMovedEvent &event)
|
||||
|
|
@ -187,12 +134,12 @@ void System::on_pointer_move(const lt::surface::MouseMovedEvent &event)
|
|||
|
||||
void System::on_button_press(const lt::surface::ButtonPressedEvent &event)
|
||||
{
|
||||
m_buttons[std::to_underlying(event.get_button())] = true;
|
||||
m_buttons[event.get_button()] = true;
|
||||
}
|
||||
|
||||
void System::on_button_release(const lt::surface::ButtonReleasedEvent &event)
|
||||
{
|
||||
m_buttons[std::to_underlying(event.get_button())] = false;
|
||||
m_buttons[event.get_button()] = false;
|
||||
}
|
||||
|
||||
} // namespace lt::input
|
||||
|
|
@ -1,17 +1,11 @@
|
|||
import std;
|
||||
import input.system;
|
||||
import input.codes;
|
||||
import std;
|
||||
import test.test;
|
||||
import test.expects;
|
||||
import surface.events;
|
||||
import memory.scope;
|
||||
import memory.reference;
|
||||
import app.system;
|
||||
import ecs.entity;
|
||||
import ecs.registry;
|
||||
import surface.system;
|
||||
|
||||
#include <ecs/entity.hpp>
|
||||
#include <input/components.hpp>
|
||||
#include <input/system.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
#include <ranges>
|
||||
#include <surface/system.hpp>
|
||||
#include <test/test.hpp>
|
||||
|
||||
// NOLINTBEGIN
|
||||
using namespace lt;
|
||||
|
|
@ -23,7 +17,6 @@ using test::expect_eq;
|
|||
using test::expect_false;
|
||||
using test::expect_ne;
|
||||
using test::expect_not_nullptr;
|
||||
using test::operator""_suite;
|
||||
using test::expect_throw;
|
||||
using test::Suite;
|
||||
// NOLINTEND
|
||||
|
|
@ -162,7 +155,7 @@ Suite tick = "tick"_suite = [] {
|
|||
auto action_key = input.add_action(
|
||||
{
|
||||
.name { "test" },
|
||||
.trigger = { .mapped_keycode = Key::A },
|
||||
.trigger = { .mapped_keycode = 69 },
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -170,7 +163,7 @@ Suite tick = "tick"_suite = [] {
|
|||
system.tick(tick_info());
|
||||
expect_eq(input.get_action(action_key).state, input::InputAction::State::inactive);
|
||||
|
||||
surface.push_event(surface::KeyPressedEvent(Key::A));
|
||||
surface.push_event(surface::KeyPressedEvent(69));
|
||||
system.tick(tick_info());
|
||||
expect_eq(input.get_action(action_key).state, input::InputAction::State::triggered);
|
||||
|
||||
|
|
@ -182,7 +175,7 @@ Suite tick = "tick"_suite = [] {
|
|||
system.tick(tick_info());
|
||||
expect_eq(input.get_action(action_key).state, input::InputAction::State::active);
|
||||
|
||||
surface.push_event(surface::KeyReleasedEvent(Key::A));
|
||||
surface.push_event(surface::KeyReleasedEvent(69));
|
||||
system.tick(tick_info());
|
||||
expect_eq(input.get_action(action_key).state, input::InputAction::State::inactive);
|
||||
};
|
||||
|
|
@ -202,7 +195,7 @@ Suite tick = "tick"_suite = [] {
|
|||
auto action_key = input.add_action(
|
||||
{
|
||||
.name { "test" },
|
||||
.trigger = { .mapped_keycode = Key::A },
|
||||
.trigger = { .mapped_keycode = 69 },
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
@ -1,17 +1,19 @@
|
|||
export module input.system:components;
|
||||
import input.codes;
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace lt::input {
|
||||
|
||||
export struct Trigger
|
||||
struct Trigger
|
||||
{
|
||||
Key mapped_keycode;
|
||||
uint32_t mapped_keycode;
|
||||
};
|
||||
|
||||
export struct InputAction
|
||||
struct InputAction
|
||||
{
|
||||
enum class State : std::uint8_t
|
||||
using Key = size_t;
|
||||
|
||||
enum class State : uint8_t
|
||||
{
|
||||
inactive,
|
||||
active,
|
||||
|
|
@ -26,18 +28,18 @@ export struct InputAction
|
|||
Trigger trigger;
|
||||
};
|
||||
|
||||
export class InputComponent
|
||||
class InputComponent
|
||||
{
|
||||
public:
|
||||
InputComponent() = default;
|
||||
|
||||
auto add_action(InputAction action) -> std::size_t
|
||||
auto add_action(InputAction action) -> size_t
|
||||
{
|
||||
m_actions.emplace_back(std::move(action));
|
||||
return m_actions.size() - 1;
|
||||
}
|
||||
|
||||
auto get_action(std::size_t idx) -> const InputAction &
|
||||
auto get_action(auto idx) -> const InputAction &
|
||||
{
|
||||
return m_actions[idx];
|
||||
}
|
||||
44
modules/input/public/events.hpp
Normal file
44
modules/input/public/events.hpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include <math/vec2.hpp>
|
||||
|
||||
namespace lt::input {
|
||||
|
||||
class AnalogEvent
|
||||
{
|
||||
public:
|
||||
AnalogEvent(uint32_t input_code, math::uvec2 pointer_position)
|
||||
: m_input_code(input_code)
|
||||
, m_pointer_position(pointer_position)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_code() const -> uint32_t
|
||||
{
|
||||
return m_input_code;
|
||||
};
|
||||
|
||||
[[nodiscard]] auto get_pointer_position() const -> math::uvec2
|
||||
{
|
||||
return m_pointer_position;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto to_string() const -> std::string
|
||||
{
|
||||
auto stream = std::stringstream {};
|
||||
const auto &[x, y] = m_pointer_position;
|
||||
stream << "input::AnalogEvent: " << m_input_code << " @ " << x << ", " << y;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_input_code;
|
||||
|
||||
math::uvec2 m_pointer_position;
|
||||
};
|
||||
|
||||
class AxisEvent
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace lt::input
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
export module input.codes;
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
export enum class Key: std::uint16_t {
|
||||
#include <cstdint>
|
||||
|
||||
namespace lt::Key {
|
||||
|
||||
enum : uint16_t
|
||||
{
|
||||
/* digits */
|
||||
D0 = 48,
|
||||
D1 = 49,
|
||||
|
|
@ -170,4 +174,7 @@ export enum class Key: std::uint16_t {
|
|||
Pause = 284,
|
||||
|
||||
Menu = 348,
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
23
modules/input/public/mouse_codes.hpp
Normal file
23
modules/input/public/mouse_codes.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace lt::Mouse {
|
||||
|
||||
enum : uint8_t
|
||||
{
|
||||
Button1 = 0,
|
||||
Button2 = 1,
|
||||
Button3 = 2,
|
||||
Button4 = 3,
|
||||
Button5 = 4,
|
||||
Button6 = 5,
|
||||
Button7 = 6,
|
||||
Button8 = 7,
|
||||
|
||||
LButton = Button1,
|
||||
RButton = Button2,
|
||||
MButton = Button3,
|
||||
};
|
||||
|
||||
}
|
||||
55
modules/input/public/system.hpp
Normal file
55
modules/input/public/system.hpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/system.hpp>
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <surface/components.hpp>
|
||||
#include <surface/events/keyboard.hpp>
|
||||
#include <surface/events/mouse.hpp>
|
||||
|
||||
namespace lt::input {
|
||||
|
||||
class System: public app::ISystem
|
||||
{
|
||||
public:
|
||||
System(memory::Ref<ecs::Registry> registry);
|
||||
|
||||
void tick(app::TickInfo tick) override;
|
||||
|
||||
void on_register() override;
|
||||
|
||||
void on_unregister() override;
|
||||
|
||||
[[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override
|
||||
{
|
||||
return m_last_tick_result;
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_event(const surface::SurfaceComponent::Event &event);
|
||||
|
||||
void on_surface_lost_focus();
|
||||
|
||||
void on_key_press(const lt::surface::KeyPressedEvent &event);
|
||||
|
||||
void on_key_release(const lt::surface::KeyReleasedEvent &event);
|
||||
|
||||
void on_pointer_move(const lt::surface::MouseMovedEvent &event);
|
||||
|
||||
void on_button_press(const lt::surface::ButtonPressedEvent &event);
|
||||
|
||||
void on_button_release(const lt::surface::ButtonReleasedEvent &event);
|
||||
|
||||
memory::Ref<ecs::Registry> m_registry;
|
||||
|
||||
std::array<bool, 512> m_keys {};
|
||||
|
||||
std::array<bool, 512> m_buttons {};
|
||||
|
||||
math::vec2 m_pointer_position;
|
||||
|
||||
app::TickResult m_last_tick_result {};
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt::input
|
||||
1
modules/logger/CMakeLists.txt
Normal file
1
modules/logger/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
add_library_module(logger logger.cpp)
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
export module logger;
|
||||
|
||||
import std;
|
||||
|
||||
namespace lt::log {
|
||||
|
||||
/** Severity of a log message. */
|
||||
enum class Level : std::uint8_t
|
||||
{
|
||||
/** Lowest and most vebose log level, for tracing execution paths and events */
|
||||
trace = 0,
|
||||
|
||||
/** Vebose log level, for enabling temporarily to debug */
|
||||
debug = 1,
|
||||
|
||||
/** General information */
|
||||
info = 2,
|
||||
|
||||
/** Things we should to be aware of and edge cases */
|
||||
warn = 3,
|
||||
|
||||
/** Defects, bugs and undesired behaviour */
|
||||
error = 4,
|
||||
|
||||
/** Unrecoverable errors */
|
||||
critical = 5,
|
||||
|
||||
/** No logging */
|
||||
off = 6,
|
||||
};
|
||||
|
||||
namespace details {
|
||||
|
||||
inline auto thread_hash_id() noexcept -> std::uint64_t
|
||||
{
|
||||
return static_cast<std::uint64_t>(std::hash<std::thread::id> {}(std::this_thread::get_id()));
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
template<typename... Args>
|
||||
struct [[maybe_unused]] print
|
||||
{
|
||||
[[maybe_unused]] print(
|
||||
Level level,
|
||||
const std::source_location &location,
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments
|
||||
) noexcept
|
||||
{
|
||||
constexpr auto to_string = [](Level level, auto location) {
|
||||
// clang-format off
|
||||
switch (level)
|
||||
{
|
||||
using enum ::lt::log::Level;
|
||||
case trace : return "\033[1;37m| trc |\033[0m";
|
||||
case debug : return "\033[1;36m| dbg |\033[0m";
|
||||
case info : return "\033[1;32m| inf |\033[0m";
|
||||
case warn : return "\033[1;33m| wrn |\033[0m";
|
||||
case error : return "\033[1;31m| err |\033[0m";
|
||||
case critical: return "\033[1;41m| crt |\033[0m";
|
||||
case off: return "off";
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
std::unreachable();
|
||||
};
|
||||
|
||||
const auto path = std::filesystem::path { location.file_name() };
|
||||
|
||||
std::println(
|
||||
"{} {} ==> {}",
|
||||
to_string(level, location),
|
||||
std::format("{}:{}", path.filename().string(), location.line()),
|
||||
std::format(format, std::forward<Args>(arguments)...)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
print(Level, const std::source_location &, std::format_string<Args...>, Args &&...) noexcept
|
||||
-> print<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] trace
|
||||
{
|
||||
[[maybe_unused]] trace(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::trace, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
trace(std::format_string<Args...>, Args &&...) noexcept -> trace<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] debug
|
||||
{
|
||||
[[maybe_unused]] debug(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::debug, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
debug(std::format_string<Args...>, Args &&...) noexcept -> debug<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] info
|
||||
{
|
||||
[[maybe_unused]] info(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::info, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
info(std::format_string<Args...>, Args &&...) noexcept -> info<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] warn
|
||||
{
|
||||
[[maybe_unused]] warn(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::warn, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
warn(std::format_string<Args...>, Args &&...) noexcept -> warn<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] error
|
||||
{
|
||||
[[maybe_unused]] error(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::error, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
error(std::format_string<Args...>, Args &&...) noexcept -> error<Args...>;
|
||||
|
||||
export template<typename... Args>
|
||||
struct [[maybe_unused]] critical
|
||||
{
|
||||
[[maybe_unused]] critical(
|
||||
std::format_string<Args...> format,
|
||||
Args &&...arguments,
|
||||
const std::source_location &location = std::source_location::current()
|
||||
) noexcept
|
||||
{
|
||||
print(Level::critical, location, format, std::forward<Args>(arguments)...);
|
||||
}
|
||||
};
|
||||
|
||||
export template<typename... Args>
|
||||
critical(std::format_string<Args...>, Args &&...) noexcept -> critical<Args...>;
|
||||
|
||||
} // namespace lt::log
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
import logger;
|
||||
import test.test;
|
||||
|
||||
using ::lt::test::Case;
|
||||
using ::lt::test::Suite;
|
||||
|
||||
Suite suite = [] {
|
||||
Case { "no format" } = [] {
|
||||
lt::log::trace("trace");
|
||||
lt::log::debug("debug");
|
||||
lt::log::info("info");
|
||||
lt::log::warn("warn");
|
||||
lt::log::error("error");
|
||||
lt::log::critical("critical");
|
||||
};
|
||||
|
||||
Case { "formatted" } = [] {
|
||||
lt::log::trace("trace {}", 69);
|
||||
lt::log::debug("debug {}", 69);
|
||||
lt::log::info("info {}", 69);
|
||||
lt::log::warn("warn {}", 69);
|
||||
lt::log::error("error {}", 69);
|
||||
lt::log::critical("critical {}", 69);
|
||||
};
|
||||
};
|
||||
1
modules/logger/private/logger.cpp
Normal file
1
modules/logger/private/logger.cpp
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include <logger/logger.hpp>
|
||||
89
modules/logger/public/logger.hpp
Normal file
89
modules/logger/public/logger.hpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#pragma once
|
||||
|
||||
#include <format>
|
||||
#include <print>
|
||||
|
||||
/** Severity of a log message. */
|
||||
enum class LogLvl : uint8_t
|
||||
{
|
||||
/** Lowest and most vebose log level, for tracing execution paths and events */
|
||||
trace = 0,
|
||||
|
||||
/** Vebose log level, for enabling temporarily to debug */
|
||||
debug = 1,
|
||||
|
||||
/** General information */
|
||||
info = 2,
|
||||
|
||||
/** Things we should to be aware of and edge cases */
|
||||
warn = 3,
|
||||
|
||||
/** Defects, bugs and undesired behaviour */
|
||||
error = 4,
|
||||
|
||||
/** Unrecoverable errors */
|
||||
critical = 5,
|
||||
|
||||
/** No logging */
|
||||
off = 6,
|
||||
};
|
||||
|
||||
/** Simple console logger */
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
void static show_imgui_window();
|
||||
|
||||
template<typename... Args>
|
||||
void static log(LogLvl lvl, std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
std::ignore = lvl;
|
||||
std::println(fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void static log(LogLvl lvl, const char *message) noexcept
|
||||
{
|
||||
std::ignore = lvl;
|
||||
std::println("{}", message);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Logger() = default;
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
void log_trc(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::trace, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log_dbg(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::debug, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log_inf(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::info, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log_wrn(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::warn, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log_err(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::error, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void log_crt(std::format_string<Args...> fmt, Args &&...args) noexcept
|
||||
{
|
||||
Logger::log(LogLvl::critical, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
1
modules/math/CMakeLists.txt
Normal file
1
modules/math/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
add_library_module(math)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
export module math.components;
|
||||
|
||||
import math.vec3;
|
||||
|
||||
namespace lt::math::components {
|
||||
|
||||
export struct Transform
|
||||
{
|
||||
math::vec3 translation;
|
||||
|
||||
math::vec3 scale;
|
||||
|
||||
math::vec3 rotation;
|
||||
};
|
||||
|
||||
} // namespace lt::math::components
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
export module math.algebra;
|
||||
import math.mat4;
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
export namespace lt::math {
|
||||
#include <math/mat4.hpp>
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
/**
|
||||
* let...
|
||||
|
|
@ -31,29 +31,25 @@ export namespace lt::math {
|
|||
*
|
||||
* the 1 at [z][3] is to save the Z axis into the resulting W for perspective division.
|
||||
*
|
||||
* @ref Thanks to pikuma for explaining the math behind this:
|
||||
* https://www.youtube.com/watch?v=EqNcqBdrNyI
|
||||
* thanks to pikuma: https://www.youtube.com/watch?v=EqNcqBdrNyI
|
||||
*/
|
||||
template<typename T>
|
||||
constexpr auto perspective(T field_of_view, T aspect_ratio, T z_near, T z_far)
|
||||
{
|
||||
const T half_fov_tan = std::tan(field_of_view / static_cast<T>(2));
|
||||
|
||||
auto result = mat4_impl<T>::identity();
|
||||
auto result = mat4_impl<T> { T { 0 } };
|
||||
|
||||
result[0][0] = T { 1 } / (aspect_ratio * half_fov_tan);
|
||||
//
|
||||
|
||||
result[1][1] = T { 1 } / (half_fov_tan);
|
||||
//
|
||||
// result[2][2] = -(z_far + z_near) / (z_far - z_near);
|
||||
//
|
||||
result[2][2] = z_far / (z_far - z_near);
|
||||
//
|
||||
|
||||
result[2][2] = -(z_far + z_near) / (z_far - z_near);
|
||||
|
||||
result[2][3] = -T { 1 };
|
||||
//
|
||||
// result[3][2] = -(T { 2 } * z_far * z_near) / (z_far - z_near);
|
||||
result[3][2] = -(z_far * z_near) / (z_far - z_near);
|
||||
//
|
||||
|
||||
result[3][2] = -(T { 2 } * z_far * z_near) / (z_far - z_near);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1,15 +1,14 @@
|
|||
export module math.mat4;
|
||||
import math.vec3;
|
||||
import math.vec4;
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
#include <math/vec3.hpp>
|
||||
#include <math/vec4.hpp>
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
export template<typename T = float>
|
||||
template<typename T = float>
|
||||
struct mat4_impl
|
||||
{
|
||||
using Column_T = vec4_impl<T>;
|
||||
|
||||
constexpr explicit mat4_impl(T scalar = 0)
|
||||
: values(
|
||||
{
|
||||
|
|
@ -44,7 +43,7 @@ struct mat4_impl
|
|||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr auto identity() -> mat4_impl<T>
|
||||
[[nodiscard]] constexpr auto identity() -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {
|
||||
{ 1 }, {}, {}, {}, //
|
||||
|
|
@ -54,12 +53,12 @@ struct mat4_impl
|
|||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) -> Column_T &
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) -> Column_T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) const -> const Column_T &
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) const -> const Column_T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
|
@ -77,34 +76,34 @@ struct mat4_impl
|
|||
std::array<Column_T, 4> values; // NOLINT
|
||||
};
|
||||
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto translate(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto translate(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto rotate(float value, const vec3_impl<T> &xyz) -> mat4_impl<T>
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto rotate(float value, const vec3_impl<T> &xyz) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto scale(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto scale(const vec3_impl<T> &value) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
export template<typename T>
|
||||
[[nodiscard]] auto inverse(const mat4_impl<T> &value) -> mat4_impl<T>
|
||||
template<typename T>
|
||||
[[nodiscard]] inline auto inverse(const mat4_impl<T> &value) -> mat4_impl<T>
|
||||
{
|
||||
return mat4_impl<T> {};
|
||||
}
|
||||
|
||||
export using mat4 = mat4_impl<float>;
|
||||
using mat4 = mat4_impl<float>;
|
||||
|
||||
export using imat4 = mat4_impl<std::int32_t>;
|
||||
using imat4 = mat4_impl<int32_t>;
|
||||
|
||||
export using umat4 = mat4_impl<std::uint32_t>;
|
||||
using umat4 = mat4_impl<uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
export module math.trig;
|
||||
#pragma once
|
||||
|
||||
export namespace lt::math {
|
||||
namespace lt::math {
|
||||
|
||||
[[nodiscard]] constexpr auto radians(float degrees) -> float
|
||||
{
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
export module math.vec2;
|
||||
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
export template<typename T = float>
|
||||
template<typename T = float>
|
||||
struct vec2_impl
|
||||
{
|
||||
constexpr vec2_impl(): x(), y()
|
||||
|
|
@ -59,15 +57,15 @@ struct vec2_impl
|
|||
};
|
||||
|
||||
|
||||
export using vec2 = vec2_impl<float>;
|
||||
using vec2 = vec2_impl<float>;
|
||||
|
||||
export using ivec2 = vec2_impl<std::int32_t>;
|
||||
using ivec2 = vec2_impl<int32_t>;
|
||||
|
||||
export using uvec2 = vec2_impl<std::uint32_t>;
|
||||
using uvec2 = vec2_impl<uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
||||
export template<typename T>
|
||||
template<typename T>
|
||||
struct std::formatter<lt::math::vec2_impl<T>>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context &context)
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
export module math.vec3;
|
||||
#pragma once
|
||||
|
||||
import math.vec2;
|
||||
import std;
|
||||
#include <cstdint>
|
||||
#include <math/vec2.hpp>
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
export template<typename T = float>
|
||||
template<typename T = float>
|
||||
struct vec3_impl
|
||||
{
|
||||
constexpr vec3_impl(): x(), y(), z()
|
||||
|
|
@ -61,11 +61,11 @@ struct vec3_impl
|
|||
T z; // NOLINT
|
||||
};
|
||||
|
||||
export using vec3 = vec3_impl<float>;
|
||||
using vec3 = vec3_impl<float>;
|
||||
|
||||
export using ivec3 = vec3_impl<std::int32_t>;
|
||||
using ivec3 = vec3_impl<int32_t>;
|
||||
|
||||
export using uvec3 = vec3_impl<std::uint32_t>;
|
||||
using uvec3 = vec3_impl<uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
export module math.vec4;
|
||||
import math.vec2;
|
||||
import math.vec3;
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace lt::math {
|
||||
|
||||
export template<typename T = float>
|
||||
template<typename T = float>
|
||||
struct vec4_impl
|
||||
{
|
||||
constexpr vec4_impl(): x(), y(), z(), w()
|
||||
|
|
@ -40,12 +40,12 @@ struct vec4_impl
|
|||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) -> T &
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) -> T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator[](std::size_t idx) const -> const T &
|
||||
[[nodiscard]] constexpr auto operator[](size_t idx) const -> const T &
|
||||
{
|
||||
return values[idx];
|
||||
}
|
||||
|
|
@ -86,15 +86,15 @@ struct vec4_impl
|
|||
};
|
||||
};
|
||||
|
||||
export using vec4 = vec4_impl<float>;
|
||||
using vec4 = vec4_impl<float>;
|
||||
|
||||
export using ivec4 = vec4_impl<std::int32_t>;
|
||||
using ivec4 = vec4_impl<int32_t>;
|
||||
|
||||
export using uvec4 = vec4_impl<std::uint32_t>;
|
||||
using uvec4 = vec4_impl<uint32_t>;
|
||||
|
||||
} // namespace lt::math
|
||||
|
||||
export template<typename T>
|
||||
template<typename T>
|
||||
struct std::formatter<lt::math::vec4_impl<T>>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context &context)
|
||||
1
modules/memory/CMakeLists.txt
Normal file
1
modules/memory/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
add_library_module(memory)
|
||||
|
|
@ -1,15 +1,13 @@
|
|||
export module memory.null_on_move;
|
||||
|
||||
import std;
|
||||
#pragma once
|
||||
|
||||
namespace lt::memory {
|
||||
|
||||
/** Holds an `Underlying_T`, assigns it to `null_value` when this object is moved.
|
||||
*
|
||||
* @note For avoiding the need to explicitly implement the move constructor for objects that hold
|
||||
* Vulkan handles. But may serve other purposes, hence why I kept the implementation generic.
|
||||
* Vulkan objects. But may server other purposes, hence why I kept the implementation generic.
|
||||
*/
|
||||
export template<typename Underlying_T, Underlying_T null_value = nullptr>
|
||||
template<typename Underlying_T, Underlying_T null_value = nullptr>
|
||||
class NullOnMove
|
||||
{
|
||||
public:
|
||||
|
|
@ -79,17 +77,12 @@ public:
|
|||
return m_value;
|
||||
}
|
||||
|
||||
operator std::uint64_t() const
|
||||
operator uint64_t() const
|
||||
{
|
||||
return (std::uint64_t)m_value;
|
||||
return (uint64_t)m_value;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get() -> Underlying_T &
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get() const -> const Underlying_T &
|
||||
[[nodiscard]] auto get() -> Underlying_T
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
export module memory.reference;
|
||||
#pragma once
|
||||
|
||||
import std;
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace lt::memory {
|
||||
|
||||
|
|
@ -9,21 +10,21 @@ namespace lt::memory {
|
|||
* @note Currently just an alias, might turn into an implementation later.
|
||||
* @ref https://en.cppreference.com/w/cpp/memory/shared_ptr.html
|
||||
*/
|
||||
export template<typename T>
|
||||
using Ref = std::shared_ptr<T>;
|
||||
template<typename t>
|
||||
using Ref = std::shared_ptr<t>;
|
||||
|
||||
/** Allocates memory for an `Underlying_T` and directly constructs it there.
|
||||
*
|
||||
* @return A Ref<Underlying_T> to the constructed object.
|
||||
*/
|
||||
export template<typename Underlying_T, typename... Args>
|
||||
template<typename Underlying_T, typename... Args>
|
||||
constexpr Ref<Underlying_T> create_ref(Args &&...args)
|
||||
{
|
||||
return std::make_shared<Underlying_T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Converts c-style pointer of type `Underlying_T` to a `Ref<Underlying_T>`. */
|
||||
export template<typename Underlying_T>
|
||||
template<typename Underlying_T>
|
||||
constexpr Ref<Underlying_T> make_ref(Underlying_T *raw_pointer)
|
||||
{
|
||||
return Ref<Underlying_T>(raw_pointer);
|
||||
|
|
@ -1,29 +1,30 @@
|
|||
export module memory.scope;
|
||||
#pragma once
|
||||
|
||||
import std;
|
||||
#include <memory/scope.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace lt::memory {
|
||||
|
||||
/** @brief Wrapper around std::unique_ptr.
|
||||
/** Wrapper around std::unique_ptr.
|
||||
*
|
||||
* @note Currently just an alias, might turn into an implementation later.
|
||||
* @ref https://en.cppreference.com/w/cpp/memory/unique_ptr.html
|
||||
*/
|
||||
export template<typename t>
|
||||
template<typename t>
|
||||
using Scope = std::unique_ptr<t>;
|
||||
|
||||
/** Allocates memory for an `Underlying_T` and directly constructs it there.
|
||||
*
|
||||
* @return A Scope<Underlying_T> to the constructed object.
|
||||
*/
|
||||
export template<typename Underlying_T, typename... Args>
|
||||
template<typename Underlying_T, typename... Args>
|
||||
constexpr Scope<Underlying_T> create_scope(Args &&...args)
|
||||
{
|
||||
return std::make_unique<Underlying_T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/** Converts c-style pointer of type `Underlying_T` to a `Scope<Underlying_T>`. */
|
||||
export template<typename Underlying_T>
|
||||
template<typename Underlying_T>
|
||||
constexpr Scope<Underlying_T> make_scope(Underlying_T *raw_pointer)
|
||||
{
|
||||
return Scope<Underlying_T>(raw_pointer);
|
||||
9
modules/mirror/CMakeLists.txt
Normal file
9
modules/mirror/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
add_library_module(libmirror)
|
||||
target_link_libraries(libmirror INTERFACE app time input surface renderer)
|
||||
|
||||
add_test_module(
|
||||
libmirror layers/editor_layer.test.cpp panels/asset_browser.test.cpp
|
||||
panels/properties.test.cpp panels/scene_hierarchy.test.cpp)
|
||||
|
||||
add_executable_module(mirror entrypoint/mirror.cpp)
|
||||
target_link_libraries(mirror PRIVATE libmirror input)
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import app;
|
||||
import app.system;
|
||||
import std;
|
||||
import logger;
|
||||
import memory.scope;
|
||||
import mirror.system;
|
||||
import renderer.factory;
|
||||
|
||||
/** The ultimate entrypoint. */
|
||||
auto main(int argc, char *argv[]) -> std::int32_t
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ignore = argc;
|
||||
std::ignore = argv;
|
||||
|
||||
auto application = lt::memory::create_scope<lt::Mirror>();
|
||||
if (!application)
|
||||
{
|
||||
throw std::runtime_error { "Failed to create application\n" };
|
||||
}
|
||||
|
||||
application->game_loop();
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception &exp)
|
||||
{
|
||||
lt::log::critical("Terminating due to uncaught exception:");
|
||||
lt::log::critical("\texception.what(): {}", exp.what());
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +1,26 @@
|
|||
export module mirror.system;
|
||||
import math.vec3;
|
||||
import camera.components;
|
||||
import surface.requests;
|
||||
import logger;
|
||||
import surface.system;
|
||||
import math.vec2;
|
||||
import math.vec4;
|
||||
import math.trig;
|
||||
import input.codes;
|
||||
import input.events;
|
||||
import input.system;
|
||||
import math.components;
|
||||
import memory.reference;
|
||||
import memory.scope;
|
||||
import renderer.components;
|
||||
import renderer.system;
|
||||
import renderer.frontend;
|
||||
import surface.events;
|
||||
import time;
|
||||
import app;
|
||||
import app.system;
|
||||
import ecs.entity;
|
||||
import ecs.registry;
|
||||
import std;
|
||||
#include <X11/keysym.h>
|
||||
#include <app/application.hpp>
|
||||
#include <app/entrypoint.hpp>
|
||||
#include <app/system.hpp>
|
||||
#include <ecs/entity.hpp>
|
||||
#include <input/components.hpp>
|
||||
#include <input/system.hpp>
|
||||
#include <math/vec2.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <memory/scope.hpp>
|
||||
#include <renderer/components/messenger.hpp>
|
||||
#include <renderer/system.hpp>
|
||||
#include <surface/events/keyboard.hpp>
|
||||
#include <surface/events/surface.hpp>
|
||||
#include <surface/system.hpp>
|
||||
#include <time/timer.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
void renderer_callback(
|
||||
renderer::IDebugger::MessageSeverity message_severity,
|
||||
renderer::IDebugger::MessageType message_type,
|
||||
renderer::IDebugger::MessageData data,
|
||||
renderer::IMessenger::MessageSeverity message_severity,
|
||||
renderer::IMessenger::MessageType message_type,
|
||||
renderer::IMessenger::MessageData data,
|
||||
std::any &user_data
|
||||
)
|
||||
{
|
||||
|
|
@ -37,7 +28,7 @@ void renderer_callback(
|
|||
std::ignore = message_type;
|
||||
std::ignore = user_data;
|
||||
|
||||
log::debug("RENDERER CALLBACK: {}", std::string { data.message });
|
||||
log_dbg("RENDERER CALLBACK: {}", data.message);
|
||||
}
|
||||
|
||||
class MirrorSystem: public lt::app::ISystem
|
||||
|
|
@ -45,8 +36,8 @@ class MirrorSystem: public lt::app::ISystem
|
|||
public:
|
||||
MirrorSystem(
|
||||
memory::Ref<ecs::Registry> registry,
|
||||
std::size_t quit_action_key,
|
||||
std::array<std::size_t, 4ul> debug_action_keys
|
||||
lt::input::InputAction::Key quit_action_key,
|
||||
std::array<lt::input::InputAction::Key, 4> debug_action_keys
|
||||
)
|
||||
: m_registry(std::move(registry))
|
||||
, m_quit_action_key(quit_action_key)
|
||||
|
|
@ -81,11 +72,7 @@ public:
|
|||
}
|
||||
if (input.get_action(m_debug_action_keys[0]).state == State::active)
|
||||
{
|
||||
for (auto &[id, camera] :
|
||||
m_registry->view<lt::camera::components::PerspectiveCamera>())
|
||||
{
|
||||
camera.vertical_fov += (static_cast<float>(tick.delta_time.count()) * 40.0f);
|
||||
}
|
||||
surface.push_request(surface::ModifyPositionRequest({ x + 5, y + 5 }));
|
||||
}
|
||||
|
||||
if (input.get_action(m_debug_action_keys[1]).state == State::active)
|
||||
|
|
@ -128,14 +115,15 @@ public:
|
|||
private:
|
||||
memory::Ref<ecs::Registry> m_registry;
|
||||
|
||||
std::size_t m_quit_action_key;
|
||||
|
||||
std::array<std::size_t, 4ul> m_debug_action_keys {};
|
||||
lt::input::InputAction::Key m_quit_action_key;
|
||||
|
||||
std::array<lt::input::InputAction::Key, 4> m_debug_action_keys {};
|
||||
|
||||
app::TickResult m_last_tick_result {};
|
||||
};
|
||||
|
||||
export class Mirror: public app::Application
|
||||
class Mirror: public app::Application
|
||||
{
|
||||
public:
|
||||
Mirror()
|
||||
|
|
@ -150,7 +138,7 @@ public:
|
|||
|
||||
void on_window_close()
|
||||
{
|
||||
log::info("Window close requested...");
|
||||
log_inf("Window close requested...");
|
||||
|
||||
unregister_system(m_input_system);
|
||||
unregister_system(m_surface_system);
|
||||
|
|
@ -176,31 +164,41 @@ public:
|
|||
);
|
||||
|
||||
auto &input = m_editor_registry->add<InputComponent>(m_window, {});
|
||||
auto quit_action_key = input.add_action(input::InputAction {
|
||||
.name = "quit",
|
||||
.trigger = input::Trigger { .mapped_keycode = Key::Q },
|
||||
});
|
||||
auto quit_action_key = input.add_action(
|
||||
input::InputAction {
|
||||
.name = "quit",
|
||||
.trigger = input::Trigger { .mapped_keycode = XK_q },
|
||||
}
|
||||
);
|
||||
|
||||
auto debug_action_keys = std::array<std::size_t, 4ul> {};
|
||||
debug_action_keys[0] = input.add_action(input::InputAction {
|
||||
.name = "debug_1",
|
||||
.trigger = input::Trigger { .mapped_keycode = Key::D1 },
|
||||
});
|
||||
auto debug_action_keys = std::array<lt::input::InputAction::Key, 4> {};
|
||||
debug_action_keys[0] = input.add_action(
|
||||
input::InputAction {
|
||||
.name = "debug_1",
|
||||
.trigger = input::Trigger { .mapped_keycode = XK_1 },
|
||||
}
|
||||
);
|
||||
|
||||
debug_action_keys[1] = input.add_action(input::InputAction {
|
||||
.name = "debug_2",
|
||||
.trigger = input::Trigger { .mapped_keycode = Key::D2 },
|
||||
});
|
||||
debug_action_keys[1] = input.add_action(
|
||||
input::InputAction {
|
||||
.name = "debug_2",
|
||||
.trigger = input::Trigger { .mapped_keycode = XK_2 },
|
||||
}
|
||||
);
|
||||
|
||||
debug_action_keys[2] = input.add_action(input::InputAction {
|
||||
.name = "debug_3",
|
||||
.trigger = input::Trigger { .mapped_keycode = Key::D3 },
|
||||
});
|
||||
debug_action_keys[2] = input.add_action(
|
||||
input::InputAction {
|
||||
.name = "debug_3",
|
||||
.trigger = input::Trigger { .mapped_keycode = XK_3 },
|
||||
}
|
||||
);
|
||||
|
||||
debug_action_keys[3] = input.add_action(input::InputAction {
|
||||
.name = "debug_4",
|
||||
.trigger = input::Trigger { .mapped_keycode = Key::D4 },
|
||||
});
|
||||
debug_action_keys[3] = input.add_action(
|
||||
input::InputAction {
|
||||
.name = "debug_4",
|
||||
.trigger = input::Trigger { .mapped_keycode = XK_4 },
|
||||
}
|
||||
);
|
||||
|
||||
m_input_system = memory::create_ref<input::System>(m_editor_registry);
|
||||
m_mirror_system = memory::create_ref<MirrorSystem>(
|
||||
|
|
@ -215,43 +213,12 @@ public:
|
|||
.config = { .target_api = renderer::Api::vulkan, .max_frames_in_flight = 3u },
|
||||
.registry = m_editor_registry,
|
||||
.surface_entity = entity,
|
||||
.debug_callback_info = renderer::IDebugger::CreateInfo {
|
||||
.severities = renderer::IDebugger::MessageSeverity::all,
|
||||
.types = renderer::IDebugger::MessageType::all,
|
||||
.debug_callback_info = renderer::IMessenger::CreateInfo {
|
||||
.severities = renderer::IMessenger::MessageSeverity::all,
|
||||
.types = renderer::IMessenger::MessageType::all,
|
||||
.callback = &renderer_callback,
|
||||
.user_data = this,
|
||||
} });
|
||||
|
||||
m_sprite_id = m_editor_registry->create_entity();
|
||||
|
||||
m_editor_registry->add(
|
||||
m_sprite_id,
|
||||
renderer::components::Sprite {
|
||||
.color = lt::math::vec3 { 1.0f, 0.0f, 0.0f },
|
||||
}
|
||||
);
|
||||
m_editor_registry->add(
|
||||
m_sprite_id,
|
||||
math::components::Transform {
|
||||
.translation = { -5.0, -5.0, 0.5 },
|
||||
.scale = { 5.0, 5.0, 1.0 },
|
||||
.rotation = {},
|
||||
}
|
||||
);
|
||||
|
||||
m_camera_id = m_editor_registry->create_entity();
|
||||
|
||||
m_editor_registry->add(
|
||||
m_camera_id,
|
||||
camera::components::PerspectiveCamera {
|
||||
.vertical_fov = math::radians(90.0f),
|
||||
.near_plane = 0.1f,
|
||||
.far_plane = 30.0,
|
||||
.aspect_ratio = 1.0f,
|
||||
.background_color = math::vec4(1.0, 0.0, 0.0, 1.0),
|
||||
.is_primary = true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void setup_input_system()
|
||||
|
|
@ -278,10 +245,11 @@ private:
|
|||
memory::Ref<MirrorSystem> m_mirror_system;
|
||||
|
||||
lt::ecs::EntityId m_window = lt::ecs::null_entity;
|
||||
|
||||
lt::ecs::EntityId m_camera_id = lt::ecs::null_entity;
|
||||
|
||||
lt::ecs::EntityId m_sprite_id = lt::ecs::null_entity;
|
||||
};
|
||||
|
||||
auto app::create_application() -> memory::Scope<app::Application>
|
||||
{
|
||||
return memory::create_scope<Mirror>();
|
||||
}
|
||||
|
||||
} // namespace lt
|
||||
|
|
@ -1,64 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include <app/layer.hpp>
|
||||
#include <imgui.h>
|
||||
#include <math/vec2.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <mirror/panels/asset_browser.hpp>
|
||||
#include <mirror/panels/properties.hpp>
|
||||
#include <mirror/panels/scene_hierarchy.hpp>
|
||||
#include <renderer/texture.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
class Scene;
|
||||
|
||||
class EditorLayer: public Layer
|
||||
{
|
||||
public:
|
||||
EditorLayer(const std::string &name);
|
||||
|
||||
~EditorLayer() override;
|
||||
|
||||
EditorLayer(EditorLayer &&) = delete;
|
||||
|
||||
EditorLayer(const EditorLayer &) = delete;
|
||||
|
||||
auto operator=(EditorLayer &&) const -> EditorLayer & = delete;
|
||||
|
||||
auto operator=(const EditorLayer &) const -> EditorLayer & = delete;
|
||||
|
||||
void on_update(float delta_time) override;
|
||||
|
||||
void on_render() override;
|
||||
|
||||
void on_user_interface_update() override;
|
||||
|
||||
private:
|
||||
std::string m_scene_dir;
|
||||
|
||||
math::vec2 m_direction;
|
||||
|
||||
float m_speed = 1000.0f;
|
||||
|
||||
memory::Ref<Scene> m_scene;
|
||||
|
||||
memory::Ref<SceneHierarchyPanel> m_sceneHierarchyPanel;
|
||||
|
||||
memory::Ref<PropertiesPanel> m_properties_panel;
|
||||
|
||||
memory::Ref<AssetBrowserPanel> m_content_browser_panel;
|
||||
|
||||
memory::Ref<Framebuffer> m_framebuffer;
|
||||
|
||||
Entity m_camera_entity;
|
||||
|
||||
ImVec2 m_available_content_region_prev;
|
||||
};
|
||||
|
||||
} // namespace lt
|
||||
|
||||
|
||||
#include <app/application.hpp>
|
||||
#include <asset_manager/asset_manager.hpp>
|
||||
#include <camera/component.hpp>
|
||||
|
|
@ -1,51 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory/reference.hpp>
|
||||
#include <mirror/panels/panel.hpp>
|
||||
#include <renderer/texture.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
class Scene;
|
||||
|
||||
class AssetBrowserPanel: public Panel
|
||||
{
|
||||
public:
|
||||
AssetBrowserPanel(memory::Ref<Scene> active_scene);
|
||||
|
||||
void on_user_interface_update();
|
||||
|
||||
private:
|
||||
enum class AssetType
|
||||
{
|
||||
none = 0,
|
||||
scene,
|
||||
directory,
|
||||
text,
|
||||
image,
|
||||
};
|
||||
|
||||
std::filesystem::path m_current_directory;
|
||||
|
||||
const std::filesystem::path m_assets_path;
|
||||
|
||||
float m_file_size = 128.0f;
|
||||
|
||||
float m_file_padding = 8.0f;
|
||||
|
||||
memory::Ref<Scene> m_active_scene;
|
||||
|
||||
memory::Ref<Texture> m_directory_texture;
|
||||
|
||||
memory::Ref<Texture> m_scene_texture;
|
||||
|
||||
memory::Ref<Texture> m_image_texture;
|
||||
|
||||
memory::Ref<Texture> m_text_texture;
|
||||
};
|
||||
|
||||
} // namespace lt
|
||||
#include <asset_manager/asset_manager.hpp>
|
||||
#include <ecs/registry.hpp>
|
||||
#include <ecs/serializer.hpp>
|
||||
|
|
@ -157,7 +109,7 @@ void AssetBrowserPanel::on_user_interface_update()
|
|||
))
|
||||
{
|
||||
auto serializer = SceneSerializer { m_active_scene };
|
||||
log::info("Attempting to deserialize: {}", path.string());
|
||||
log_inf("Attempting to deserialize: {}", path.string());
|
||||
serializer.deserialize(path.string());
|
||||
}
|
||||
break;
|
||||
|
|
@ -1,36 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include <ecs/entity.hpp>
|
||||
#include <math/vec3.hpp>
|
||||
#include <mirror/panels/panel.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
class PropertiesPanel: public Panel
|
||||
{
|
||||
public:
|
||||
PropertiesPanel() = default;
|
||||
|
||||
void on_user_interface_update();
|
||||
|
||||
void set_entity_context(const Entity &entity);
|
||||
|
||||
private:
|
||||
void draw_vec3_control(
|
||||
const std::string &label,
|
||||
math::vec3 &values,
|
||||
float reset_value = 0.0f,
|
||||
float column_width = 100.0f
|
||||
);
|
||||
|
||||
template<typename ComponentType, typename UIFunction>
|
||||
void draw_component(const std::string &name, Entity entity, UIFunction function);
|
||||
|
||||
Entity m_entity_context;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lt
|
||||
#include <asset_manager/asset_manager.hpp>
|
||||
#include <camera/component.hpp>
|
||||
#include <ecs/components.hpp>
|
||||
|
|
@ -1,42 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include <ecs/entity.hpp>
|
||||
#include <ecs/registry.hpp>
|
||||
#include <memory/reference.hpp>
|
||||
#include <mirror/panels/panel.hpp>
|
||||
|
||||
namespace lt {
|
||||
|
||||
class PropertiesPanel;
|
||||
|
||||
class SceneHierarchyPanel: public Panel
|
||||
{
|
||||
public:
|
||||
SceneHierarchyPanel();
|
||||
|
||||
SceneHierarchyPanel(
|
||||
memory::Ref<Scene> context,
|
||||
memory::Ref<PropertiesPanel> properties_panel = nullptr
|
||||
);
|
||||
|
||||
void on_user_interface_update();
|
||||
|
||||
void set_context(
|
||||
memory::Ref<Scene> context,
|
||||
memory::Ref<PropertiesPanel> properties_panel = nullptr
|
||||
);
|
||||
|
||||
private:
|
||||
void draw_node(Entity entity, const std::string &label);
|
||||
|
||||
memory::Ref<Scene> m_context;
|
||||
|
||||
memory::Ref<PropertiesPanel> m_properties_panel_context;
|
||||
|
||||
Entity m_selection_context;
|
||||
};
|
||||
|
||||
} // namespace lt
|
||||
#include <ecs/components.hpp>
|
||||
#include <imgui.h>
|
||||
#include <memory/reference.hpp>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue