Compare commits

...
Sign in to create a new pull request.

89 commits

Author SHA1 Message Date
4a7a220af8
fix: missing display env var
Some checks are pending
continuous-integration/drone/push Build is running
2025-09-05 12:21:44 +03:30
a43243ca3f
build: differentiate between test types
Some checks are pending
continuous-integration/drone/push Build is running
fix: #41
2025-09-05 12:15:40 +03:30
5d30a56e22
revert: uncommenting the whole .drone.yml
Some checks are pending
continuous-integration/drone/push Build is running
2025-09-05 11:36:29 +03:30
51e044065a ci: documentation pipelines (#39)
All checks were successful
continuous-integration/drone/push Build is passing
fix: #36
fix: #37
Co-authored-by: light7734 <light7734@tuta.io>
Co-committed-by: light7734 <light7734@tuta.io>
2025-08-23 11:36:02 +00:00
b0caeded2a
fix(surface): invalid value_or invokation for libc++
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-08-12 15:12:17 +03:30
585d37b31b
test: add fuzz seed for surface
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-08-11 23:06:33 +03:30
4cd258bcb6
refactor(test): printable concept to accept enums
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-08-10 23:26:06 +03:30
052ac6dd5b
docs(guidelines/conventions): minor changes
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone Build was killed
2025-08-06 12:18:51 +03:30
b005857c31
docs(architecture/resource): add missing header lines 2025-08-06 12:18:36 +03:30
9389dfe7fb
docs: add features.rst & showcase.rst for light 2025-08-06 12:18:13 +03:30
40503239df
docs: setup toctree 2025-08-06 12:17:21 +03:30
552602f0af
docs: update generate_changelog.py 2025-08-06 12:16:29 +03:30
76fc5dd572
chore: add docs/generated to docs/.gitignore file 2025-08-06 12:15:43 +03:30
cd571d4a9d
docs(guidelines/development): add missing commit types 2025-08-06 12:13:31 +03:30
813e8a3a3a
docs(guidelines/development): add semantic versioning 2025-08-06 12:13:07 +03:30
d6aa5fc91d
docs: initial guidelines/philosophy content 2025-08-06 12:11:59 +03:30
bd2f74b120
docs: minor changes to architecture/assets 2025-08-06 12:11:03 +03:30
af4ce09838 docs: add generate_changelog.py script
for generating changelogs :D
2025-08-06 12:10:13 +03:30
f7591a23f4
chore: add docs/.gitignore 2025-08-06 12:07:52 +03:30
51990599a7
docs: initial revision
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-08-05 23:42:08 +03:30
459b3b961d
feat(renderer/vk): function loading & device creation
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-08-05 10:39:08 +03:30
d58f8994aa
refactor(debug): fix & improve ensure
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-31 08:42:42 +03:30
c57e5a56ac
fix(test): process_fuzz_input returning EXIT_SUCCESS on non-zero harness returns
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-31 08:13:58 +03:30
ea8986b764
fix(mirror): typo 2025-07-31 08:13:09 +03:30
e36991e6de
test(surface): add fuzz testing
test(surface): add & fix unit tests

fix(surface): bugs

refactor(surface): minor refactors & some edge-case handling
2025-07-31 08:11:05 +03:30
60ad7cdc70
feat(test): add fuzz testing support
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-30 23:02:53 +03:30
638a009047
refactor: surface, app, tests, ecs refactors
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-28 20:45:24 +03:30
a102db0699
refactor: minor adjustments to test log formattings
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-27 22:52:38 +03:30
2b96a85b62
feat: systems
Some checks reported errors
continuous-integration/drone/push Build was killed
feat: surface system

This commit puts the project in major jeopardy as it overhauls the
architecture such as removing the layer stack completely, etc.

I am filled with determination.
2025-07-26 18:01:27 +03:30
d9229ad912 build: test executable target not having private include dirs of target lib
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-25 15:07:43 +03:30
6a814bd177 style: minor fixes 2025-07-25 15:07:13 +03:30
2d019878a5 tests: add missing test cases for test/expects 2025-07-25 15:06:44 +03:30
b0ad9ff964 feat(test): expect_unreachable
feat(test): expect_throw
2025-07-25 15:06:14 +03:30
22c62bf5f9
docs: add initial guidelines/conventions
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-24 22:42:44 +03:30
d83e269432
refactor: move renderer gl/dx files to private section
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-23 10:11:55 +03:30
65f0d3bb73
fuck: fuck!
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-22 23:51:22 +03:30
0b94aaffa7
ci: add libc++ to coverage.dockerfile
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-21 19:19:39 +03:30
026f97ad0b
ci: dirty fix
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-21 19:06:37 +03:30
8720fdcebf
ci: fix llvm-cov -ignore-filename-regex pattern
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-21 18:56:20 +03:30
46505a6c24
ci: fix coverage.sh including external
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-21 18:36:58 +03:30
754b6361ad
ci: fix llvm-cov not taking into account symbol library
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-21 18:30:51 +03:30
bf485e354a
fix: amd64/clang/coverage.sh
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-21 16:19:04 +03:30
688c88f255 ci: add clang code coverage check (#10)
All checks were successful
continuous-integration/drone/push Build is passing
reviewed-on: #10
Co-authored-by: light7734 <light7734@tuta.io>
Co-committed-by: light7734 <light7734@tuta.io>
2025-07-21 09:37:44 +00:00
3998c4127a ci: add memory sanitization check (#9)
All checks were successful
continuous-integration/drone/push Build is passing
reviewed-on: #9
Co-authored-by: light7734 <light7734@tuta.io>
Co-committed-by: light7734 <light7734@tuta.io>
2025-07-20 11:12:29 +00:00
798732632a ci: major refactors & add msvc check (#8)
Some checks failed
continuous-integration/drone/push Build is failing
reviewed-on: #8
Co-authored-by: light7734 <light7734@tuta.io>
Co-committed-by: light7734 <light7734@tuta.io>
2025-07-20 04:37:05 +00:00
28010e9a92
ci: minor ci improvements
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2025-07-20 05:52:32 +03:30
9c071493c5
refactor: imgui as conan module instead of git submodule
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-20 05:20:43 +03:30
cd886aa8c9
refactor: flatten directory structure
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-20 04:46:15 +03:30
2b27f5d82b
ci: try fix windows exec runner issue
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-19 16:03:00 +03:30
9012869bf1
ci: add hello world windows exec pipeline runner test
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-19 15:57:54 +03:30
8094f0cf86 ci: add leak sanitizer ci check (#7)
Some checks reported errors
continuous-integration/drone/push Build encountered an error
reviewed-on: #7
Co-authored-by: light7734 <light7734@tuta.io>
Co-committed-by: light7734 <light7734@tuta.io>
2025-07-18 20:21:14 +00:00
bd5196a9c9
build: fix compilation on Windows
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-17 18:11:53 +03:30
dac89f64ce
build: made use of mold linker optional
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-17 17:42:18 +03:30
05f6fab1b8
ci: change ninja-build to ninja in apk installs
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-17 12:24:07 +03:30
d453982acf
ci: update static_analysis dockerfile
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-17 12:21:38 +03:30
4ff69dea7c
tools: add some logs to build_ci_images script 2025-07-17 12:17:59 +03:30
ecd2d7b8b6
tools: add build_ci_images script
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-17 12:13:11 +03:30
49cd9fecf8
ci: add ninja to .drone.yml conan build invokations
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-17 12:08:02 +03:30
4a15c5c213
ci: add ninja & mold to static_analysis ci Dockerfile 2025-07-17 12:07:35 +03:30
e02b208771
ci: add ninja cmake-toolchain-generator option to ci Dockerfiles 2025-07-17 12:04:46 +03:30
3791916a32
ci: add ninja-build package to ci Dockersfiles 2025-07-17 12:03:17 +03:30
e85374b97e
ci: add mold package to ci Dockerfiles
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-17 11:58:32 +03:30
e4c59bb51f build: change cmake build type to MOLD in conan (#6)
Some checks failed
continuous-integration/drone/push Build is failing
reviewed-on: #6
Co-authored-by: light7734 <light7734@tuta.io>
Co-committed-by: light7734 <light7734@tuta.io>
2025-07-17 08:22:33 +00:00
01d85accac ci: add valgrind check (#5)
Some checks failed
continuous-integration/drone/push Build is failing
reviewed-on: #5
Co-authored-by: light7734 <light7734@tuta.io>
Co-committed-by: light7734 <light7734@tuta.io>
2025-07-17 08:20:48 +00:00
e65b6b3f83
chore: remove glm dependency
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-17 10:45:52 +03:30
f9ce347ca0
feat: initial math module implementation
refactor: replace glm with built-in math library
2025-07-17 10:44:00 +03:30
d6b7c774bd
refactor: remove imconfig
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-16 14:42:50 +03:30
8268a07e1b
refactor: remove spdlog dependency
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-16 13:56:59 +03:30
207cd48a7a
fix: glfw window create before glfw init 2025-07-16 13:56:28 +03:30
44baac6a52
chore: remove volk dependency 2025-07-16 13:36:15 +03:30
a56f11f2a4
chore: remove spirv-cross dependency 2025-07-16 13:35:55 +03:30
3cc0801e8f
chore: remove nlohmann::json dependency
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-16 13:27:48 +03:30
3cc3da4dbe
chore: remove gtest dependency
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-16 13:26:47 +03:30
8970fa87a3
docs: remove github issue template
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-16 13:26:05 +03:30
52bf0f22f0 ci: add unit tests check (#4)
Some checks failed
continuous-integration/drone/push Build is failing
reviewed-on: #4
2025-07-16 09:55:15 +00:00
c4b9bd8359
fix: failing tests in test.tests.cpp
Some checks failed
continuous-integration/drone/pr Build is failing
2025-07-16 13:20:36 +03:30
f457e5ae19
refactor: test result output issues 2025-07-16 13:18:08 +03:30
61c898f47f
ci: fix ci step not failing on test failure
Some checks failed
continuous-integration/drone/pr Build is failing
2025-07-16 12:50:37 +03:30
c76d6e8019
feat: test executables will exit with failing code if any tests fails
Some checks failed
continuous-integration/drone/pr Build is failing
2025-07-16 12:44:58 +03:30
5f1c65d72d
fix: conflicting declaration build error from gcc
Some checks failed
continuous-integration/drone/pr Build is failing
2025-07-16 11:41:16 +03:30
60944b9d49
fix: build error on gcc
Some checks failed
continuous-integration/drone/pr Build is failing
2025-07-16 11:37:02 +03:30
5bcb4cfdd3 ci: add unit testing to drone-ci
Some checks failed
continuous-integration/drone/pr Build is failing
2025-07-16 11:32:20 +03:30
5748e0a496 ci: add unit tests Dockerfile 2025-07-16 11:32:20 +03:30
a88aa739b1
fix: build issues with NULL on some compilers
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-07-16 11:31:58 +03:30
b25ea41096
build: add enable_tests compile option
Some checks failed
continuous-integration/drone/push Build is failing
refactor: minor cmake refactor
2025-07-16 10:52:49 +03:30
a54885b02e
build: add add_test_module cmake macro
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-16 10:36:07 +03:30
5d1862f493
style: fix clang-format issues
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-15 16:31:46 +03:30
8b3990959b chore: revert accidental commit
Some checks reported errors
continuous-integration/drone/push Build was killed
This reverts commit ff2a2d3bb3.
2025-07-15 16:24:44 +03:30
ff2a2d3bb3
testing...
Some checks failed
continuous-integration/drone/push Build is failing
2025-07-15 16:21:42 +03:30
263 changed files with 8461 additions and 2875 deletions

View file

@ -1,55 +1,140 @@
---
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: clang format
clone:
recursive: true
submodule_update_remote: true
name: amd64 — gcc
trigger:
branch:
- main
steps:
- name: unit tests
image: amd64_gcc_unit_tests:latest
pull: if-not-exists
commands:
- ./tools/ci/amd64/gcc/unit_tests.sh
- name: valgrind
image: amd64_gcc_valgrind:latest
pull: if-not-exists
commands:
- ./tools/ci/amd64/gcc/valgrind.sh
---
kind: pipeline
type: docker
name: amd64 — clang
trigger:
branch:
- main
steps:
- name: code coverage
image: amd64_clang_coverage:latest
pull: if-not-exists
environment:
CODECOV_TOKEN:
from_secret: CODECOV_TOKEN
commands:
- ./tools/ci/amd64/clang/coverage.sh
- name: leak sanitizer
image: amd64_clang_lsan:latest
pull: if-not-exists
commands:
- ./tools/ci/amd64/clang/lsan.sh
- name: memory sanitizer
image: amd64_clang_msan: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: clang_tidy:latest
pull: if-not-exists
privileged: true
commands:
- ./tools/ci/static_analysis/clang_tidy.sh
- name: clang format
image: clang_format:latest
pull: if-not-exists
commands:
- |
set -e
clang-format --version
has_fomatting_issues=0
- ./tools/ci/static_analysis/clang_format.sh
for file in $(find ./modules -name '*.?pp'); do
echo "Checking format for $file"
if ! clang-format --dry-run --Werror "$file"; then
echo "❌ Formatting issue detected in $file"
has_fomatting_issues=1
fi
done
if [ "$has_fomatting_issues" -eq 0 ]; then
echo "✅ All files are properly formatted! Well done! ^~^"
fi
exit ${has_fomatting_issues}
---
kind: pipeline
type: docker
name: static analysis
clone:
recursive: true
submodule_update_remote: true
name: documentation — development
node:
environment: ryali
trigger:
branch:
- main
steps:
- name: static_analysis
image: static_analysis:latest
- name: build and deploy
image: documentation:latest
pull: if-not-exists
privileged: true
commands:
- git submodule update --init --recursive
- conan build . -s build_type=Release -o enable_static_analysis=True --build=missing
- 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:
- pwd
- cd docs
- mkdir generated
- touch generated/changelogs.rst
- touch generated/api.rst
- sphinx-build -M html . .
- rm -rf /light_docs/*
- mv ./html/* /light_docs/

View file

@ -1,36 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]: "
labels: ''
assignees: Light3039
---
**Describe the bug**
A clear and concise description of what the bug is.
**Expected behavior**
A clear and concise description of what you expected to happen.
**To Reproduce**
Steps to reproduce the behavior:
1. Make projects "..."
2. Build projects "..."
3. Run project (Mirror/Sandbox) "..."
4. Do "..."
5. See bug "..."
**System (you can omit any of the fields except OS and Console's debug output):**
- OS: [e.g. Manjaro Linux v21.1.0]
- GPU: [e.g. NVIDIA GeForce GTX 1050 Ti Mobile]
- CPU: [e.g. Intel i7-7700HQ (8) @ 3.800GHz]
- Console's debug output (omit if bug occurs before running the program):
**Screenshots**
If applicable, add screenshots to help explain your problem.
If possible add screen shot of console's debug output and neofetch.
**Additional context**
Add any other context about the problem here.

4
.gitmodules vendored
View file

@ -1,4 +0,0 @@
[submodule "external/imgui"]
path = external/imgui
url = https://github.com/ocornut/imgui
branch = docking

View file

@ -1,30 +1,43 @@
cmake_minimum_required(VERSION 3.14)
project(Light)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/macros.cmake)
include(CheckCXXSourceCompiles)
include(${CMAKE_DIR}/functions.cmake)
include(${CMAKE_DIR}/definitions.cmake)
include(${CMAKE_DIR}/dependencies.cmake)
add_option(ENABLE_STATIC_ANALYSIS "Enables clang-tidy static analysis")
add_option(ENABLE_UNIT_TESTS "Enables the building of the unit test modules")
add_option(ENABLE_FUZZ_TESTS "Enables the building of the fuzz test modules")
add_option(ENABLE_STATIC_ANALYSIS "Makes clang-tidy checks mandatory for compilation")
if (ENABLE_STATIC_ANALYSIS)
set(CMAKE_CXX_CLANG_TIDY "clang-tidy;--warnings-as-errors=*;--allow-no-checks")
endif ()
if(WIN32)
add_compile_definitions(LIGHT_PLATFORM_WINDOWS)
elseif(UNIX)
add_compile_definitions(LIGHT_PLATFORM_LINUX)
endif()
add_option(ENABLE_LLVM_COVERAGE "Enables the code coverage instrumentation for clang")
if(ENABLE_LLVM_COVERAGE)
if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
message(FATAL_ERROR "ENABLE_LLVM_COVERAGE only supports the clang compiler")
endif ()
find_package(glfw3 REQUIRED)
find_package(glm REQUIRED)
find_package(spdlog REQUIRED)
find_package(stb REQUIRED)
find_package(yaml-cpp REQUIRED)
find_package(EnTT REQUIRED)
find_package(opengl_system REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(lz4 REQUIRED)
# Check for libc++
check_cxx_source_compiles("
#include <string>
#ifdef _LIBCPP_VERSION
int main() { return 0; }
#else
#error Not using libc++
#endif
" USING_LIBCXX)
if(NOT USING_LIBCXX)
message(FATAL_ERROR "ENABLE_LLVM_COVERAGE requires libc++, please compile with -stdlib=libc++")
endif()
add_subdirectory(./modules)
add_subdirectory(./external)
add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
add_link_options(-fprofile-instr-generate -fcoverage-mapping)
endif ()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/modules)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/external/glad)

View file

@ -1,2 +1,6 @@
# Light
See docs.light7734.com for a comprehensive project documentation
<!---FUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUCK
MEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!!!!!!!!-->

View file

@ -11,26 +11,29 @@ class LightRecipe(ConanFile):
generators = "CMakeDeps"
options = {
"enable_unit_tests": [True, False],
"enable_fuzz_tests": [True, False],
"enable_llvm_coverage": [True, False],
"enable_static_analysis": [True, False],
"use_mold": [True, False],
"export_compile_commands": [True, False],
}
default_options = {
"export_compile_commands": True,
"enable_unit_tests": True,
"enable_fuzz_tests": False,
"enable_llvm_coverage": False,
"enable_static_analysis": False,
"use_mold": False,
"export_compile_commands": True,
}
def requirements(self):
self.requires("gtest/1.16.0")
self.requires("imgui/1.92.0-docking")
self.requires("entt/3.15.0")
self.requires("glfw/3.4")
self.requires("glm/1.0.1")
self.requires("spdlog/1.15.3")
self.requires("spirv-cross/1.4.313.0")
self.requires("stb/cci.20240531")
self.requires("volk/1.3.296.0")
self.requires("yaml-cpp/0.8.0")
self.requires("nlohmann_json/3.12.0")
self.requires("lz4/1.10.0")
def layout(self):
@ -41,7 +44,13 @@ class LightRecipe(ConanFile):
tc.variables["CMAKE_BUILD_TYPE"] = self.settings.build_type
if self.options.use_mold:
tc.cache_variables["CMAKE_LINKER_TYPE"] = "MOLD"
tc.cache_variables["CMAKE_EXPORT_COMPILE_COMMANDS"] = self.options.export_compile_commands
tc.cache_variables["ENABLE_UNIT_TESTS"] = self.options.enable_unit_tests
tc.cache_variables["ENABLE_FUZZ_TESTS"] = self.options.enable_fuzz_tests
tc.cache_variables["ENABLE_LLVM_COVERAGE"] = self.options.enable_llvm_coverage
tc.cache_variables["ENABLE_STATIC_ANALYSIS"] = self.options.enable_static_analysis
repo = git.Repo(search_parent_directories=True)

3
docs/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
_build/
generated/

View file

@ -1,62 +1,72 @@
Asset Management
===================================================================================================
Layout
On Disk (file) Layout
---------------------------------------------------------------------------------------------------
{version} | 4 bytes, ie. uint32_t
{general metadata} | sizeof(AssetMetadata)
{specialized metadata} | sizeof(XXXAssetMetadata), eg. TextureAssetMetadata
{n} | 4 bytes, ie. uint32_t
{blob_0...n metadata} | n * sizeof(BlobMetadata)
{blob_0...n data} | variable size based on actual data
{end marker} | 8 byte, ie size_t for marking the END
.. code-block:: md
{version} | 4 bytes, ie. uint32_t
{general metadata} | sizeof(AssetMetadata)
{specialized metadata} | sizeof(XXXAssetMetadata), eg. TextureAssetMetadata
{n} | 4 bytes, ie. uint32_t
{blob_0...n metadata} | n * sizeof(BlobMetadata)
{blob_0...n data} | variable size based on actual data
{end marker} | 8 byte, ie size_t for marking the END
Sections
---------------------------------------------------------------------------------------------------
version -> The version of the asset for forward compatibility
general metadata -> Common asset metadata such as file-path, asset-type, creator, etc.
specialized metadata -> Metadata specific to the asset, eg. texture dimensions for Textures.
n -> The number of blobs.
blob_0...n metadata -> Metadata specifying how the actual data is packed, required for unpacking.
blob_0...n data -> The actual data, packed and compressed to be reacdy for direct engine consumption.
.. code-block:: md
version -> The version of the asset for forward compatibility
general metadata -> Common asset metadata such as file-path, asset-type, creator, etc.
specialized metadata -> Metadata specific to the asset, eg. texture dimensions for Textures.
n -> The number of blobs.
blob_0...n metadata -> Metadata specifying how the actual data is packed, required for unpacking.
blob_0...n data -> The actual data, packed and compressed to be reacdy for direct engine consumption.
Loading
---------------------------------------------------------------------------------------------------
Each `Loader` has ONE OR MORE supported input file types (detected via the file extension): eg. StbLoader -> Can read in .jpg, .png, .bmp, etc.... files
Loading pre-baked asset files (like .png files) for baking:
Each `Loader` has ONLY ONE supported output asset type:
Each **Loader** has ONE OR MORE supported input file types (detected via the file extension): eg. StbLoader -> Can read in .jpg, .png, .bmp, etc.... files
Each **Loader** has ONLY ONE supported output asset type:
eg. StbLoader -> outputs TextureAsset
Multiple `Loader`s MAY have as output the same asset type:
Multiple **Loader**\s MAY have as output the same asset type:
eg. StbLoader -> outputs TextureAsset
eg. SomeOtherImgLoader -> outputs TextureAsset
Multiple `Loader`s SHOULD NOT have as input same extension types
eg. .jpg, .png -> if supported, should only be supported by 1 `Loader` class
Multiple **Loader**\s SHOULD NOT have as input same extension types
eg. .jpg, .png -> if supported, should only be supported by 1 **Loader** class
Each `Loader` SHOULD read and turn the data from a file (eg. .png for textures) into something
understandable by a `Packer` (not the engine itself).
Each **Loader** SHOULD read and turn the data from a file (eg. .png for textures) into something
understandable by a **Packer** (not the engine itself).
A `Loader` SHOULD NOT be responsible for packing the parsed file data into asset data,
A **Loader** SHOULD NOT be responsible for packing the parsed file data into asset data,
as that implies direct understanding of the layout required by the engine.
And if that layout changes, ALL `Loader`s should change accordingly;
And if that layout changes, ALL **Loader**s should change accordingly;
which makes a class that's responsible for reading files dependant on the engine's (potentially frequent) internal changes.
The logic is to reduce many-to-one dependency into a one-to-one dependency by redirecting the packing process to `Packer` classes
The logic is to reduce many-to-one dependency into a one-to-one dependency by redirecting the packing process to **Packer** classes
Packing
---------------------------------------------------------------------------------------------------
Each `Packer` is responsible for packing ONLY ONE asset type:
Each **Packer** is responsible for packing ONLY ONE asset type:
eg. TexturePacker for packing texture assets from parsed image files.
eg. ModelPacker for packing model assets from parsed model files.
Each `Packer` will output ONE OR MORE blobs of data,
Each **Packer** will output ONE OR MORE blobs of data,
and for EACH blob of data, it'll write a BlobMetadata, AFTER the specialized metadata (eg. TextureAssetMetadata)
A `Packer` will make use of the `Compressor` classes to compress the data,
A **Packer** will make use of the **Compressor** classes to compress the data,
and lay it out in a way that is suitable for the engine's consumption.
Unpacking
---------------------------------------------------------------------------------------------------
A `Parser` is responsible for parsing ONLY ONE asset type:
A **Parser** is responsible for parsing ONLY ONE asset type:
eg. TextureParser for parsing texture assets for direct engine consumption.
eg. ModelParser for parsing model assets for direct engine consumption.

View file

@ -1,4 +1,5 @@
Resource Management
.. architecture/resources
Resource Management
===================================================================================================

27
docs/conf.py Normal file
View file

@ -0,0 +1,27 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'light'
copyright = '2025, light7734'
author = 'light7734'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = []
templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = 'sphinx_rtd_theme'
html_static_path = ['_static']

View 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')

View file

@ -0,0 +1,10 @@
.. guidelines/conventions
Coding Conventions
===================================================================================================
Any line of code added to the engine, must abide by following conventions.
They may seem arbitrary, and sometimes they are. But to achieve **consistency**, which is not an arbitrary goal, is to
follow these guidelines.
AAA
--------------------

View file

@ -0,0 +1,147 @@
.. guidelines/development
Development
===================================================================================================
As a solo-project, I am not only the **developer**, but also the **manager**.
Therefore there is a need, if this project is to succeed, to have a development plan.
Such a plan should:
- Define a way to **distribute work** (across time, since there's only 1 developer).
- Define what is a **unit of work** (cycles).
- Provide a way to **track productivity**, which helps projecting the future and **detecting patterns** early on.
- Provide a **pipeline** for the work to go through and **minimize ambiguity**.
These are the **management** aspects of the project, which help the development goals to be more **pragmatic**
---by pulling my mind out of its **engineering dreamland**, and make it focus on the **broader picture**.
Cycle
---------------------------------------------------------------------------------------------------
A cycle is one **step** in development, one cycle = one ticket, and it consists of 4 stages:
1 - Make it known
- Write the commit message.
- This limits the **scope of changes** and gives you a very specific **goal** to work towards.
- If something outside of this scope really bothers you, fix and stash for a future cycle.
- Make a ticket if stash-fix is implausible ---**DO NOT** write **todo** comments.
- The message should follow the project's **commit message specifications**.
- Make a ticket.
- Version control (git) is a **development-tool**, not a **management-tool**.
- Provide a very brief description ---This may be used in the commit message's body.
2 - Make it work
- Write high-level tests that confirms the cycle's requirements are met.
- That is, specify requirements in a programming language instead of English.
- You're done when all the tests pass.
- Preferably write the tests first, but it's okay to start with the interface.
- Tests may not be necessary depending on the requirements and commit type.
- "Make it work" doesn't mean liberally producing shit code, you should:
- Follow project's **conventions**.
- Follow **best practices** and **proven swe principles**.
- Enable **warnings as errors**.
- Enable **static analysis**.
- Don't break any pre-existing-tests.
- Have the over-all picture in mind.
3 - Make it right
- Test driven refactoring
- Now you have a better picture of how things relate and work.
- Switch to a TDD-style development to do the refactoring while following swe best-practices and proven-principles.
4 - Make it fast
- This is an engine, at the end of the day, **performance** is king.
- Get a performance and/or memory profile and try to alleviate the bottlenecks.
- Avoid premature optimizations, be certain what you change has performance benefits.
Sprint
---------------------------------------------------------------------------------------------------
A sprint is the collection of all the finished cycles in one week.
It's meant to provide insight on development speed and help projecting the future.
Commit Message Specification
---------------------------------------------------------------------------------------------------
The project follows the `Conventional Commits Specification <https://www.conventionalcommits.org/en/v1.0.0-beta.4>`_.
.. code-block:: md
<type>[optional scope]: <description>
[optional body]
[optional footer]
With the following commit types:
- feat
- For adding a new feature.
- Causes a **minor** bump in version.
- fix
- For changes that fix one or more bug.
- Causes a **patch** bump in version.
- refactor
- For non feat/fix changes that improve the implementation and/or the interface.
- Causes a **patch** bump in version.
- perf
- For changes that (hopefully) improve the performance.
- Causes a **patch** bump in version.
- build
- For changes that affect the build system or external dependencies.
- Causes a **patch** bump in version.
- asset
- For changes to the files under the ``/data`` directory.
- Causes a **patch** bump in version.
- test
- For adding missing tests or correcting the existing tests.
- Does not affect the version.
- chore
- For releases, .gitignore changes, deleting unused files, etc.
- Does not affect the version.
- ci
- For changes to our CI configuration files and scripts, including files under ``/tools/ci``.
- Does not affect the version.
- docs
- For changes to the documentations.
- Does not affect the version.
Semantic Versioning
---------------------------------------------------------------------------------------------------
Coupled with conventional commit style messages, we can automajically version the project following
the **Semantic Versioning 2.0.0** specifications.
The full version identifier consits of a version core (major.minor.patch) + label + hexsha of the commit.
Using the following format:
.. code-block:: md
<major>.<minor>.<patch>-<label>+<short_hexsha>
eg.
0.8.1-kitten+ea898
0.5.0-kitten+01d85
1.5.0-akasha+7de53
kitten refers to all pre-release (1.0.0) versions
The shortened hexsha of a commit is obtained by:
``git rev-parse --short=5 <commit_hexsha>``

View file

@ -0,0 +1,7 @@
.. guidelines/philosophy
Philosophy
===================================================================================================
| **A theory or attitude that acts as a guiding principle for behaviour.**
| --- Oxford Languages

32
docs/index.rst Normal file
View file

@ -0,0 +1,32 @@
.. light documentation
.. toctree::
:maxdepth: 2
:caption: Light Engine
light/showcase.rst
light/features.rst
.. toctree::
:maxdepth: 2
:caption: Software Architecture
architecture/assets.rst
architecture/resource.rst
.. toctree::
:maxdepth: 2
:caption: Development Guidelines
guidelines/philosophy.rst
guidelines/development.rst
guidelines/conventions.rst
.. toctree::
:maxdepth: 2
:caption: Generated Docs
generated/api.rst
generated/changelog.rst

4
docs/light/features.rst Normal file
View file

@ -0,0 +1,4 @@
.. light/features
Features
===================================================================================================

4
docs/light/showcase.rst Normal file
View file

@ -0,0 +1,4 @@
.. light/demos
Showcase
===================================================================================================

35
docs/make.bat Normal file
View 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

View file

@ -1,58 +0,0 @@
# GLAD #
add_subdirectory(./glad)
set(MIRROR_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../modules/mirror/)
set(DEPENDENCIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/)
if (CMAKE_COMPILER_IS_GNUCC)
add_compile_options(-w)
endif()
if(MSVC)
add_compile_options(/MP)
add_compile_options(/W0)
endif()
file(GLOB IMGUI_FILES true ABSOLUTE
${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui.cpp
${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_tables.cpp
${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_widgets.cpp
${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_draw.cpp
${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_demo.cpp
)
set(BACKENDS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends/)
file(GLOB IMGUI_BACKEND_FILES true ABSOLUTE
${BACKENDS_DIR}imgui_impl_opengl3.cpp
${BACKENDS_DIR}imgui_impl_glfw.cpp
# ${BACKENDS_DIR}imgui_impl_vulkan.cpp ${BACKENDS_DIR}imgui_impl_vulkan.h
)
if(WIN32)
file(GLOB IMGUI_WINDOWS_BACKEND_FILES true ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR}/backends/
${BACKENDS_DIR}imgui_impl_dx11.cpp
${BACKENDS_DIR}imgui_impl_win32.cpp
)
list(APPEND IMGUI_BACKEND_FILES ${IMGUI_WINDOWS_BACKEND_FILES})
endif()
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
include_directories(${DEPENDENCIES_DIR}GLFW/include)
include_directories(${DEPENDENCIES_DIR}glm/)
add_library(imgui STATIC ${IMGUI_FILES} ${IMGUI_BACKEND_FILES})
target_include_directories(imgui PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/imgui)
target_link_libraries(
imgui
PUBLIC glad
PUBLIC opengl::opengl
PUBLIC glm::glm
PUBLIC glfw
)
# Copy imconfig.h over
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/configurations/imgui/imconfig.h
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/imgui/)

View file

@ -1,131 +0,0 @@
//-----------------------------------------------------------------------------
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
//-----------------------------------------------------------------------------
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
#pragma once
//---- Define assertion handler. Defaults to calling assert().
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
//---- Disable all of Dear ImGui or don't implement standard windows.
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger and other debug tools: ShowMetricsWindow() and ShowStackToolWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
//---- Include imgui_user.h at the end of imgui.h as a convenience
//#define IMGUI_INCLUDE_IMGUI_USER_H
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
//#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf.
// #define IMGUI_USE_STB_SPRINTF
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
//#define IMGUI_ENABLE_FREETYPE
//---- Use stb_truetype to build and rasterize the font atlas (default)
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
//#define IMGUI_ENABLE_STB_TRUETYPE
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
#include <glm/glm.hpp>
#define IM_VEC2_CLASS_EXTRA \
bool operator==(glm::vec2 rhs) { return x == rhs.x && y == rhs.y; } \
bool operator!=(glm::vec2 rhs) { return (*this) == rhs; } \
bool operator==(ImVec2 rhs) { return x == rhs.x && y == rhs.y; } \
bool operator!=(ImVec2 rhs) { return (*this) == rhs; }
#define IM_VEC4_CLASS_EXTRA \
bool operator==(glm::vec4 rhs) { return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w; } \
bool operator!=(glm::vec4 rhs) { return (*this) == rhs; } \
bool operator==(ImVec4 rhs) { return x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w; } \
bool operator!=(ImVec4 rhs) { return (*this) == rhs; }
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList;
//struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
//---- Debug Tools: Macro to break in Debugger
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#define IM_DEBUG_BREAK __debugbreak()
//---- Debug Tools: Have the Item Picker break in the ItemAdd() function instead of ItemHoverable(),
// (which comes earlier in the code, will catch a few extra items, allow picking items other than Hovered one.)
// This adds a small runtime cost which is why it is not enabled by default.
//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
//---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
/*
namespace ImGui
{
void MyFunction(const char* name, const MyMatrix44& v);
}
*/

1
external/imgui vendored

@ -1 +0,0 @@
Subproject commit 250333d895b1067533533dcfab137512745b9689

View file

@ -3,22 +3,22 @@ add_subdirectory(./base)
add_subdirectory(./time)
add_subdirectory(./logger)
add_subdirectory(./debug)
add_subdirectory(./math)
#
add_subdirectory(./asset_baker)
add_subdirectory(./asset_parser)
add_subdirectory(./asset_manager)
# add_subdirectory(./asset_manager)
#
add_subdirectory(./camera)
add_subdirectory(./input)
add_subdirectory(./ui)
add_subdirectory(./window)
add_subdirectory(./renderer)
# add_subdirectory(./input)
# add_subdirectory(./ui)
#
add_subdirectory(./surface)
# add_subdirectory(./renderer)
add_subdirectory(./ecs)
#
add_subdirectory(./app)
# apps
add_subdirectory(./mirror)
add_subdirectory(test)

View file

@ -1,21 +1,2 @@
add_library_module(app
application.cpp
layer.cpp
layer_stack.cpp
)
target_link_libraries(app
PUBLIC
renderer
logger
ui
asset_parser
asset_manager
lt_debug
ecs
window
glad
time
opengl::opengl
EnTT::EnTT
)
add_library_module(app application.cpp)
target_link_libraries(app PRIVATE lt_debug)

View file

@ -1,77 +0,0 @@
#pragma once
#include <time/timer.hpp>
namespace lt {
class Renderer;
class Window;
class Event;
class GraphicsContext;
class UserInterface;
class LayerStack;
extern Scope<class Application> create_application();
class Application
{
public:
Application(const Application &) = delete;
Application(Application &&) = delete;
auto operator=(const Application &) -> Application & = delete;
auto operator=(Application &&) -> Application & = delete;
virtual ~Application();
[[nodiscard]] auto sanity_check() const -> bool;
void game_loop();
[[nodiscard]] auto get_window() -> Window &
{
return *m_window;
}
[[nodiscard]] auto get_layer_stack() -> LayerStack &
{
return *m_layer_stack;
}
static void quit();
protected:
Application();
private:
void update_layers();
void render_layers();
void render_user_interface();
void poll_events();
void on_event(const Event &event);
void log_debug_data() const;
Timer m_timer;
Scope<Window> m_window;
Scope<UserInterface> m_user_interface;
Scope<GraphicsContext> m_graphics_context;
Scope<Renderer> m_renderer;
Scope<LayerStack> m_layer_stack;
static Application *s_instance;
};
} // namespace lt

View file

@ -1,116 +0,0 @@
#pragma once
namespace lt {
class Event;
class MouseMovedEvent;
class ButtonPressedEvent;
class ButtonReleasedEvent;
class WheelScrolledEvent;
class KeyPressedEvent;
class KeyRepeatEvent;
class KeyReleasedEvent;
class SetCharEvent;
class WindowClosedEvent;
class WindowResizedEvent;
class WindowMovedEvent;
class WindowLostFocusEvent;
class WindowGainFocusEvent;
class Layer
{
public:
Layer(std::string name);
virtual ~Layer() = default;
[[nodiscard]] auto get_name() const -> const std::string &
{
return m_layer_name;
}
virtual void on_update(float deltaTime)
{
}
virtual void on_user_interface_update()
{
}
virtual void on_render()
{
}
auto on_event(const Event &event) -> bool;
protected:
std::string m_layer_name;
virtual auto on_mouse_moved(const MouseMovedEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_button_pressed(const ButtonPressedEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_button_released(const ButtonReleasedEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_wheel_scrolled(const WheelScrolledEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_key_pressed(const KeyPressedEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_key_repeat(const KeyRepeatEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_key_released(const KeyReleasedEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_set_char(const SetCharEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_window_closed(const WindowClosedEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_window_resized(const WindowResizedEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_window_moved(const WindowMovedEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_window_lost_focus(const WindowLostFocusEvent & /*event*/) -> bool
{
return false;
}
virtual auto on_window_gain_focus(const WindowGainFocusEvent & /*event*/) -> bool
{
return false;
}
};
} // namespace lt

View file

@ -1,50 +0,0 @@
#pragma once
namespace lt {
class Layer;
class Event;
class LayerStack
{
public:
template<typename Layer_T, typename... Args>
void emplace_layer(Args &&...args)
{
attach_layer(create_ref<Layer_T>(std::forward<Args>(args)...));
}
void attach_layer(Ref<Layer> layer);
void detach_layer(const Ref<Layer> &layer);
[[nodiscard]] auto is_empty() const -> bool
{
return m_layers.empty();
}
[[nodiscard]] auto begin() -> std::vector<Ref<Layer>>::iterator
{
return m_layers.begin();
}
[[nodiscard]] auto end() -> std::vector<Ref<Layer>>::iterator
{
return m_layers.end();
}
[[nodiscard]] auto rbegin() -> std::vector<Ref<Layer>>::reverse_iterator
{
return m_layers.rbegin();
}
[[nodiscard]] auto rend() -> std::vector<Ref<Layer>>::reverse_iterator
{
return m_layers.rend();
}
private:
std::vector<Ref<Layer>> m_layers;
};
} // namespace lt

View file

@ -0,0 +1,48 @@
#include <app/application.hpp>
#include <app/system.hpp>
namespace lt::app {
void Application::game_loop()
{
while (true)
{
for (auto &system : m_systems)
{
if (system->tick())
{
return;
}
}
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(Ref<app::ISystem> system)
{
m_systems.emplace_back(std::move(system));
}
void Application::unregister_system(Ref<app::ISystem> system)
{
m_systems_to_be_unregistered.emplace_back(std::move(system));
}
} // namespace lt::app

View file

@ -0,0 +1,44 @@
#pragma once
namespace lt::app {
class ISystem;
extern 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(Ref<app::ISystem> system);
void unregister_system(Ref<app::ISystem> system);
protected:
Application() = default;
private:
std::vector<Ref<app::ISystem>> m_systems;
std::vector<Ref<app::ISystem>> m_systems_to_be_unregistered;
std::vector<Ref<app::ISystem>> m_systems_to_be_registered;
};
} // namespace lt::app

View file

@ -2,21 +2,21 @@
#include <app/application.hpp>
int main(int argc, char *argv[]) // NOLINT
auto main(int argc, char *argv[]) -> int32_t
try
{
std::ignore = argc;
std::ignore = argv;
auto application = lt::Scope<lt::Application> {};
auto application = lt::Scope<lt::app::Application> {};
application = lt::create_application();
lt::ensure(application, "Failed to create application");
lt::ensure(application->sanity_check(), "Failed to verify the sanity of the application");
application = 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)

View file

@ -0,0 +1,27 @@
#pragma once
namespace lt::app {
class ISystem
{
public:
ISystem() = default;
virtual ~ISystem() = default;
ISystem(ISystem &&) = default;
ISystem(const ISystem &) = delete;
auto operator=(ISystem &&) -> ISystem & = default;
auto operator=(const ISystem &) -> ISystem & = delete;
virtual void on_register() = 0;
virtual void on_unregister() = 0;
virtual auto tick() -> bool = 0;
};
} // namespace lt::app

View file

@ -1,203 +0,0 @@
#include <app/application.hpp>
#include <app/layer.hpp>
#include <app/layer_stack.hpp>
#include <asset_manager/asset_manager.hpp>
#include <debug/assertions.hpp>
#include <input/events/event.hpp>
#include <input/events/keyboard.hpp>
#include <input/events/window.hpp>
#include <input/input.hpp>
#include <ranges>
#include <renderer/blender.hpp>
#include <renderer/graphics_context.hpp>
#include <renderer/render_command.hpp>
#include <renderer/renderer.hpp>
#include <ui/ui.hpp>
#include <window/linux/window.hpp>
namespace lt {
Application *Application::s_instance = nullptr;
Application::Application(): m_window(nullptr)
{
ensure(!s_instance, "Application constructed twice");
s_instance = this;
m_window = Window::create([this](auto &&PH1) { on_event(std::forward<decltype(PH1)>(PH1)); });
// create graphics context
m_graphics_context = GraphicsContext::create(
GraphicsAPI::OpenGL,
(GLFWwindow *)m_window->get_handle()
);
AssetManager::load_shader(
"LT_ENGINE_RESOURCES_TEXTURE_SHADER",
"data/assets/shaders/texture/vs.asset",
"data/assets/shaders/texture/ps.asset"
);
AssetManager::load_shader(
"LT_ENGINE_RESOURCES_TINTED_TEXTURE_SHADER",
"data/assets/shaders/tinted_texture/vs.asset",
"data/assets/shaders/tinted_texture/ps.asset"
);
AssetManager::load_shader(
"LT_ENGINE_RESOURCES_QUAD_SHADER",
"data/assets/shaders/quads/vs.asset",
"data/assets/shaders/quads/ps.asset"
);
m_renderer = Renderer::create(
(GLFWwindow *)m_window->get_handle(),
lt::GraphicsContext::get_shared_context(),
Renderer::CreateInfo {
.quad_renderer_shader = AssetManager::get_shader("LT_ENGINE_RESOURCES_QUAD_SHADER"),
.texture_renderer_shader = AssetManager::get_shader(
"LT_ENGINE_RESOURCES_TEXTURE_SHADER"
),
.tinted_texture_renderer_shader = AssetManager::get_shader(
"LT_ENGINE_RESOURCES_TINTED_"
"TEXTURE_SHADER"
),
}
);
ensure(m_graphics_context, "lWindow::lWindow: failed to create 'GraphicsContext'");
m_user_interface = UserInterface::create(
(GLFWwindow *)m_window->get_handle(),
lt::GraphicsContext::get_shared_context()
);
m_layer_stack = create_scope<LayerStack>();
}
Application::~Application()
{
/** This is required to make forward-declarations possible:
* https://stackoverflow.com/questions/34072862/why-is-error-invalid-application-of-sizeof-to-an-incomplete-type-using-uniqu
*/
}
void Application::game_loop()
{
m_window->set_visibility(true);
while (!m_window->is_closed())
{
update_layers();
render_layers();
render_user_interface();
poll_events();
}
}
void Application::quit()
{
s_instance->m_window->close();
}
void Application::update_layers()
{
for (auto &it : *m_layer_stack)
{
// narrowing double -> float
it->on_update(static_cast<float>(m_timer.elapsed_time().count()));
}
// TODO(Light): each layer should have their own "delta time"
m_timer.reset();
}
void Application::render_layers()
{
m_renderer->begin_frame();
for (auto &it : *m_layer_stack)
{
it->on_render();
}
m_renderer->end_frame();
}
void Application::render_user_interface()
{
m_user_interface->begin();
for (auto &it : *m_layer_stack)
{
it->on_user_interface_update();
}
m_user_interface->end();
}
void Application::poll_events()
{
m_window->poll_events();
}
void Application::on_event(const Event &event)
{
// window
if (event.has_category(WindowEventCategory))
{
m_window->on_event(event);
if (event.get_event_type() == EventType::WindowResized)
{
m_renderer->on_window_resize(dynamic_cast<const WindowResizedEvent &>(event));
}
}
// input
if (event.has_category(InputEventCategory))
{
Input::instance().on_event(event);
if (!Input::instance().is_receiving_game_events())
{
return;
}
}
for (auto &it : std::ranges::reverse_view(*m_layer_stack))
{
if (it->on_event(event))
{
return;
}
}
}
[[nodiscard]] auto Application::sanity_check() const -> bool
{
log_inf("Checking application sanity...");
ensure(s_instance, "Application not constructed!?");
ensure(m_window, "Window is not initialized");
ensure(m_user_interface, "User interface is not initialized");
ensure(m_graphics_context, "Graphics context is not initialized");
ensure(m_renderer, "Renderer is not initialized");
ensure(m_layer_stack, "Layer_stack is not initialized");
ensure(!m_layer_stack->is_empty(), "Layer_stack is empty");
log_inf("Logging application state...");
this->log_debug_data();
m_graphics_context->log_debug_data();
m_user_interface->log_debug_data();
return true;
}
void Application::log_debug_data() const
{
log_inf("Platform::");
log_inf(" Platform name: {}", constants::platform_name);
log_inf(" Platform identifier: {}", std::to_underlying(constants::platform));
log_inf(" CWD: {}", std::filesystem::current_path().generic_string());
}
} // namespace lt

View file

@ -1,47 +0,0 @@
#include <app/layer.hpp>
#include <input/events/char.hpp>
#include <input/events/event.hpp>
#include <input/events/keyboard.hpp>
#include <input/events/mouse.hpp>
#include <input/events/window.hpp>
namespace lt {
Layer::Layer(std::string name): m_layer_name(std::move(name))
{
}
auto Layer::on_event(const Event &event) -> bool
{
switch (event.get_event_type())
{
case EventType::MouseMoved: return on_mouse_moved(dynamic_cast<const MouseMovedEvent &>(event));
case EventType::ButtonPressed:
return on_button_pressed(dynamic_cast<const ButtonPressedEvent &>(event));
case EventType::ButtonReleased:
return on_button_released(dynamic_cast<const ButtonReleasedEvent &>(event));
case EventType::WheelScrolled:
return on_wheel_scrolled(dynamic_cast<const WheelScrolledEvent &>(event));
case EventType::KeyPressed: return on_key_pressed(dynamic_cast<const KeyPressedEvent &>(event));
case EventType::KeyRepeated: return on_key_repeat(dynamic_cast<const KeyRepeatEvent &>(event));
case EventType::KeyReleased:
return on_key_released(dynamic_cast<const KeyReleasedEvent &>(event));
case EventType::SetChar: return on_set_char(dynamic_cast<const SetCharEvent &>(event));
case EventType::WindowClosed:
return on_window_closed(dynamic_cast<const WindowClosedEvent &>(event));
case EventType::WindowResized:
return on_window_resized(dynamic_cast<const WindowResizedEvent &>(event));
case EventType::WindowMoved:
return on_window_moved(dynamic_cast<const WindowMovedEvent &>(event));
case EventType::WindowLostFocus:
return on_window_lost_focus(dynamic_cast<const WindowLostFocusEvent &>(event));
case EventType::WindowGainFocus:
return on_window_gain_focus(dynamic_cast<const WindowGainFocusEvent &>(event));
default: ensure(false, "Invalid event: {}", event.get_info_lt_log());
}
}
} // namespace lt

View file

@ -1,18 +0,0 @@
#include <app/layer.hpp>
#include <app/layer_stack.hpp>
namespace lt {
void LayerStack::attach_layer(Ref<Layer> layer)
{
log_trc("Attaching layer [{}]", layer->get_name());
m_layers.emplace_back(std::move(layer));
}
void LayerStack::detach_layer(const Ref<Layer> &layer)
{
log_trc("Detaching layer [{}]", layer->get_name());
m_layers.erase(std::find(m_layers.begin(), m_layers.end(), layer));
}
} // namespace lt

View file

@ -1,5 +1,5 @@
add_executable_module(
asset_baker baker.cpp
asset_baker entrypoint/baker.cpp
)
target_link_libraries(

View file

@ -131,7 +131,8 @@ public:
return "TextLoader";
}
[[nodiscard]] auto load(const std::filesystem::path& file_path) const -> Assets::TextAsset::PackageData
[[nodiscard]] auto load(const std::filesystem::path &file_path) const
-> Assets::TextAsset::PackageData
{
auto stream = std::ifstream { file_path, std::ios::binary };
if (!stream.good())

View file

@ -5,5 +5,5 @@ add_library_module(asset_manager
target_link_libraries(
asset_manager
PUBLIC asset_parser
PRIVATE renderer
PRIVATE logger
)

View file

@ -6,7 +6,6 @@ add_library_module(asset_parser
target_link_libraries(
asset_parser
PUBLIC LZ4::lz4_static
PUBLIC nlohmann_json::nlohmann_json
PUBLIC logger
PRIVATE LZ4::lz4_static
PRIVATE logger
)

View file

@ -1,6 +1,5 @@
#include <asset_parser/assets/text.hpp>
#include <lz4.h>
#include <nlohmann/json.hpp>
namespace Assets {

View file

@ -1,6 +1,5 @@
#include <asset_parser/assets/texture.hpp>
#include <lz4.h>
#include <nlohmann/json.hpp>
namespace Assets {

View file

@ -1,7 +1,7 @@
#pragma once
#include <asset_parser/compressors/compressors.hpp>
#include <asset_parser/parser.hpp>
#include <compressors/compressors.hpp>
#include <cstdint>
#include <filesystem>
#include <fstream>

View file

@ -1,7 +1,7 @@
#pragma once
#include <asset_parser/compressors/compressors.hpp>
#include <asset_parser/parser.hpp>
#include <compressors/compressors.hpp>
#include <cstdint>
#include <filesystem>
#include <fstream>

View file

@ -1,6 +1,6 @@
#pragma once
#include <compressors/compressors.hpp>
#include <asset_parser/compressors/compressors.hpp>
#include <cstdint>
#include <filesystem>
#include <fstream>

View file

@ -1,3 +1,2 @@
add_library_module(base)
target_precompile_headers(base INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src/pch.hpp)
target_precompile_headers(base INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/private/pch.hpp)

View file

@ -1,3 +1,3 @@
add_library_module(camera camera.cpp scene.cpp)
target_link_libraries(camera PUBLIC glm::glm)
target_link_libraries(camera PUBLIC math)

View file

@ -1,34 +0,0 @@
#pragma once
#include <glm/glm.hpp>
namespace lt {
class Camera
{
public:
Camera() = default;
[[nodiscard]] auto get_projection() const -> const glm::mat4 &
{
return m_projection;
}
[[nodiscard]] auto get_background_color() const -> const glm::vec4 &
{
return m_background_color;
}
void set_background_color(const glm::vec4 &color)
{
m_background_color = color;
}
protected:
glm::mat4 m_projection {};
private:
glm::vec4 m_background_color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f);
};
} // namespace lt

View file

@ -1,11 +1,12 @@
#include <camera/scene.hpp>
#include <glm/gtc/matrix_transform.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 = glm::radians(45.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)
@ -64,26 +65,19 @@ void SceneCamera::set_perspective_near_plane(float near_plane)
void SceneCamera::calculate_projection()
{
// TODO(Light): implement ortho perspective
if (m_projection_type == ProjectionType::Orthographic)
{
m_projection = glm::ortho(
-m_orthographic_specification.size * 0.5f * m_aspect_ratio,
m_orthographic_specification.size * 0.5f * m_aspect_ratio,
-m_orthographic_specification.size * 0.5f,
m_orthographic_specification.size * 0.5f,
m_orthographic_specification.far_plane,
m_orthographic_specification.near_plane
);
}
else // perspective
{
m_projection = glm::perspective(
m_perspective_specification.vertical_fov,
m_aspect_ratio,
m_perspective_specification.near_plane,
m_perspective_specification.far_plane
);
// 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

View 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

View file

@ -1,7 +1,6 @@
#pragma once
#include <camera/scene.hpp>
#include <glm/glm.hpp>
namespace lt {

View file

@ -1,3 +1,3 @@
add_library_module(lt_debug instrumentor.cpp)
target_link_libraries(lt_debug PUBLIC logger)
target_precompile_headers(lt_debug PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/pch.hpp)
target_precompile_headers(lt_debug PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/private/pch.hpp)

View file

@ -1,36 +0,0 @@
#pragma once
#include <logger/logger.hpp>
namespace lt {
struct FailedAssertion: std::exception
{
FailedAssertion(const char *file, int line)
{
log_crt("Assertion failed in: {} (line {})", file, line);
}
};
template<typename Expression_T, typename... Args>
constexpr void ensure(Expression_T &&expression, std::format_string<Args...> fmt, Args &&...args)
{
if (!static_cast<bool>(expression))
{
Logger::log(LogLvl::critical, fmt, std::forward<Args>(args)...);
throw ::lt::FailedAssertion(__FILE__, __LINE__);
}
}
template<typename Expression_T>
constexpr void ensure(Expression_T &&expression, const char *message)
{
if (!static_cast<bool>(expression))
{
Logger::log(LogLvl::critical, message);
throw ::lt::FailedAssertion(__FILE__, __LINE__);
}
}
} // namespace lt

View file

@ -1,5 +1,5 @@
#include <debug/instrumentor.hpp>
#include <logger/logger.hpp>
#include <lt_debug/instrumentor.hpp>
namespace lt {

View file

@ -0,0 +1,3 @@
#pragma once
#include <lt_debug/assertions.hpp>

View 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(
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

View file

@ -1,3 +0,0 @@
#pragma once
#include <debug/assertions.hpp>

View file

@ -1,5 +1,4 @@
add_library_module(ecs entity.cpp scene.cpp uuid.cpp serializer.cpp)
add_library_module(ecs entity.cpp scene.cpp uuid.cpp )
target_link_libraries(ecs
PUBLIC logger lt_debug EnTT::EnTT renderer input camera
PRIVATE yaml-cpp::yaml-cpp asset_manager
PUBLIC logger lt_debug EnTT::EnTT input camera math
)

View file

@ -1,45 +0,0 @@
#pragma once
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
namespace lt {
struct TransformComponent
{
TransformComponent(const TransformComponent &) = default;
TransformComponent(
const glm::vec3 &_translation = glm::vec3(0.0f, 0.0f, 0.0f),
const glm::vec3 &_scale = glm::vec3(1.0f, 1.0f, 1.0f),
const glm::vec3 &_rotation = glm::vec3(0.0f, 0.0f, 0.0f)
)
: translation(_translation)
, scale(_scale)
, rotation(_rotation)
{
}
[[nodiscard]] auto get_transform() const -> glm::mat4
{
return glm::translate(translation) * glm::rotate(rotation.z, glm::vec3(0.0f, 0.0f, 1.0f))
* glm::scale(scale);
}
operator const glm::mat4() const
{
return get_transform();
}
glm::vec3 translation;
glm::vec3 scale;
glm::vec3 rotation;
};
} // namespace lt

View file

@ -0,0 +1,31 @@
#include <ecs/components.hpp>
#include <ecs/entity.hpp>
#include <ecs/scene.hpp>
namespace lt {
auto Scene::create_entity(const std::string &name, const TransformComponent &transform) -> Entity
{
return create_entity_with_uuid(name, UUID(), transform);
}
auto Scene::get_entity_by_tag(const std::string &tag) -> Entity
{
return {};
}
auto Scene::create_entity_with_uuid(
const std::string &name,
UUID uuid,
const TransformComponent &transform
) -> Entity
{
auto entity = Entity { m_registry.create(), this };
entity.add_component<TagComponent>(name);
entity.add_component<TransformComponent>(transform);
entity.add_component<UUIDComponent>(uuid);
return entity;
}
} // namespace lt

View file

@ -2,14 +2,16 @@
#include <camera/component.hpp>
#include <ecs/components.hpp>
#include <ecs/serializer.hpp>
#include <math/vec3.hpp>
#include <math/vec4.hpp>
#include <yaml-cpp/yaml.h>
namespace YAML {
template<>
struct convert<glm::vec3>
struct convert<lt::math::vec3>
{
static auto encode(const glm::vec3 &rhs) -> Node
static auto encode(const lt::math::vec3 &rhs) -> Node
{
auto node = Node {};
node.push_back(rhs.x);
@ -18,7 +20,7 @@ struct convert<glm::vec3>
return node;
}
static auto decode(const Node &node, glm::vec3 &rhs) -> bool
static auto decode(const Node &node, lt::math::vec3 &rhs) -> bool
{
if (!node.IsSequence() || node.size() != 3)
{
@ -33,9 +35,9 @@ struct convert<glm::vec3>
};
template<>
struct convert<glm::vec4>
struct convert<lt::math::vec4>
{
static auto encode(const glm::vec4 &rhs) -> Node
static auto encode(const lt::math::vec4 &rhs) -> Node
{
auto node = Node {};
node.push_back(rhs.x);
@ -45,7 +47,7 @@ struct convert<glm::vec4>
return node;
}
static auto decode(const Node &node, glm::vec4 &rhs) -> bool
static auto decode(const Node &node, lt::math::vec4 &rhs) -> bool
{
if (!node.IsSequence() || node.size() != 4)
{
@ -63,14 +65,14 @@ struct convert<glm::vec4>
namespace lt {
auto operator<<(YAML::Emitter &out, const glm::vec3 &v) -> YAML::Emitter &
auto operator<<(YAML::Emitter &out, const math::vec3 &v) -> YAML::Emitter &
{
out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq;
return out;
}
auto operator<<(YAML::Emitter &out, const glm::vec4 &v) -> YAML::Emitter &
auto operator<<(YAML::Emitter &out, const math::vec4 &v) -> YAML::Emitter &
{
out << YAML::Flow;
out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq;
@ -156,9 +158,10 @@ auto SceneSerializer::deserialize(const std::string &file_path) -> bool
.get_component<TransformComponent>();
entityTransforomComponent.translation = transformComponent["Translation"]
.as<glm::vec3>();
entityTransforomComponent.rotation = transformComponent["Rotation"].as<glm::vec3>();
entityTransforomComponent.scale = transformComponent["Scale"].as<glm::vec3>();
.as<math::vec3>();
entityTransforomComponent.rotation = transformComponent["Rotation"]
.as<math::vec3>();
entityTransforomComponent.scale = transformComponent["Scale"].as<math::vec3>();
}
/* #TEMPORARY SOLUTION# */
@ -168,7 +171,7 @@ auto SceneSerializer::deserialize(const std::string &file_path) -> bool
auto &entitySpriteRendererComponent = deserializedEntity
.add_component<SpriteRendererComponent>();
entitySpriteRendererComponent.tint = spriteRendererComponent["Tint"]
.as<glm::vec4>();
.as<math::vec4>();
auto texturePath = spriteRendererComponent["Texture"].as<std::string>();
@ -213,7 +216,7 @@ auto SceneSerializer::deserialize(const std::string &file_path) -> bool
);
entityCameraComponent.camera.set_background_color(
cameraSpecifications["BackgroundColor"].as<glm::vec4>()
cameraSpecifications["BackgroundColor"].as<math::vec4>()
);
entityCameraComponent.isPrimary = cameraComponent["IsPrimary"].as<bool>();

View file

@ -0,0 +1,14 @@
#include <ecs/uuid.hpp>
namespace lt {
std::mt19937_64 UUID::s_engine = std::mt19937_64(std::random_device()());
std::uniform_int_distribution<uint64_t>
UUID::s_distribution = std::uniform_int_distribution<uint64_t> {};
UUID::UUID(uint64_t uuid /* = -1 */): m_uuid(uuid == -1 ? s_distribution(s_engine) : uuid)
{
}
} // namespace lt

View file

@ -1,6 +1,6 @@
#pragma once
#include <glm/glm.hpp>
#include <math/vec4.hpp>
#include <utility>
namespace lt {
@ -15,7 +15,7 @@ struct SpriteRendererComponent
SpriteRendererComponent(
Ref<Texture> _texture,
const glm::vec4 &_tint = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)
const math::vec4 &_tint = math::vec4 { 1.0f, 1.0f, 1.0f, 1.0f }
)
: texture(std::move(std::move(_texture)))
, tint(_tint)
@ -29,7 +29,7 @@ struct SpriteRendererComponent
Ref<Texture> texture;
glm::vec4 tint {};
math::vec4 tint {};
};
} // namespace lt

View file

@ -0,0 +1,43 @@
#pragma once
#include <math/mat4.hpp>
#include <math/vec3.hpp>
namespace lt {
struct TransformComponent
{
TransformComponent(const TransformComponent &) = default;
TransformComponent(
const math::vec3 &_translation = math::vec3(0.0f, 0.0f, 0.0f),
const math::vec3 &_scale = math::vec3(1.0f, 1.0f, 1.0f),
const math::vec3 &_rotation = math::vec3(0.0f, 0.0f, 0.0f)
)
: translation(_translation)
, scale(_scale)
, rotation(_rotation)
{
}
[[nodiscard]] auto get_transform() const -> math::mat4
{
return math::translate(translation)
* math::rotate(rotation.z, math::vec3 { 0.0f, 0.0f, 1.0f }) //
* math::scale(scale);
}
operator const math::mat4() const
{
return get_transform();
}
math::vec3 translation;
math::vec3 scale;
math::vec3 rotation;
};
} // namespace lt

View file

@ -3,7 +3,7 @@
#include <ecs/components/transform.hpp>
#include <ecs/uuid.hpp>
#include <entt/entt.hpp>
#include <glm/glm.hpp>
#include <functional>
namespace lt {
@ -13,11 +13,17 @@ class Framebuffer;
class Scene
{
public:
void on_create();
template<typename... T>
auto group()
{
return m_registry.group(entt::get<T...>);
}
void on_update(float deltaTime);
void on_render(const Ref<Framebuffer> &targetFrameBuffer = nullptr);
template<typename T>
auto view()
{
return m_registry.view<T>();
}
auto create_entity(
const std::string &name,
@ -26,6 +32,12 @@ public:
auto get_entity_by_tag(const std::string &tag) -> Entity;
auto get_entt_registry() -> entt::registry &
{
return m_registry;
}
private:
friend class Entity;
@ -42,4 +54,12 @@ private:
) -> Entity;
};
namespace ecs {
using Registry = Scene;
using Entity = ::lt::Entity;
} // namespace ecs
} // namespace lt

View file

@ -1,111 +0,0 @@
#include <camera/component.hpp>
#include <ecs/components.hpp>
#include <ecs/entity.hpp>
#include <ecs/scene.hpp>
#include <glm/glm.hpp>
#include <renderer/renderer.hpp>
namespace lt {
void Scene::on_create()
{
/* native scripts */
{
m_registry.view<NativeScriptComponent>().each([](NativeScriptComponent &nsc) {
if (nsc.instance == nullptr)
{
nsc.instance = nsc.CreateInstance();
nsc.instance->on_create();
}
});
}
}
void Scene::on_update(float deltaTime)
{
/* native scripts */
{
m_registry.view<NativeScriptComponent>().each([=](NativeScriptComponent &nsc) {
nsc.instance->on_update(deltaTime);
});
}
}
void Scene::on_render(const Ref<Framebuffer> &targetFrameBuffer /* = nullptr */)
{
auto *sceneCamera = (Camera *)nullptr;
auto *sceneCameraTransform = (TransformComponent *)nullptr;
/* scene camera */
{
m_registry.group(entt::get<TransformComponent, CameraComponent>)
.each([&](TransformComponent &transformComp, CameraComponent &cameraComp) {
if (cameraComp.isPrimary)
{
sceneCamera = &cameraComp.camera;
sceneCameraTransform = &transformComp;
}
});
}
/* draw quads */
{
if (sceneCamera)
{
Renderer::begin_scene(sceneCamera, *sceneCameraTransform, targetFrameBuffer);
m_registry.group(entt::get<TransformComponent, SpriteRendererComponent>)
.each([](TransformComponent &transformComp,
SpriteRendererComponent &spriteRendererComp) {
Renderer::draw_quad(
transformComp,
spriteRendererComp.tint,
spriteRendererComp.texture
);
});
Renderer::end_scene();
}
}
}
auto Scene::create_entity(const std::string &name, const TransformComponent &transform) -> Entity
{
return create_entity_with_uuid(name, UUID(), transform);
}
auto Scene::get_entity_by_tag(const std::string &tag) -> Entity
{
// TagComponent tagComp(tag);
// entt::entity entity = entt::to_entity(m_registry, tagComp);
auto entity = Entity {};
m_registry.view<TagComponent>().each([&](TagComponent &tagComp) {
// if (tagComp.tag == tag)
// entity = entity(entt::to_entity(m_registry, tagComp), this);
});
if (entity.is_valid())
{
return entity;
}
ensure(false, "Scene::get_entity_by_tag: failed to find entity by tag: {}", tag);
return {};
}
auto Scene::create_entity_with_uuid(
const std::string &name,
UUID uuid,
const TransformComponent &transform
) -> Entity
{
auto entity = Entity { m_registry.create(), this };
entity.add_component<TagComponent>(name);
entity.add_component<TransformComponent>(transform);
entity.add_component<UUIDComponent>(uuid);
return entity;
}
} // namespace lt

View file

@ -1,12 +0,0 @@
#include <ecs/uuid.hpp>
namespace lt {
auto UUID::s_engine = std::mt19937_64(std::random_device()());
auto UUID::s_distribution = std::uniform_int_distribution<uint64_t> {};
UUID::UUID(uint64_t uuid /* = -1 */): m_uuid(uuid == -1 ? s_distribution(s_engine) : uuid)
{
}
} // namespace lt

View file

@ -1,2 +1,2 @@
add_library_module(input input.cpp)
target_link_libraries(input PUBLIC spdlog::spdlog glm::glm imgui logger)
target_link_libraries(input PUBLIC surface math imgui::imgui logger)

View file

@ -1,41 +0,0 @@
#pragma once
#include <input/events/event.hpp>
#include <sstream>
namespace lt {
class SetCharEvent: public Event
{
public:
SetCharEvent(unsigned int character): m_character(character)
{
}
[[nodiscard]] auto get_character() const -> int
{
return m_character;
}
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
std::stringstream ss;
ss << "CharSet: " << m_character;
return ss.str();
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::SetChar;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(InputEventCategory | KeyboardEventCategory) & category;
}
private:
const unsigned int m_character;
};
} // namespace lt

View file

@ -1,56 +0,0 @@
#pragma once
namespace lt {
enum class EventType : uint8_t
{
None = 0,
// input
MouseMoved,
WheelScrolled,
ButtonPressed,
ButtonReleased,
KeyPressed,
KeyRepeated,
KeyReleased,
SetChar,
// window
WindowMoved,
WindowResized,
WindowClosed,
WindowLostFocus,
WindowGainFocus,
};
enum EventCategory : uint8_t
{
None = 0,
WindowEventCategory = bit(0),
InputEventCategory = bit(1),
KeyboardEventCategory = bit(2),
MouseEventCategory = bit(3),
};
class Event
{
public:
Event() = default;
virtual ~Event() = default;
[[nodiscard]] virtual auto get_event_type() const -> EventType = 0;
[[nodiscard]] virtual auto get_info_lt_log() const -> std::string = 0;
[[nodiscard]] virtual auto has_category(EventCategory category) const -> bool = 0;
friend auto operator<<(std::ostream &os, const Event &e) -> std::ostream &
{
return os << e.get_info_lt_log();
}
};
} // namespace lt

View file

@ -1,107 +0,0 @@
#pragma once
#include <input/events/event.hpp>
#include <sstream>
namespace lt {
class KeyPressedEvent: public Event
{
public:
KeyPressedEvent(int key): m_key(key)
{
}
[[nodiscard]] auto get_key() const -> int
{
return m_key;
}
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
std::stringstream ss;
ss << "KeyPressed: " << m_key;
return ss.str();
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::KeyPressed;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(InputEventCategory | KeyboardEventCategory) & category;
}
private:
const int m_key;
};
class KeyRepeatEvent: public Event
{
public:
KeyRepeatEvent(int key): m_key(key)
{
}
[[nodiscard]] auto get_key() const -> int
{
return m_key;
}
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
std::stringstream ss;
ss << "KeyRepeated: " << m_key;
return ss.str();
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::KeyRepeated;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(InputEventCategory | KeyboardEventCategory) & category;
}
private:
const int m_key;
};
class KeyReleasedEvent: public Event
{
public:
KeyReleasedEvent(int key): m_key(key)
{
}
[[nodiscard]] auto get_key() const -> int
{
return m_key;
}
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
std::stringstream ss;
ss << "KeyReleased: " << m_key;
return ss.str();
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::KeyReleased;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(InputEventCategory | KeyboardEventCategory) & category;
}
private:
const int m_key;
};
} // namespace lt

View file

@ -1,151 +0,0 @@
#pragma once
#include <glm/glm.hpp>
#include <input/events/event.hpp>
#include <sstream>
namespace lt {
class MouseMovedEvent: public Event
{
public:
MouseMovedEvent(float x, float y): m_position(x, y)
{
}
[[nodiscard]] auto get_position() const -> const glm::vec2 &
{
return m_position;
}
[[nodiscard]] auto get_x() const -> float
{
return m_position.x;
}
[[nodiscard]] auto get_y() const -> float
{
return m_position.y;
}
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
std::stringstream ss;
ss << "MouseMoved: " << m_position.x << ", " << m_position.y;
return ss.str();
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::MouseMoved;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(InputEventCategory | MouseEventCategory) & category;
}
private:
const glm::vec2 m_position;
};
class WheelScrolledEvent: public Event
{
public:
WheelScrolledEvent(float offset): m_offset(offset)
{
}
[[nodiscard]] auto get_offset() const -> float
{
return m_offset;
}
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
std::stringstream ss;
ss << "WheelScrolled: " << m_offset;
return ss.str();
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::WheelScrolled;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(InputEventCategory | MouseEventCategory) & category;
}
private:
const float m_offset;
};
class ButtonPressedEvent: public Event
{
public:
ButtonPressedEvent(int button): m_button(button)
{
}
[[nodiscard]] auto get_button() const -> int
{
return m_button;
}
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
std::stringstream ss;
ss << "ButtonPressed: " << m_button;
return ss.str();
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::ButtonPressed;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(InputEventCategory | MouseEventCategory) & category;
}
private:
const int m_button;
};
class ButtonReleasedEvent: public Event
{
public:
ButtonReleasedEvent(int button): m_button(button)
{
}
[[nodiscard]] auto get_button() const -> int
{
return m_button;
}
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
std::stringstream ss;
ss << "ButtonReleased: " << m_button;
return ss.str();
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::ButtonReleased;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(InputEventCategory | MouseEventCategory) & category;
}
private:
const int m_button;
};
} // namespace lt

View file

@ -1,133 +0,0 @@
#pragma once
#include <glm/glm.hpp>
#include <input/events/event.hpp>
#include <sstream>
namespace lt {
class WindowClosedEvent: public Event
{
public:
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
return "WindowClosedEvent";
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::WindowClosed;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(WindowEventCategory) & category;
}
};
class WindowMovedEvent: public Event
{
public:
WindowMovedEvent(int x, int y): m_position(x, y)
{
}
[[nodiscard]] auto get_position() const -> const glm::ivec2 &
{
return m_position;
}
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
std::stringstream ss;
ss << "WindwoMoved: " << m_position.x << ", " << m_position.y;
return ss.str();
;
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::WindowMoved;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(WindowEventCategory) & category;
}
private:
const glm::ivec2 m_position;
};
class WindowResizedEvent: public Event
{
public:
WindowResizedEvent(unsigned int width, unsigned int height): m_size(width, height)
{
}
[[nodiscard]] auto get_size() const -> const glm::uvec2 &
{
return m_size;
}
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
std::stringstream ss;
ss << "WindowResized: " << m_size.x << ", " << m_size.y;
return ss.str();
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::WindowResized;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(WindowEventCategory) & category;
}
private:
const glm::uvec2 m_size;
};
class WindowLostFocusEvent: public Event
{
public:
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
return "WindowLostFocus";
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::WindowLostFocus;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(WindowEventCategory) & category;
}
};
class WindowGainFocusEvent: public Event
{
public:
[[nodiscard]] auto get_info_lt_log() const -> std::string override
{
return "WindowGainFocus";
}
[[nodiscard]] auto get_event_type() const -> EventType override
{
return ::lt::EventType::WindowGainFocus;
}
[[nodiscard]] auto has_category(EventCategory category) const -> bool override
{
return static_cast<uint8_t>(WindowEventCategory) & category;
}
};
} // namespace lt

View file

@ -1,10 +1,5 @@
#include <imgui.h>
#include <input/events/char.hpp>
#include <input/events/event.hpp>
#include <input/events/keyboard.hpp>
#include <input/events/mouse.hpp>
#include <input/input.hpp>
#include <input/key_codes.hpp>
#include <logger/logger.hpp>
namespace lt {
@ -36,8 +31,8 @@ void Input::restart_input_state()
m_keyboad_keys.fill(false);
m_mouse_buttons.fill(false);
m_mouse_position = glm::vec2(0.0f);
m_mouse_delta = glm::vec2(0.0f);
m_mouse_position = math::vec2(0.0f);
m_mouse_delta = math::vec2(0.0f);
m_mouse_wheel_delta = 0.0f;
}

View file

@ -0,0 +1,5 @@
#include <input/system.hpp>
namespace lt::input {
} // namespace lt::input

View file

@ -1,7 +1,7 @@
#pragma once
#include <array>
#include <glm/glm.hpp>
#include <math/vec2.hpp>
namespace lt {
@ -36,7 +36,7 @@ public:
return instance().m_mouse_buttons[code];
}
static auto get_mouse_position(int /*code*/) -> const glm::vec2 &
static auto get_mouse_position(int /*code*/) -> const math::vec2 &
{
return instance().m_mouse_position;
}
@ -66,9 +66,9 @@ private:
std::array<bool, 8> m_mouse_buttons {};
glm::vec2 m_mouse_position;
math::vec2 m_mouse_position;
glm::vec2 m_mouse_delta;
math::vec2 m_mouse_delta;
float m_mouse_wheel_delta {};

View file

@ -0,0 +1,64 @@
#pragma once
#include <surface/system.hpp>
namespace lt::input {
template<class... Ts>
struct overloads: Ts...
{
using Ts::operator()...;
};
/**
*
* @note If this system is attached, it will always consume the input events f rom surface.
* Therefore if you want any input detection mechanism, callbacks should be setup with this
* system and not directly with surface.
*/
class System
{
public:
System(lt::surface::System &surface_system)
{
surface_system.add_event_listener([this](auto &&event) {
return handle_event(std::forward<decltype(event)>(event));
});
};
private:
auto handle_event(const lt::surface::System::Event &event) -> bool
{
const auto visitor = overloads {
[this](const lt::surface::KeyPressedEvent &event) {
m_keys[event.get_key()] = true;
return true;
},
[](const lt::surface::KeyRepeatEvent &) { return false; },
[](const lt::surface::KeyReleasedEvent &) { return false; },
[](const lt::surface::KeySetCharEvent &) { return false; },
[](const lt::surface::MouseMovedEvent &) { return false; },
[](const lt::surface::WheelScrolledEvent &) { return false; },
[](const lt::surface::ButtonPressedEvent &) { return false; },
[](const lt::surface::ButtonReleasedEvent &) { return false; },
[](const auto &) { return false; },
};
return std::visit(visitor, event);
}
void setup_callbacks(GLFWwindow *handle);
std::array<bool, 512> m_keys {};
};
} // namespace lt::input

View file

@ -1,2 +1 @@
add_library_module(logger logger.cpp)
target_link_libraries(logger PUBLIC spdlog::spdlog)

View file

@ -0,0 +1 @@
#include <logger/logger.hpp>

View file

@ -1,15 +1,9 @@
#pragma once
#include <format>
#include <memory>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
#include <print>
/** @brief Severity of a log message.
*
* @note Values reflect spdlog::lvl
*/
/** Severity of a log message. */
enum class LogLvl : uint8_t
{
/** Lowest and most vebose log level, for tracing execution paths and events */
@ -34,11 +28,7 @@ enum class LogLvl : uint8_t
off = 6,
};
namespace spdlog {
class logger;
}
/** Responsible for logging */
/** Simple console logger */
class Logger
{
public:
@ -47,26 +37,19 @@ public:
template<typename... Args>
void static log(LogLvl lvl, std::format_string<Args...> fmt, Args &&...args)
{
instance().spd_logger->log(
(spdlog::level::level_enum)lvl,
std::format(fmt, std::forward<Args>(args)...)
);
std::ignore = lvl;
std::println(fmt, std::forward<Args>(args)...);
}
void static log(LogLvl lvl, const char *message)
{
instance().spd_logger->log((spdlog::level::level_enum)lvl, message);
std::ignore = lvl;
std::println("{}", message);
}
private:
Logger();
~Logger();
auto static instance() -> Logger &;
std::shared_ptr<spdlog::logger> spd_logger;
Logger() = default;
};
template<typename... Args>

View file

@ -1,18 +0,0 @@
#include <logger/logger.hpp>
Logger::Logger(): spd_logger(spdlog::stdout_color_mt("Logger"))
{
spd_logger->set_pattern("%^%v%$");
spd_logger->set_level(spdlog::level::level_enum::trace);
}
Logger::~Logger()
{
spdlog::drop_all();
}
auto Logger::instance() -> Logger &
{
static auto logger = Logger {};
return logger;
}

View file

@ -0,0 +1 @@
add_library_module(math)

Some files were not shown because too many files have changed in this diff Show more