Compare commits
	
		
			179 commits
		
	
	
		
			ci/libx11_
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 14c2512202 | |||
| 599f28fe73 | |||
| 0a1bda9573 | |||
| 311b20bdf2 | |||
| 6a257566bd | |||
| 4534ed11d2 | |||
| d029c0e473 | |||
| 604ee5e6a1 | |||
| 7ee4381bbf | |||
| 8730d31e2f | |||
| f50208653e | |||
| 5422792705 | |||
| 2ddb90faff | |||
| 736c37d2f1 | |||
| 97ca429d38 | |||
| 5a404d5269 | |||
| a9e27d6935 | |||
| 80662983a3 | |||
| c39ce89a9b | |||
| f1a91c9b81 | |||
| ec5483d13f | |||
| 598e1b232d | |||
| 3f5a85197a | |||
| 479a15bfd0 | |||
| 30548ea4db | |||
| 9de1bc7ba7 | |||
| 4b5d380a0e | |||
| 2612a19f3c | |||
| bd8a111607 | |||
| 3066153d6c | |||
| d5dc37d081 | |||
| b393cbb31c | |||
| 847ad7dd74 | |||
| 80a3afbb75 | |||
| a6a1a9e243 | |||
| 2890853ffe | |||
| 49596c31f3 | |||
| a19e095a8e | |||
| b6976c01c4 | |||
| 36d2d81e8a | |||
| cbe391ba32 | |||
| b763b10034 | |||
| 400b49f1d8 | |||
| 94335375ec | |||
| df056d08ed | |||
| 686ccc8f71 | |||
| 23d84c251a | |||
| 07a3dfcb36 | |||
| e70438706c | |||
| 56ef217142 | |||
| 38ec10f4fd | |||
| 00332ee958 | |||
| 9cbebaef06 | |||
| b804360884 | |||
| dc7c6ff0aa | |||
| 0471969615 | |||
| eb9e358d83 | |||
| fc0e63455b | |||
| 487f907ffb | |||
| 20ef8c04d8 | |||
| 77c04d38c9 | |||
| 81811351b8 | |||
| e1360cabce | |||
| 054af3fd8f | |||
| 5fbd9282d1 | |||
| 7132bd3324 | |||
| 3a06d51ee4 | |||
| 61473c2758 | |||
| e7c61b2faf | |||
| 41575df141 | |||
| 237d852ede | |||
| 879d375b7f | |||
| 8defb9a3ec | |||
| 68c49ebdfb | |||
| d506d6a6a7 | |||
| 16f3a80fd3 | |||
| 9ca94dc7d7 | |||
| b05762c95b | |||
| 6af758643e | |||
| ef2f728cd6 | |||
| 1ce8aed8a2 | |||
| c4403b7c90 | |||
| ebf1f54d31 | |||
| 01db551fa9 | |||
| 4ad50122ef | |||
| 0c4b3dd0f9 | |||
| 0fe399a33e | |||
| 85dbe47990 | |||
| 83a872f3f3 | |||
| 4976773218 | |||
| 5148b8836c | |||
| 405c707e23 | |||
| 21a82ff57d | |||
| a46f36aefd | |||
| 723ade84ea | |||
| cce627a350 | |||
| a77abe312b | |||
| 84d0026051 | |||
| 34fa8344ac | |||
| fa1bfaae1e | |||
| d411c9ab2c | |||
| 607e6864b4 | |||
| f268724034 | |||
| 030556c733 | |||
| 26dd49188b | |||
| 131d3472ac | |||
| bf6f2e9981 | |||
| bf8ffc3dc9 | |||
| 963032617e | |||
| 55d68e3b71 | |||
| 6e838afbab | |||
| c2f2abedd7 | |||
| fc0f039395 | |||
| 4e96a871c9 | |||
| 1765dd0bd0 | |||
| f04e3652a5 | |||
| 46a8ebf6da | |||
| eb7b780a20 | |||
| 1ad45dec5e | |||
| c3142f3117 | |||
| f2ac6daf1f | |||
| ac2d5c7c20 | |||
| 65d086c3d4 | |||
| 3e2cf440c9 | |||
| 19df29495c | |||
| 1f1535262f | |||
| cda81f7b3c | |||
| fef6c4bf52 | |||
| 47b8cbc3aa | |||
| febe633520 | |||
| b99167fc4f | |||
| 25e742b8ab | |||
| 8063903344 | |||
| f465f152e3 | |||
| d66ef55cc8 | |||
| e77a42cf7f | |||
| 53dd008df5 | |||
| d924d14ab0 | |||
| b6834310a7 | |||
| a58b0c030f | |||
| dd0f8ebf0a | |||
| ca91c5c1d1 | |||
| 85a1bbfcab | |||
| 5cb331def9 | |||
| 154d6eacf4 | |||
| 1555f2867d | |||
| b1e0e6a9e0 | |||
| fa8a1c53b4 | |||
| e3a20e2c33 | |||
| 4ef2bca643 | |||
| fc01fb6d6e | |||
| 57eb9797ca | |||
| 3800c62827 | |||
| 6d301ec510 | |||
| 6537b456f9 | |||
| 3d3ddd2197 | |||
| 5de1037e93 | |||
| 5c96e2deb9 | |||
| 0700ab282a | |||
| f0f8836042 | |||
| dc0258219d | |||
| 8b98768539 | |||
| 9267214300 | |||
| 04c2e59ada | |||
| 1b6d53f1c1 | |||
| 9badcddeae | |||
| 120b6c24d9 | |||
| d72ee8d9ef | |||
| 03225b3ae6 | |||
| 7266451b45 | |||
| 91d86545dc | |||
| 21e7291189 | |||
| 0c35c13ac1 | |||
| b179149597 | |||
| ca29c61521 | |||
| 2061fc74c2 | |||
| b570653c82 | |||
| f47afbdbcc | |||
| 4be35c76c0 | 
					 304 changed files with 10025 additions and 8695 deletions
				
			
		
							
								
								
									
										5
									
								
								.clangd
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.clangd
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					CompileFlags:
 | 
				
			||||||
 | 
					  DriverMode: cl
 | 
				
			||||||
 | 
					  Add:
 | 
				
			||||||
 | 
					    - /EHsc
 | 
				
			||||||
 | 
					    - /std:c++latest
 | 
				
			||||||
							
								
								
									
										37
									
								
								.drone.yml
									
										
									
									
									
								
							
							
						
						
									
										37
									
								
								.drone.yml
									
										
									
									
									
								
							| 
						 | 
					@ -25,13 +25,13 @@ trigger:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
steps:
 | 
					steps:
 | 
				
			||||||
- name: unit tests
 | 
					- name: unit tests
 | 
				
			||||||
  image: amd64_gcc_unit_tests:latest
 | 
					  image: ci:latest
 | 
				
			||||||
  pull: if-not-exists
 | 
					  pull: if-not-exists
 | 
				
			||||||
  commands:
 | 
					  commands:
 | 
				
			||||||
    - ./tools/ci/amd64/gcc/unit_tests.sh
 | 
					    - ./tools/ci/amd64/gcc/unit_tests.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- name: valgrind
 | 
					- name: valgrind
 | 
				
			||||||
  image: amd64_gcc_valgrind:latest
 | 
					  image: ci:latest
 | 
				
			||||||
  pull: if-not-exists
 | 
					  pull: if-not-exists
 | 
				
			||||||
  commands:
 | 
					  commands:
 | 
				
			||||||
    - ./tools/ci/amd64/gcc/valgrind.sh
 | 
					    - ./tools/ci/amd64/gcc/valgrind.sh
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@ trigger:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
steps:
 | 
					steps:
 | 
				
			||||||
- name: code coverage
 | 
					- name: code coverage
 | 
				
			||||||
  image: amd64_clang_coverage:latest
 | 
					  image: ci:latest
 | 
				
			||||||
  pull: if-not-exists
 | 
					  pull: if-not-exists
 | 
				
			||||||
  environment:
 | 
					  environment:
 | 
				
			||||||
    CODECOV_TOKEN:
 | 
					    CODECOV_TOKEN:
 | 
				
			||||||
| 
						 | 
					@ -55,13 +55,13 @@ steps:
 | 
				
			||||||
    - ./tools/ci/amd64/clang/coverage.sh
 | 
					    - ./tools/ci/amd64/clang/coverage.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- name: leak sanitizer
 | 
					- name: leak sanitizer
 | 
				
			||||||
  image: amd64_clang_lsan:latest
 | 
					  image: ci:latest
 | 
				
			||||||
  pull: if-not-exists
 | 
					  pull: if-not-exists
 | 
				
			||||||
  commands:
 | 
					  commands:
 | 
				
			||||||
    - ./tools/ci/amd64/clang/lsan.sh
 | 
					    - ./tools/ci/amd64/clang/lsan.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- name: memory sanitizer
 | 
					- name: memory sanitizer
 | 
				
			||||||
  image: amd64_clang_msan:latest
 | 
					  image: ci:latest
 | 
				
			||||||
  pull: if-not-exists
 | 
					  pull: if-not-exists
 | 
				
			||||||
  commands:
 | 
					  commands:
 | 
				
			||||||
    - ./tools/ci/amd64/clang/msan.sh
 | 
					    - ./tools/ci/amd64/clang/msan.sh
 | 
				
			||||||
| 
						 | 
					@ -76,18 +76,36 @@ trigger:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
steps:
 | 
					steps:
 | 
				
			||||||
- name: clang tidy
 | 
					- name: clang tidy
 | 
				
			||||||
  image: clang_tidy:latest
 | 
					  image: ci:latest
 | 
				
			||||||
  pull: if-not-exists
 | 
					  pull: if-not-exists
 | 
				
			||||||
  privileged: true
 | 
					  privileged: true
 | 
				
			||||||
  commands:
 | 
					  commands:
 | 
				
			||||||
    - ./tools/ci/static_analysis/clang_tidy.sh
 | 
					    - ./tools/ci/static_analysis/clang_tidy.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- name: shell check
 | 
				
			||||||
 | 
					  image: ci:latest
 | 
				
			||||||
 | 
					  pull: if-not-exists
 | 
				
			||||||
 | 
					  commands:
 | 
				
			||||||
 | 
					    - ./tools/ci/static_analysis/shell_check.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- name: clang format
 | 
					- name: clang format
 | 
				
			||||||
  image: clang_format:latest
 | 
					  image: ci:latest
 | 
				
			||||||
  pull: if-not-exists
 | 
					  pull: if-not-exists
 | 
				
			||||||
  commands:
 | 
					  commands:
 | 
				
			||||||
    - ./tools/ci/static_analysis/clang_format.sh
 | 
					    - ./tools/ci/static_analysis/clang_format.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- name: cmake format
 | 
				
			||||||
 | 
					  image: ci:latest
 | 
				
			||||||
 | 
					  pull: if-not-exists
 | 
				
			||||||
 | 
					  commands:
 | 
				
			||||||
 | 
					    - ./tools/ci/static_analysis/cmake_format.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- name: shell format
 | 
				
			||||||
 | 
					  image: ci:latest
 | 
				
			||||||
 | 
					  pull: if-not-exists
 | 
				
			||||||
 | 
					  commands:
 | 
				
			||||||
 | 
					    - ./tools/ci/static_analysis/shell_format.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
kind: pipeline
 | 
					kind: pipeline
 | 
				
			||||||
type: docker 
 | 
					type: docker 
 | 
				
			||||||
| 
						 | 
					@ -103,11 +121,7 @@ steps:
 | 
				
			||||||
  image: documentation:latest
 | 
					  image: documentation:latest
 | 
				
			||||||
  pull: if-not-exists
 | 
					  pull: if-not-exists
 | 
				
			||||||
  commands:
 | 
					  commands:
 | 
				
			||||||
    - pwd
 | 
					 | 
				
			||||||
    - cd docs
 | 
					    - cd docs
 | 
				
			||||||
    - mkdir generated
 | 
					 | 
				
			||||||
    - touch generated/changelogs.rst
 | 
					 | 
				
			||||||
    - touch generated/api.rst
 | 
					 | 
				
			||||||
    - sphinx-build -M html . .
 | 
					    - sphinx-build -M html . .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - rm -rf /light_docs_dev/*
 | 
					    - rm -rf /light_docs_dev/*
 | 
				
			||||||
| 
						 | 
					@ -137,3 +151,4 @@ steps:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - rm -rf /light_docs/*
 | 
					    - rm -rf /light_docs/*
 | 
				
			||||||
    - mv ./html/* /light_docs/
 | 
					    - mv ./html/* /light_docs/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,42 +1,8 @@
 | 
				
			||||||
cmake_minimum_required(VERSION 3.14)
 | 
					cmake_minimum_required(VERSION 3.14)
 | 
				
			||||||
project(Light)
 | 
					project(Light)
 | 
				
			||||||
set(CMAKE_CXX_STANDARD 23)
 | 
					 | 
				
			||||||
set(CMAKE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
include(CheckCXXSourceCompiles)
 | 
					include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/functions.cmake)
 | 
				
			||||||
include(${CMAKE_DIR}/functions.cmake)
 | 
					include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/definitions.cmake)
 | 
				
			||||||
include(${CMAKE_DIR}/definitions.cmake)
 | 
					include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/options.cmake)
 | 
				
			||||||
include(${CMAKE_DIR}/dependencies.cmake)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 ()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 ()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # 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_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}/modules)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,128 +0,0 @@
 | 
				
			||||||
# Contributor Covenant Code of Conduct
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Our Pledge
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
We as members, contributors, and leaders pledge to make participation in our
 | 
					 | 
				
			||||||
community a harassment-free experience for everyone, regardless of age, body
 | 
					 | 
				
			||||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
 | 
					 | 
				
			||||||
identity and expression, level of experience, education, socio-economic status,
 | 
					 | 
				
			||||||
nationality, personal appearance, race, religion, or sexual identity
 | 
					 | 
				
			||||||
and orientation.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
We pledge to act and interact in ways that contribute to an open, welcoming,
 | 
					 | 
				
			||||||
diverse, inclusive, and healthy community.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Our Standards
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Examples of behavior that contributes to a positive environment for our
 | 
					 | 
				
			||||||
community include:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* Demonstrating empathy and kindness toward other people
 | 
					 | 
				
			||||||
* Being respectful of differing opinions, viewpoints, and experiences
 | 
					 | 
				
			||||||
* Giving and gracefully accepting constructive feedback
 | 
					 | 
				
			||||||
* Accepting responsibility and apologizing to those affected by our mistakes,
 | 
					 | 
				
			||||||
  and learning from the experience
 | 
					 | 
				
			||||||
* Focusing on what is best not just for us as individuals, but for the
 | 
					 | 
				
			||||||
  overall community
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Examples of unacceptable behavior include:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* The use of sexualized language or imagery, and sexual attention or
 | 
					 | 
				
			||||||
  advances of any kind
 | 
					 | 
				
			||||||
* Trolling, insulting or derogatory comments, and personal or political attacks
 | 
					 | 
				
			||||||
* Public or private harassment
 | 
					 | 
				
			||||||
* Publishing others' private information, such as a physical or email
 | 
					 | 
				
			||||||
  address, without their explicit permission
 | 
					 | 
				
			||||||
* Other conduct which could reasonably be considered inappropriate in a
 | 
					 | 
				
			||||||
  professional setting
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Enforcement Responsibilities
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Community leaders are responsible for clarifying and enforcing our standards of
 | 
					 | 
				
			||||||
acceptable behavior and will take appropriate and fair corrective action in
 | 
					 | 
				
			||||||
response to any behavior that they deem inappropriate, threatening, offensive,
 | 
					 | 
				
			||||||
or harmful.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Community leaders have the right and responsibility to remove, edit, or reject
 | 
					 | 
				
			||||||
comments, commits, code, wiki edits, issues, and other contributions that are
 | 
					 | 
				
			||||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
 | 
					 | 
				
			||||||
decisions when appropriate.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Scope
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This Code of Conduct applies within all community spaces, and also applies when
 | 
					 | 
				
			||||||
an individual is officially representing the community in public spaces.
 | 
					 | 
				
			||||||
Examples of representing our community include using an official e-mail address,
 | 
					 | 
				
			||||||
posting via an official social media account, or acting as an appointed
 | 
					 | 
				
			||||||
representative at an online or offline event.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Enforcement
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
 | 
					 | 
				
			||||||
reported to the community leaders responsible for enforcement at
 | 
					 | 
				
			||||||
Discord: Light7734#4652.
 | 
					 | 
				
			||||||
All complaints will be reviewed and investigated promptly and fairly.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
All community leaders are obligated to respect the privacy and security of the
 | 
					 | 
				
			||||||
reporter of any incident.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Enforcement Guidelines
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Community leaders will follow these Community Impact Guidelines in determining
 | 
					 | 
				
			||||||
the consequences for any action they deem in violation of this Code of Conduct:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### 1. Correction
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**Community Impact**: Use of inappropriate language or other behavior deemed
 | 
					 | 
				
			||||||
unprofessional or unwelcome in the community.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**Consequence**: A private, written warning from community leaders, providing
 | 
					 | 
				
			||||||
clarity around the nature of the violation and an explanation of why the
 | 
					 | 
				
			||||||
behavior was inappropriate. A public apology may be requested.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### 2. Warning
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**Community Impact**: A violation through a single incident or series
 | 
					 | 
				
			||||||
of actions.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**Consequence**: A warning with consequences for continued behavior. No
 | 
					 | 
				
			||||||
interaction with the people involved, including unsolicited interaction with
 | 
					 | 
				
			||||||
those enforcing the Code of Conduct, for a specified period of time. This
 | 
					 | 
				
			||||||
includes avoiding interactions in community spaces as well as external channels
 | 
					 | 
				
			||||||
like social media. Violating these terms may lead to a temporary or
 | 
					 | 
				
			||||||
permanent ban.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### 3. Temporary Ban
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**Community Impact**: A serious violation of community standards, including
 | 
					 | 
				
			||||||
sustained inappropriate behavior.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**Consequence**: A temporary ban from any sort of interaction or public
 | 
					 | 
				
			||||||
communication with the community for a specified period of time. No public or
 | 
					 | 
				
			||||||
private interaction with the people involved, including unsolicited interaction
 | 
					 | 
				
			||||||
with those enforcing the Code of Conduct, is allowed during this period.
 | 
					 | 
				
			||||||
Violating these terms may lead to a permanent ban.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### 4. Permanent Ban
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**Community Impact**: Demonstrating a pattern of violation of community
 | 
					 | 
				
			||||||
standards, including sustained inappropriate behavior,  harassment of an
 | 
					 | 
				
			||||||
individual, or aggression toward or disparagement of classes of individuals.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
**Consequence**: A permanent ban from any sort of public interaction within
 | 
					 | 
				
			||||||
the community.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Attribution
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
 | 
					 | 
				
			||||||
version 2.0, available at
 | 
					 | 
				
			||||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
 | 
					 | 
				
			||||||
enforcement ladder](https://github.com/mozilla/diversity).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[homepage]: https://www.contributor-covenant.org
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
For answers to common questions about this code of conduct, see the FAQ at
 | 
					 | 
				
			||||||
https://www.contributor-covenant.org/faq. Translations are available at
 | 
					 | 
				
			||||||
https://www.contributor-covenant.org/translations.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,4 @@
 | 
				
			||||||
# Light
 | 
					# Light
 | 
				
			||||||
See docs.light7734.com for a comprehensive project documentation
 | 
					See docs.light7734.com for a comprehensive project documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!---FUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUCK
 | 
					###### “No great thing comes into being all at once, any more than a cluster of grapes or a fig. If you tell me, 'I want a fig,' I will answer that it needs time. Let it flower first, then put forth its fruit and then ripen. I say then, if the fig tree's fruit is not brought to perfection suddenly in a single hour, would you expect to gather the fruit of a person’s mind so soon and so easily? I tell you, you must not expect it.” —Epictetus, Discourses 1.15.7-8
 | 
				
			||||||
MEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
 | 
					 | 
				
			||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!!!!!!!!-->
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										63
									
								
								conanfile.py
									
										
									
									
									
								
							
							
						
						
									
										63
									
								
								conanfile.py
									
										
									
									
									
								
							| 
						 | 
					@ -1,63 +0,0 @@
 | 
				
			||||||
from conan import ConanFile
 | 
					 | 
				
			||||||
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout
 | 
					 | 
				
			||||||
import shutil
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import git
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class LightRecipe(ConanFile):
 | 
					 | 
				
			||||||
    name = "Light Engine"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    settings = "os", "compiler", "build_type", "arch"
 | 
					 | 
				
			||||||
    generators = "CMakeDeps"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    options = {
 | 
					 | 
				
			||||||
        "enable_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 = {
 | 
					 | 
				
			||||||
        "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("imgui/1.92.0-docking")
 | 
					 | 
				
			||||||
        self.requires("entt/3.15.0")
 | 
					 | 
				
			||||||
        self.requires("stb/cci.20240531")
 | 
					 | 
				
			||||||
        self.requires("yaml-cpp/0.8.0")
 | 
					 | 
				
			||||||
        self.requires("lz4/1.10.0")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def layout(self):
 | 
					 | 
				
			||||||
        cmake_layout(self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def generate(self):
 | 
					 | 
				
			||||||
        tc = CMakeToolchain(self)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        tc.variables["CMAKE_BUILD_TYPE"] = self.settings.build_type
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if self.options.use_mold:
 | 
					 | 
				
			||||||
            tc.cache_variables["CMAKE_LINKER_TYPE"] = "MOLD"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        tc.cache_variables["CMAKE_EXPORT_COMPILE_COMMANDS"] = self.options.export_compile_commands
 | 
					 | 
				
			||||||
        tc.cache_variables["ENABLE_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)
 | 
					 | 
				
			||||||
        tc.cache_variables["GIT_HASH"] = repo.head.object.hexsha
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        tc.generate()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def build(self):
 | 
					 | 
				
			||||||
        cmake = CMake(self)
 | 
					 | 
				
			||||||
        cmake.configure()
 | 
					 | 
				
			||||||
        cmake.build()
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,10 +0,0 @@
 | 
				
			||||||
#version 440 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
in vec4 vso_FragmentColor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out vec4 fso_FragmentColor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	fso_FragmentColor = vso_FragmentColor;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
#version 440 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(location = 0) in vec4 a_Position;
 | 
					 | 
				
			||||||
layout(location = 1) in vec4 a_Color;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(std140, binding = 0) uniform ub_ViewProjection
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	mat4 viewProjection;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(location = 0) out vec4 vso_FragmentColor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	gl_Position = viewProjection * a_Position;
 | 
					 | 
				
			||||||
	vso_FragmentColor = a_Color;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,12 +0,0 @@
 | 
				
			||||||
#version 450 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
in vec2 vso_TexCoord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uniform sampler2D u_Texture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out vec4 fso_FragmentColor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	fso_FragmentColor = texture(u_Texture, vso_TexCoord);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,19 +0,0 @@
 | 
				
			||||||
#version 450 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(location = 0) in vec4 a_Position;
 | 
					 | 
				
			||||||
layout(location = 1) in vec2 a_TexCoord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(std140, binding = 0) uniform ub_ViewProjection
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	mat4 u_ViewProjection;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(location = 0) out vec2 vso_TexCoord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	gl_Position = u_ViewProjection * a_Position;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vso_TexCoord = a_TexCoord;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
#version 450 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
in vec4 vso_Tint;
 | 
					 | 
				
			||||||
in vec2 vso_TexCoord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uniform sampler2D u_Texture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out vec4 fso_FragmentColor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	fso_FragmentColor = texture(u_Texture, vso_TexCoord) * vso_Tint;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,21 +0,0 @@
 | 
				
			||||||
#version 450 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(location = 0) in vec4 a_Position;
 | 
					 | 
				
			||||||
layout(location = 1) in vec4 a_Tint;
 | 
					 | 
				
			||||||
layout(location = 2) in vec2 a_TexCoord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(std140, binding = 0) uniform ub_ViewProjection
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	mat4 u_ViewProjection;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out vec4 vso_Tint;
 | 
					 | 
				
			||||||
out vec2 vso_TexCoord; 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	gl_Position = u_ViewProjection * a_Position;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vso_Tint = a_Tint;
 | 
					 | 
				
			||||||
	vso_TexCoord = a_TexCoord;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								data/test_assets/dummytext
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								data/test_assets/dummytext
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					The quick brown fox jumps over the lazy dog
 | 
				
			||||||
							
								
								
									
										10
									
								
								data/test_assets/triangle.frag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								data/test_assets/triangle.frag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					#version 450 core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) in vec3 in_frag_color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) out vec4 out_frag_color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						out_frag_color =  vec4(in_frag_color, 1.0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								data/test_assets/triangle.frag.asset
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/test_assets/triangle.frag.asset
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										26
									
								
								data/test_assets/triangle.vert
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								data/test_assets/triangle.vert
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					#version 450 core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(push_constant ) uniform pc {
 | 
				
			||||||
 | 
					 mat4 view_projection;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 positions[3] = vec3[](
 | 
				
			||||||
 | 
					    vec3(0.0, -0.5, 0.5),
 | 
				
			||||||
 | 
					    vec3(0.5, 0.5, 0.5),
 | 
				
			||||||
 | 
					    vec3(-0.5, 0.5, 0.5)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 colors[3] = vec3[](
 | 
				
			||||||
 | 
					    vec3(0.0, 0.0, 0.0),
 | 
				
			||||||
 | 
					    vec3(0.0, 0.0, 0.0),
 | 
				
			||||||
 | 
					    vec3(0.0, 0.0, 0.0)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) out vec3 out_frag_color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main() 
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gl_Position = view_projection * vec4(positions[gl_VertexIndex], 1.0);
 | 
				
			||||||
 | 
					    out_frag_color = colors[gl_VertexIndex];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								data/test_assets/triangle.vert.asset
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								data/test_assets/triangle.vert.asset
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,48 +0,0 @@
 | 
				
			||||||
[Window][Dockspace]
 | 
					 | 
				
			||||||
Pos=0,0
 | 
					 | 
				
			||||||
Size=1595,720
 | 
					 | 
				
			||||||
Collapsed=0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[Window][Debug##Default]
 | 
					 | 
				
			||||||
ViewportPos=2078,721
 | 
					 | 
				
			||||||
ViewportId=0x9F5F46A1
 | 
					 | 
				
			||||||
Size=848,1408
 | 
					 | 
				
			||||||
Collapsed=0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[Window][Dear ImGui Demo]
 | 
					 | 
				
			||||||
Pos=836,24
 | 
					 | 
				
			||||||
Size=759,696
 | 
					 | 
				
			||||||
Collapsed=0
 | 
					 | 
				
			||||||
DockId=0x00000003,1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[Window][Hierarchy]
 | 
					 | 
				
			||||||
Pos=0,24
 | 
					 | 
				
			||||||
Size=184,696
 | 
					 | 
				
			||||||
Collapsed=0
 | 
					 | 
				
			||||||
DockId=0x00000001,0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[Window][Properties]
 | 
					 | 
				
			||||||
Pos=836,24
 | 
					 | 
				
			||||||
Size=759,696
 | 
					 | 
				
			||||||
Collapsed=0
 | 
					 | 
				
			||||||
DockId=0x00000003,0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[Window][Game]
 | 
					 | 
				
			||||||
Pos=186,24
 | 
					 | 
				
			||||||
Size=648,696
 | 
					 | 
				
			||||||
Collapsed=0
 | 
					 | 
				
			||||||
DockId=0x00000002,0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[Window][Content Browser]
 | 
					 | 
				
			||||||
ViewportPos=1359,621
 | 
					 | 
				
			||||||
ViewportId=0x371352B7
 | 
					 | 
				
			||||||
Size=1274,1296
 | 
					 | 
				
			||||||
Collapsed=0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[Docking][Data]
 | 
					 | 
				
			||||||
DockSpace     ID=0x1ED03EE2 Window=0x5B816B74 Pos=516,375 Size=1595,696 Split=X
 | 
					 | 
				
			||||||
  DockNode    ID=0x00000006 Parent=0x1ED03EE2 SizeRef=834,696 Split=X
 | 
					 | 
				
			||||||
    DockNode  ID=0x00000001 Parent=0x00000006 SizeRef=184,696 Selected=0x29EABFBD
 | 
					 | 
				
			||||||
    DockNode  ID=0x00000002 Parent=0x00000006 SizeRef=648,696 CentralNode=1 Selected=0x26816F31
 | 
					 | 
				
			||||||
  DockNode    ID=0x00000003 Parent=0x1ED03EE2 SizeRef=759,696 Selected=0x199AB496
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
							
								
								
									
										2
									
								
								docs/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								docs/.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
_build/
 | 
					_build/
 | 
				
			||||||
generated/
 | 
					generated/
 | 
				
			||||||
 | 
					html/
 | 
				
			||||||
 | 
					xml/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										86
									
								
								docs/Doxyfile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								docs/Doxyfile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,86 @@
 | 
				
			||||||
 | 
					TARGET = ./
 | 
				
			||||||
 | 
					INPUT = "../modules"
 | 
				
			||||||
 | 
					RECURSIVE = YES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PROJECT_NAME           = "Light"
 | 
				
			||||||
 | 
					JAVADOC_AUTOBRIEF      = YES
 | 
				
			||||||
 | 
					JAVADOC_BANNER         = YES
 | 
				
			||||||
 | 
					GENERATE_XML           = YES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXTRACT_PRIVATE = NO
 | 
				
			||||||
 | 
					EXTRACT_STATIC = NO
 | 
				
			||||||
 | 
					EXTRACT_LOCAL_CLASSES = NO
 | 
				
			||||||
 | 
					HIDE_UNDOC_RELATIONS = YES
 | 
				
			||||||
 | 
					HAVE_DOT = NO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GENERATE_TODOLIST      = NO
 | 
				
			||||||
 | 
					GENERATE_HTML          = NO
 | 
				
			||||||
 | 
					GENERATE_DOCSET        = NO
 | 
				
			||||||
 | 
					GENERATE_HTMLHELP      = NO
 | 
				
			||||||
 | 
					GENERATE_CHI           = NO
 | 
				
			||||||
 | 
					GENERATE_QHP           = NO
 | 
				
			||||||
 | 
					GENERATE_ECLIPSEHELP   = NO
 | 
				
			||||||
 | 
					GENERATE_TREEVIEW      = NO
 | 
				
			||||||
 | 
					GENERATE_LATEX         = NO
 | 
				
			||||||
 | 
					GENERATE_RTF           = NO
 | 
				
			||||||
 | 
					GENERATE_MAN           = NO
 | 
				
			||||||
 | 
					GENERATE_DOCBOOK       = NO
 | 
				
			||||||
 | 
					GENERATE_AUTOGEN_DEF   = NO
 | 
				
			||||||
 | 
					GENERATE_SQLITE3       = NO
 | 
				
			||||||
 | 
					GENERATE_PERLMOD       = NO
 | 
				
			||||||
 | 
					GENERATE_TAGFILE       = NO
 | 
				
			||||||
 | 
					GENERATE_LEGEND        = NO
 | 
				
			||||||
 | 
					GENERATE_TESTLIST      = NO
 | 
				
			||||||
 | 
					GENERATE_BUGLIST       = NO
 | 
				
			||||||
 | 
					GENERATE_DEPRECATEDLIST= NO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FILE_PATTERNS          = *.c \
 | 
				
			||||||
 | 
					                         *.cc \
 | 
				
			||||||
 | 
					                         *.cxx \
 | 
				
			||||||
 | 
					                         *.cxxm \
 | 
				
			||||||
 | 
					                         *.cpp \
 | 
				
			||||||
 | 
					                         *.cppm \
 | 
				
			||||||
 | 
					                         *.ccm \
 | 
				
			||||||
 | 
					                         *.c++ \
 | 
				
			||||||
 | 
					                         *.c++m \
 | 
				
			||||||
 | 
					                         *.java \
 | 
				
			||||||
 | 
					                         *.ii \
 | 
				
			||||||
 | 
					                         *.ixx \
 | 
				
			||||||
 | 
					                         *.ipp \
 | 
				
			||||||
 | 
					                         *.i++ \
 | 
				
			||||||
 | 
					                         *.inl \
 | 
				
			||||||
 | 
					                         *.idl \
 | 
				
			||||||
 | 
					                         *.ddl \
 | 
				
			||||||
 | 
					                         *.odl \
 | 
				
			||||||
 | 
					                         *.h \
 | 
				
			||||||
 | 
					                         *.hh \
 | 
				
			||||||
 | 
					                         *.hxx \
 | 
				
			||||||
 | 
					                         *.hpp \
 | 
				
			||||||
 | 
					                         *.h++ \
 | 
				
			||||||
 | 
					                         *.l \
 | 
				
			||||||
 | 
					                         *.cs \
 | 
				
			||||||
 | 
					                         *.d \
 | 
				
			||||||
 | 
					                         *.php \
 | 
				
			||||||
 | 
					                         *.php4 \
 | 
				
			||||||
 | 
					                         *.php5 \
 | 
				
			||||||
 | 
					                         *.phtml \
 | 
				
			||||||
 | 
					                         *.inc \
 | 
				
			||||||
 | 
					                         *.m \
 | 
				
			||||||
 | 
					                         *.markdown \
 | 
				
			||||||
 | 
					                         *.md \
 | 
				
			||||||
 | 
					                         *.mm \
 | 
				
			||||||
 | 
					                         *.dox \
 | 
				
			||||||
 | 
					                         *.py \
 | 
				
			||||||
 | 
					                         *.pyw \
 | 
				
			||||||
 | 
					                         *.f90 \
 | 
				
			||||||
 | 
					                         *.f95 \
 | 
				
			||||||
 | 
					                         *.f03 \
 | 
				
			||||||
 | 
					                         *.f08 \
 | 
				
			||||||
 | 
					                         *.f18 \
 | 
				
			||||||
 | 
					                         *.f \
 | 
				
			||||||
 | 
					                         *.for \
 | 
				
			||||||
 | 
					                         *.vhd \
 | 
				
			||||||
 | 
					                         *.vhdl \
 | 
				
			||||||
 | 
					                         *.ucf \
 | 
				
			||||||
 | 
					                         *.qsf \
 | 
				
			||||||
 | 
					                         *.ice
 | 
				
			||||||
							
								
								
									
										17
									
								
								docs/api/app.rst
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								docs/api/app.rst
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					Application
 | 
				
			||||||
 | 
					===================================================================================================
 | 
				
			||||||
 | 
					.. toctree::
 | 
				
			||||||
 | 
					   :maxdepth: 3
 | 
				
			||||||
 | 
					   :caption: App
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Functions
 | 
				
			||||||
 | 
					---------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					.. doxygenfunction:: main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Classes
 | 
				
			||||||
 | 
					---------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					.. doxygenclass:: lt::app::ISystem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. doxygenstruct:: lt::app::TickInfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. doxygenstruct:: lt::app::TickResult
 | 
				
			||||||
							
								
								
									
										13
									
								
								docs/api/renderer.rst
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								docs/api/renderer.rst
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					Renderer
 | 
				
			||||||
 | 
					===================================================================================================
 | 
				
			||||||
 | 
					.. toctree::
 | 
				
			||||||
 | 
					   :maxdepth: 3
 | 
				
			||||||
 | 
					   :caption: App
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Classes
 | 
				
			||||||
 | 
					---------------------------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					.. doxygenenum:: lt::renderer::Api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. doxygenclass:: lt::renderer::System
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. doxygenstruct:: lt::renderer::components::Sprite
 | 
				
			||||||
							
								
								
									
										14
									
								
								docs/conf.py
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								docs/conf.py
									
										
									
									
									
								
							| 
						 | 
					@ -13,13 +13,21 @@ author = 'light7734'
 | 
				
			||||||
# -- General configuration ---------------------------------------------------
 | 
					# -- General configuration ---------------------------------------------------
 | 
				
			||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
 | 
					# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extensions = []
 | 
					extensions = ['breathe']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					breathe_projects = {"Light": "./xml"}
 | 
				
			||||||
 | 
					breathe_default_project = "Light"
 | 
				
			||||||
 | 
					breathe_default_members = ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Tell sphinx what the primary language being documented is.
 | 
				
			||||||
 | 
					primary_domain = 'cpp'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Tell sphinx what the pygments highlight language should be.
 | 
				
			||||||
 | 
					highlight_language = 'cpp'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
templates_path = ['_templates']
 | 
					templates_path = ['_templates']
 | 
				
			||||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
 | 
					exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# -- Options for HTML output -------------------------------------------------
 | 
					# -- Options for HTML output -------------------------------------------------
 | 
				
			||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
 | 
					# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,68 +0,0 @@
 | 
				
			||||||
from git import Repo
 | 
					 | 
				
			||||||
import re
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
repo = Repo(search_parent_directories=True)
 | 
					 | 
				
			||||||
assert not repo.bare
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
file_path = "generated/changelog.rst"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
messages = []
 | 
					 | 
				
			||||||
short_shas = []
 | 
					 | 
				
			||||||
hex_shas = []
 | 
					 | 
				
			||||||
logs = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
remote_url = "https://git.light7734.com/light7734/light/commit"
 | 
					 | 
				
			||||||
def format_log(commit_type, message, major, minor, patch, short_sha, hex_sha):
 | 
					 | 
				
			||||||
    href = f"{remote_url}/{hex_sha}"
 | 
					 | 
				
			||||||
    version = f"{major}.{minor}.{patch}-kitten+{short_sha}";
 | 
					 | 
				
			||||||
    link = f"`{version} <{remote_url}/{hex_sha}>`__"
 | 
					 | 
				
			||||||
    return f"| **{message}** ({link})"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
for commit in repo.iter_commits():
 | 
					 | 
				
			||||||
    messages.append(commit.summary)
 | 
					 | 
				
			||||||
    short_shas.append(repo.git.rev_parse(commit.hexsha, short=5))
 | 
					 | 
				
			||||||
    hex_shas.append(commit.hexsha)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ver_major = 0
 | 
					 | 
				
			||||||
ver_minor = 0
 | 
					 | 
				
			||||||
ver_patch = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
idx = len(messages)
 | 
					 | 
				
			||||||
for message in reversed(messages):
 | 
					 | 
				
			||||||
    idx = idx - 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    commit_type = re.match("^(feat|fix|refactor|perf|build|asset|test|chore|ci|docs)", message)
 | 
					 | 
				
			||||||
    if not commit_type:
 | 
					 | 
				
			||||||
        continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    match commit_type.group(0):
 | 
					 | 
				
			||||||
        case "feat":
 | 
					 | 
				
			||||||
            ver_minor = ver_minor + 1
 | 
					 | 
				
			||||||
            ver_patch = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        case "fix":
 | 
					 | 
				
			||||||
            ver_patch = ver_patch + 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        case "refactor":
 | 
					 | 
				
			||||||
            ver_patch = ver_patch + 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        case "perf":
 | 
					 | 
				
			||||||
            ver_patch = ver_patch + 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        case "build":
 | 
					 | 
				
			||||||
            ver_patch = ver_patch + 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        case "asset":
 | 
					 | 
				
			||||||
            ver_patch = ver_patch + 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    logs.append(format_log(commit_type, message, ver_major, ver_minor, ver_patch, short_shas[idx], hex_shas[idx]))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
with open(file_path, "w") as f:
 | 
					 | 
				
			||||||
    f.write(".. changelogs\n\n\n")
 | 
					 | 
				
			||||||
    f.write("Changelogs\n")
 | 
					 | 
				
			||||||
    f.write("==================================================\n\n")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    f.write("KITTEN\n")
 | 
					 | 
				
			||||||
    f.write("--------------------------------------------------\n\n")
 | 
					 | 
				
			||||||
    for log in reversed(logs):
 | 
					 | 
				
			||||||
          f.write(log + '\n')
 | 
					 | 
				
			||||||
| 
						 | 
					@ -23,10 +23,10 @@
 | 
				
			||||||
   guidelines/conventions.rst
 | 
					   guidelines/conventions.rst
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. toctree::
 | 
					.. toctree::
 | 
				
			||||||
   :maxdepth: 2
 | 
					   :maxdepth: 3
 | 
				
			||||||
   :caption: Generated Docs
 | 
					   :caption: API
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   generated/api.rst
 | 
					   api/app.rst
 | 
				
			||||||
   generated/changelog.rst
 | 
					   api/renderer.rst
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,35 +0,0 @@
 | 
				
			||||||
@ECHO OFF
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pushd %~dp0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
REM Command file for Sphinx documentation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if "%SPHINXBUILD%" == "" (
 | 
					 | 
				
			||||||
	set SPHINXBUILD=sphinx-build
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
set SOURCEDIR=.
 | 
					 | 
				
			||||||
set BUILDDIR=_build
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%SPHINXBUILD% >NUL 2>NUL
 | 
					 | 
				
			||||||
if errorlevel 9009 (
 | 
					 | 
				
			||||||
	echo.
 | 
					 | 
				
			||||||
	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
 | 
					 | 
				
			||||||
	echo.installed, then set the SPHINXBUILD environment variable to point
 | 
					 | 
				
			||||||
	echo.to the full path of the 'sphinx-build' executable. Alternatively you
 | 
					 | 
				
			||||||
	echo.may add the Sphinx directory to PATH.
 | 
					 | 
				
			||||||
	echo.
 | 
					 | 
				
			||||||
	echo.If you don't have Sphinx installed, grab it from
 | 
					 | 
				
			||||||
	echo.https://www.sphinx-doc.org/
 | 
					 | 
				
			||||||
	exit /b 1
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if "%1" == "" goto help
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
 | 
					 | 
				
			||||||
goto end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
:help
 | 
					 | 
				
			||||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
:end
 | 
					 | 
				
			||||||
popd
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,20 +1,22 @@
 | 
				
			||||||
# engine
 | 
					# engine
 | 
				
			||||||
add_subdirectory(./base)
 | 
					add_subdirectory(./std)
 | 
				
			||||||
 | 
					add_subdirectory(./bitwise)
 | 
				
			||||||
 | 
					add_subdirectory(./env)
 | 
				
			||||||
 | 
					add_subdirectory(./memory)
 | 
				
			||||||
add_subdirectory(./time)
 | 
					add_subdirectory(./time)
 | 
				
			||||||
add_subdirectory(./logger)
 | 
					add_subdirectory(./logger)
 | 
				
			||||||
add_subdirectory(./debug)
 | 
					add_subdirectory(./debug)
 | 
				
			||||||
add_subdirectory(./math)
 | 
					add_subdirectory(./math)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
add_subdirectory(./asset_baker)
 | 
					add_subdirectory(./asset_baker)
 | 
				
			||||||
add_subdirectory(./asset_parser)
 | 
					add_subdirectory(./assets)
 | 
				
			||||||
# add_subdirectory(./asset_manager)
 | 
					 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
add_subdirectory(./camera)
 | 
					add_subdirectory(./camera)
 | 
				
			||||||
add_subdirectory(./input)
 | 
					add_subdirectory(./input)
 | 
				
			||||||
# add_subdirectory(./ui)
 | 
					# add_subdirectory(./ui)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
add_subdirectory(./surface)
 | 
					add_subdirectory(./surface)
 | 
				
			||||||
# add_subdirectory(./renderer)
 | 
					add_subdirectory(./renderer)
 | 
				
			||||||
add_subdirectory(./ecs)
 | 
					add_subdirectory(./ecs)
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
add_subdirectory(./app)
 | 
					add_subdirectory(./app)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,2 +1,5 @@
 | 
				
			||||||
add_library_module(app application.cpp)
 | 
					add_library_module(app application.cpp)
 | 
				
			||||||
target_link_libraries(app PRIVATE lt_debug)
 | 
					target_link_libraries(
 | 
				
			||||||
 | 
					    app
 | 
				
			||||||
 | 
					    PUBLIC memory
 | 
				
			||||||
 | 
					    PRIVATE lt_debug)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#include <app/application.hpp>
 | 
					#include <app/application.hpp>
 | 
				
			||||||
#include <app/system.hpp>
 | 
					#include <app/system.hpp>
 | 
				
			||||||
 | 
					#include <memory/reference.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::app {
 | 
					namespace lt::app {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,10 +10,16 @@ void Application::game_loop()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		for (auto &system : m_systems)
 | 
							for (auto &system : m_systems)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (system->tick())
 | 
								const auto &last_tick = system->get_last_tick_result();
 | 
				
			||||||
			{
 | 
								const auto now = std::chrono::steady_clock::now();
 | 
				
			||||||
				return;
 | 
					
 | 
				
			||||||
 | 
								system->tick(
 | 
				
			||||||
 | 
								    TickInfo {
 | 
				
			||||||
 | 
								        .delta_time = now - last_tick.end_time,
 | 
				
			||||||
 | 
								        .budget = std::chrono::milliseconds { 10 },
 | 
				
			||||||
 | 
								        .start_time = now,
 | 
				
			||||||
			    }
 | 
								    }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto &system : m_systems_to_be_registered)
 | 
							for (auto &system : m_systems_to_be_registered)
 | 
				
			||||||
| 
						 | 
					@ -35,12 +42,12 @@ void Application::game_loop()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Application::register_system(Ref<app::ISystem> system)
 | 
					void Application::register_system(memory::Ref<app::ISystem> system)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	m_systems.emplace_back(std::move(system));
 | 
						m_systems.emplace_back(std::move(system));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Application::unregister_system(Ref<app::ISystem> system)
 | 
					void Application::unregister_system(memory::Ref<app::ISystem> system)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	m_systems_to_be_unregistered.emplace_back(std::move(system));
 | 
						m_systems_to_be_unregistered.emplace_back(std::move(system));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,13 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <memory/reference.hpp>
 | 
				
			||||||
 | 
					#include <memory/scope.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::app {
 | 
					namespace lt::app {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ISystem;
 | 
					class ISystem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern Scope<class Application> create_application();
 | 
					extern memory::Scope<class Application> create_application();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** The main application class.
 | 
					/** The main application class.
 | 
				
			||||||
 * Think of this like an aggregate of systems, you register systems through this interface.
 | 
					 * Think of this like an aggregate of systems, you register systems through this interface.
 | 
				
			||||||
| 
						 | 
					@ -25,19 +28,19 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void game_loop();
 | 
						void game_loop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void register_system(Ref<app::ISystem> system);
 | 
						void register_system(memory::Ref<app::ISystem> system);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void unregister_system(Ref<app::ISystem> system);
 | 
						void unregister_system(memory::Ref<app::ISystem> system);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	Application() = default;
 | 
						Application() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	std::vector<Ref<app::ISystem>> m_systems;
 | 
						std::vector<memory::Ref<app::ISystem>> m_systems;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::vector<Ref<app::ISystem>> m_systems_to_be_unregistered;
 | 
						std::vector<memory::Ref<app::ISystem>> m_systems_to_be_unregistered;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::vector<Ref<app::ISystem>> m_systems_to_be_registered;
 | 
						std::vector<memory::Ref<app::ISystem>> m_systems_to_be_registered;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <app/application.hpp>
 | 
					#include <app/application.hpp>
 | 
				
			||||||
 | 
					#include <logger/logger.hpp>
 | 
				
			||||||
 | 
					#include <memory/scope.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto main(int argc, char *argv[]) -> int32_t
 | 
					auto main(int argc, char *argv[]) -> int32_t
 | 
				
			||||||
try
 | 
					try
 | 
				
			||||||
| 
						 | 
					@ -8,8 +10,7 @@ try
 | 
				
			||||||
	std::ignore = argc;
 | 
						std::ignore = argc;
 | 
				
			||||||
	std::ignore = argv;
 | 
						std::ignore = argv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto application = lt::Scope<lt::app::Application> {};
 | 
						auto application = lt::memory::Scope<lt::app::Application> {};
 | 
				
			||||||
 | 
					 | 
				
			||||||
	application = lt::app::create_application();
 | 
						application = lt::app::create_application();
 | 
				
			||||||
	if (!application)
 | 
						if (!application)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -21,7 +22,7 @@ try
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
catch (const std::exception &exp)
 | 
					catch (const std::exception &exp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	log_crt("Terminating due to uncaught exception:");
 | 
						lt::log::critical("Terminating due to uncaught exception:");
 | 
				
			||||||
	log_crt("\texception.what(): {}", exp.what());
 | 
						lt::log::critical("\texception.what(): {}", exp.what());
 | 
				
			||||||
	return EXIT_FAILURE;
 | 
						return EXIT_FAILURE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,90 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <chrono>
 | 
				
			||||||
 | 
					#include <logger/logger.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::app {
 | 
					namespace lt::app {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Information required to tick a system.
 | 
				
			||||||
 | 
					 * @note May be used across an entire application-frame (consisting of multiple systems ticking)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct TickInfo
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						using Timepoint_T = std::chrono::time_point<std::chrono::steady_clock>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						using Duration_T = std::chrono::duration<double>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Duration since previous tick's end_time to current tick's start_time. */
 | 
				
			||||||
 | 
						Duration_T delta_time {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Maximum duration the system is expected to finish ticking in.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * if end_time - start_time > budget -> the system exceeded its ticking budget.
 | 
				
			||||||
 | 
						 * else end_time - start_time < budget -> the system ticked properly.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * In other words, end_time is expected to be less than start_time + budget.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						Duration_T budget {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Exact time which ticking started. */
 | 
				
			||||||
 | 
						Timepoint_T start_time;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Information about how a system's tick performed */
 | 
				
			||||||
 | 
					struct TickResult
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						using Timepoint_T = std::chrono::time_point<std::chrono::steady_clock>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						using Duration_T = std::chrono::duration<double>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** The info supplied to the system for ticking. */
 | 
				
			||||||
 | 
						TickInfo info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Equivalent to end_time - info.start_time. */
 | 
				
			||||||
 | 
						Duration_T duration {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Exact time which ticking ended. */
 | 
				
			||||||
 | 
						Timepoint_T end_time;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SystemDiagnosis
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						enum class Severity : uint8_t
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							verbose,
 | 
				
			||||||
 | 
							info,
 | 
				
			||||||
 | 
							warning,
 | 
				
			||||||
 | 
							error,
 | 
				
			||||||
 | 
							fatal,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Severity severity;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SystemStats
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void push_diagnosis(SystemDiagnosis &&diagnosis)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto diag = m_diagnosis.emplace_back(std::move(diagnosis));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log::debug("message: {}", diag.message);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto empty_diagnosis() const -> bool
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_diagnosis.empty();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						std::vector<SystemDiagnosis> m_diagnosis;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ISystem
 | 
					class ISystem
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
| 
						 | 
					@ -21,7 +104,9 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual void on_unregister() = 0;
 | 
						virtual void on_unregister() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual auto tick() -> bool = 0;
 | 
						virtual void tick(TickInfo tick) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] virtual auto get_last_tick_result() const -> const TickResult & = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace lt::app
 | 
					} // namespace lt::app
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,6 @@
 | 
				
			||||||
add_executable_module(
 | 
					add_library_module(libasset_baker bakers.cpp)
 | 
				
			||||||
    asset_baker entrypoint/baker.cpp
 | 
					target_link_libraries(libasset_baker PUBLIC assets logger lt_debug tbb)
 | 
				
			||||||
)
 | 
					add_test_module(libasset_baker bakers.test.cpp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_link_libraries(
 | 
					add_executable_module(asset_baker entrypoint/baker.cpp)
 | 
				
			||||||
    asset_baker
 | 
					target_link_libraries(asset_baker PRIVATE libasset_baker)
 | 
				
			||||||
    PRIVATE asset_parser
 | 
					 | 
				
			||||||
    PRIVATE stb::stb
 | 
					 | 
				
			||||||
    PRIVATE logger
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								modules/asset_baker/private/bakers.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								modules/asset_baker/private/bakers.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,2 @@
 | 
				
			||||||
 | 
					#include <asset_baker/bakers.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
| 
						 | 
					@ -1,69 +1,7 @@
 | 
				
			||||||
#include <asset_baker/bakers.hpp>
 | 
					#include <asset_baker/bakers.hpp>
 | 
				
			||||||
#include <asset_parser/assets/text.hpp>
 | 
					#include <assets/shader.hpp>
 | 
				
			||||||
#include <asset_parser/assets/texture.hpp>
 | 
					 | 
				
			||||||
#include <asset_parser/parser.hpp>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					#include <logger/logger.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void try_packing_texture(
 | 
					 | 
				
			||||||
    const std::filesystem::path &in_path,
 | 
					 | 
				
			||||||
    const std::filesystem::path &out_path
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	auto texture_loader = lt::TextureLoaderFactory::create(in_path.extension().string());
 | 
					 | 
				
			||||||
	if (!texture_loader)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// Don't log anything; this is expected.
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	try
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Assets::TextureAsset::pack(texture_loader->load(in_path), out_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		log_inf("Packed a texture asset:");
 | 
					 | 
				
			||||||
		log_inf("\tloader  : {}", texture_loader->get_name());
 | 
					 | 
				
			||||||
		log_inf("\tin  path: {}", in_path.string());
 | 
					 | 
				
			||||||
		log_inf("\tout path: {}", out_path.string());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	catch (const std::exception &exp)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_err("Failed to pack texture asset:");
 | 
					 | 
				
			||||||
		log_err("\tloader  : {}", texture_loader->get_name());
 | 
					 | 
				
			||||||
		log_err("\tin path : {}", in_path.string());
 | 
					 | 
				
			||||||
		log_err("\tout path: {}", out_path.string());
 | 
					 | 
				
			||||||
		log_err("\texp.what: {}", exp.what());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void try_packing_text(const std::filesystem::path &in_path, const std::filesystem::path &out_path)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	auto text_loader = lt::TextLoaderFactory::create(in_path.extension().string());
 | 
					 | 
				
			||||||
	if (!text_loader)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// Don't log anything; this is expected.
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	try
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Assets::TextAsset::pack(text_loader->load(in_path), out_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		log_inf("Packed a text asset:");
 | 
					 | 
				
			||||||
		log_inf("\tloader  : {}", text_loader->get_name());
 | 
					 | 
				
			||||||
		log_inf("\tin  path: {}", in_path.string());
 | 
					 | 
				
			||||||
		log_inf("\tout path: {}", out_path.string());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	catch (const std::exception &exp)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_err("Failed to pack a text asset:");
 | 
					 | 
				
			||||||
		log_err("\tloader  : {}", text_loader->get_name());
 | 
					 | 
				
			||||||
		log_err("\tin path : {}", in_path.string());
 | 
					 | 
				
			||||||
		log_err("\tout path: {}", out_path.string());
 | 
					 | 
				
			||||||
		log_err("\texp.what: {}", exp.what());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto main(int argc, char *argv[]) -> int32_t
 | 
					auto main(int argc, char *argv[]) -> int32_t
 | 
				
			||||||
try
 | 
					try
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -81,20 +19,24 @@ try
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const auto &in_path = directory_iterator.path();
 | 
							const auto &in_path = directory_iterator.path();
 | 
				
			||||||
 | 
							const auto out_path = std::format("{}.asset", in_path.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto out_path = in_path;
 | 
							if (in_path.extension() == ".vert")
 | 
				
			||||||
		out_path.replace_extension(".asset");
 | 
							{
 | 
				
			||||||
 | 
								bake_shader(in_path, out_path, lt::assets::ShaderAsset::Type::vertex);
 | 
				
			||||||
		try_packing_texture(in_path, out_path);
 | 
							}
 | 
				
			||||||
		try_packing_text(in_path, out_path);
 | 
							else if (in_path.extension() == ".frag")
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bake_shader(in_path, out_path, lt::assets::ShaderAsset::Type::fragment);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return EXIT_SUCCESS;
 | 
						return EXIT_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
catch (const std::exception &exp)
 | 
					catch (const std::exception &exp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	log_crt("Terminating due to uncaught exception:");
 | 
						lt::log::critical("Terminating due to uncaught exception:");
 | 
				
			||||||
	log_crt("\texception.what: {}:", exp.what());
 | 
						lt::log::critical("\texception.what: {}:", exp.what());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return EXIT_FAILURE;
 | 
						return EXIT_FAILURE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,184 +1,65 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asset_parser/assets/text.hpp>
 | 
					#include <assets/shader.hpp>
 | 
				
			||||||
#include <asset_parser/assets/texture.hpp>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					#include <logger/logger.hpp>
 | 
				
			||||||
#include <string_view>
 | 
					 | 
				
			||||||
#include <unordered_set>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STB_IMAGE_IMPLEMENTATION
 | 
					inline void bake_shader(
 | 
				
			||||||
#include <stb_image.h>
 | 
					    const std::filesystem::path &in_path,
 | 
				
			||||||
 | 
					    const std::filesystem::path &out_path,
 | 
				
			||||||
namespace lt {
 | 
					    lt::assets::ShaderAsset::Type type
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
class Loader
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
						using lt::assets::ShaderAsset;
 | 
				
			||||||
	[[nodiscard]] virtual auto get_name() const -> std::string_view = 0;
 | 
						using enum lt::assets::ShaderAsset::Type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Loader() = default;
 | 
						auto glsl_path = in_path.string();
 | 
				
			||||||
 | 
						auto spv_path = std::format("{}.spv", glsl_path);
 | 
				
			||||||
 | 
						lt::log::trace(
 | 
				
			||||||
 | 
						    "Compiling {} shader {} -> {}",
 | 
				
			||||||
 | 
						    type == vertex ? "vertex" : "fragment",
 | 
				
			||||||
 | 
						    glsl_path,
 | 
				
			||||||
 | 
						    spv_path
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Loader(Loader &&) = default;
 | 
						// Don't bother linking to shaderc, just invoke the command with a system call.
 | 
				
			||||||
 | 
						// NOLINTNEXTLINE(concurrency-mt-unsafe)
 | 
				
			||||||
	Loader(const Loader &) = delete;
 | 
						system(
 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto operator=(Loader &&) -> Loader & = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto operator=(const Loader &) -> Loader & = delete;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	virtual ~Loader() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextureLoader: public Loader
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	TextureLoader() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] virtual auto load(std::filesystem::path file_path) const
 | 
					 | 
				
			||||||
	    -> Assets::TextureAsset::PackageData
 | 
					 | 
				
			||||||
	    = 0;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StbLoader: public TextureLoader
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	StbLoader() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void load(std::filesystem::path path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] static auto get_supported_extensions() -> std::unordered_set<std::string_view>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return { ".png" };
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_name() const -> std::string_view override
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return "StbLoader";
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto load(std::filesystem::path file_path) const
 | 
					 | 
				
			||||||
	    -> Assets::TextureAsset::PackageData override
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		auto width = int {};
 | 
					 | 
				
			||||||
		auto height = int {};
 | 
					 | 
				
			||||||
		auto channels = int {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto *pixels = stbi_load(file_path.string().c_str(), &width, &height, &channels, 4);
 | 
					 | 
				
			||||||
		if (!pixels)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			throw std::runtime_error {
 | 
					 | 
				
			||||||
				std::format("Failed to load image file at: {} using stbi_load", file_path.string()),
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const auto metadata = Assets::Asset::Metadata {
 | 
					 | 
				
			||||||
			.type = Assets::Asset::Type::Texture,
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const auto texture_metadata = Assets::TextureAsset::Metadata {
 | 
					 | 
				
			||||||
            .format = Assets::TextureAsset::Format::RGBA8,
 | 
					 | 
				
			||||||
            .num_components = static_cast<uint32_t>(channels),
 | 
					 | 
				
			||||||
            .pixel_size = {
 | 
					 | 
				
			||||||
                static_cast<uint32_t>(width),
 | 
					 | 
				
			||||||
                static_cast<uint32_t>(height),
 | 
					 | 
				
			||||||
                {},
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto pixels_blob = Assets::Blob {};
 | 
					 | 
				
			||||||
		pixels_blob.resize(static_cast<size_t>(width) * height * channels);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// TODO(Light): figure out if it's possible to directly populate a blob with stbi functions
 | 
					 | 
				
			||||||
		memcpy(pixels_blob.data(), pixels, pixels_blob.size());
 | 
					 | 
				
			||||||
		stbi_image_free(pixels);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return Assets::TextureAsset::PackageData {
 | 
					 | 
				
			||||||
			.metadata = metadata,
 | 
					 | 
				
			||||||
			.texture_metadata = texture_metadata,
 | 
					 | 
				
			||||||
			.pixels = std::move(pixels_blob),
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextureLoaderFactory
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	static auto create(std::string_view file_extension) -> std::unique_ptr<TextureLoader>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (StbLoader::get_supported_extensions().contains(file_extension))
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return std::make_unique<StbLoader>();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return {};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextLoader: Loader
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	[[nodiscard]] static auto get_supported_extensions() -> std::unordered_set<std::string_view>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return { ".glsl", ".txt", ".hlsl" };
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_name() const -> std::string_view override
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return "TextLoader";
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto load(const std::filesystem::path &file_path) const
 | 
					 | 
				
			||||||
	    -> Assets::TextAsset::PackageData
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		auto stream = std::ifstream { file_path, std::ios::binary };
 | 
					 | 
				
			||||||
		if (!stream.good())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			throw std::runtime_error {
 | 
					 | 
				
			||||||
	    std::format(
 | 
						    std::format(
 | 
				
			||||||
				    "Failed to open ifstream for text loading of file: {}",
 | 
						        "glslc --target-env=vulkan1.4 -std=450core -fshader-stage={} {} -o {}",
 | 
				
			||||||
				    file_path.string()
 | 
						        type == vertex ? "vert" : "frag",
 | 
				
			||||||
				),
 | 
						        glsl_path,
 | 
				
			||||||
			};
 | 
						        spv_path
 | 
				
			||||||
 | 
						    )
 | 
				
			||||||
 | 
						        .c_str()
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto stream = std::ifstream(spv_path, std::ios::binary);
 | 
				
			||||||
 | 
						lt::ensure(
 | 
				
			||||||
 | 
						    stream.is_open(),
 | 
				
			||||||
 | 
						    "Failed to open compiled {} shader at: {}",
 | 
				
			||||||
 | 
						    type == vertex ? "vert" : "frag",
 | 
				
			||||||
 | 
						    spv_path
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stream.seekg(0, std::ios::end);
 | 
				
			||||||
 | 
						const auto size = stream.tellg();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto bytes = std::vector<std::byte>(size);
 | 
				
			||||||
 | 
						stream.seekg(0, std::ios::beg);
 | 
				
			||||||
 | 
						stream.read((char *)bytes.data(), size); // NOLINT
 | 
				
			||||||
 | 
						lt::log::debug("BYTES: {}", bytes.size());
 | 
				
			||||||
 | 
						stream.close();
 | 
				
			||||||
 | 
						std::filesystem::remove(spv_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ShaderAsset::pack(
 | 
				
			||||||
 | 
						    out_path,
 | 
				
			||||||
 | 
						    lt::assets::AssetMetadata {
 | 
				
			||||||
 | 
						        .version = lt::assets::current_version,
 | 
				
			||||||
 | 
						        .type = ShaderAsset::asset_type_identifier,
 | 
				
			||||||
 | 
						    },
 | 
				
			||||||
 | 
						    ShaderAsset::Metadata {
 | 
				
			||||||
 | 
						        .type = type,
 | 
				
			||||||
 | 
						    },
 | 
				
			||||||
 | 
						    std::move(bytes)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto file_size = std::filesystem::file_size(file_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto text_blob = Assets::Blob(file_size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		stream.read((char *)(text_blob.data()), static_cast<long>(file_size)); // NOLINT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const auto metadata = Assets::Asset::Metadata {
 | 
					 | 
				
			||||||
			.type = Assets::Asset::Type::Text,
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const auto text_metadata = Assets::TextAsset::Metadata {
 | 
					 | 
				
			||||||
			.lines = {},
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return Assets::TextAsset::PackageData {
 | 
					 | 
				
			||||||
			.metadata = metadata,
 | 
					 | 
				
			||||||
			.text_metadata = {},
 | 
					 | 
				
			||||||
			.text_blob = std::move(text_blob),
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextLoaderFactory
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	static auto create(std::string_view file_extension) -> std::unique_ptr<TextLoader>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (TextLoader::get_supported_extensions().contains(file_extension))
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return std::make_unique<TextLoader>();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return {};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +0,0 @@
 | 
				
			||||||
add_library_module(asset_manager 
 | 
					 | 
				
			||||||
    asset_manager.cpp
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
target_link_libraries(
 | 
					 | 
				
			||||||
  asset_manager
 | 
					 | 
				
			||||||
  PUBLIC asset_parser
 | 
					 | 
				
			||||||
  PRIVATE logger
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,92 +0,0 @@
 | 
				
			||||||
#include <asset_manager/asset_manager.hpp>
 | 
					 | 
				
			||||||
#include <asset_parser/assets/text.hpp>
 | 
					 | 
				
			||||||
#include <asset_parser/assets/texture.hpp>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
#include <renderer/graphics_context.hpp>
 | 
					 | 
				
			||||||
#include <renderer/shader.hpp>
 | 
					 | 
				
			||||||
#include <renderer/texture.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* static */ auto AssetManager::instance() -> AssetManager &
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static auto instance = AssetManager {};
 | 
					 | 
				
			||||||
	return instance;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void AssetManager::load_shader_impl(
 | 
					 | 
				
			||||||
    const std::string &name,
 | 
					 | 
				
			||||||
    const std::filesystem::path &vertex_path,
 | 
					 | 
				
			||||||
    const std::filesystem::path &pixel_path
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	try
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_trc("Loading shader:");
 | 
					 | 
				
			||||||
		log_trc("\tname       : {}", name);
 | 
					 | 
				
			||||||
		log_trc("\tvertex path: {}", vertex_path.string());
 | 
					 | 
				
			||||||
		log_trc("\tpixel path : {}", pixel_path.string());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_shaders[name] = Ref<Shader>(Shader::create(
 | 
					 | 
				
			||||||
		    get_or_load_text_asset(vertex_path.string()),
 | 
					 | 
				
			||||||
		    get_or_load_text_asset(pixel_path),
 | 
					 | 
				
			||||||
		    GraphicsContext::get_shared_context()
 | 
					 | 
				
			||||||
		));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	catch (const std::exception &exp)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_err("Failed to load shader:");
 | 
					 | 
				
			||||||
		log_err("\tname       : {}", name);
 | 
					 | 
				
			||||||
		log_err("\tvertex path: {}", vertex_path.string());
 | 
					 | 
				
			||||||
		log_err("\tpixel path : {}", pixel_path.string());
 | 
					 | 
				
			||||||
		log_err("\texception  : {}", exp.what());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void AssetManager::load_texture_impl(const std::string &name, const std::filesystem::path &path)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	try
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_trc("Loading texture:");
 | 
					 | 
				
			||||||
		log_trc("\tname: {}", name);
 | 
					 | 
				
			||||||
		log_trc("\tpath: {}", path.string());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_textures[name] = Ref<Texture>(
 | 
					 | 
				
			||||||
		    Texture::create(get_or_load_texture_asset(path), GraphicsContext::get_shared_context())
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	catch (const std::exception &exp)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_err("Failed to load texture:");
 | 
					 | 
				
			||||||
		log_err("\tname     : {}", name);
 | 
					 | 
				
			||||||
		log_err("\tpath     : {}", path.string());
 | 
					 | 
				
			||||||
		log_err("\texception: {}", exp.what());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto AssetManager::get_or_load_text_asset(const std::filesystem::path &path)
 | 
					 | 
				
			||||||
    -> Ref<Assets::TextAsset>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const auto key = std::filesystem::canonical(path).string();
 | 
					 | 
				
			||||||
	if (!m_text_assets.contains(key))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		m_text_assets.emplace(key, create_ref<Assets::TextAsset>(path));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return m_text_assets[key];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto AssetManager::get_or_load_texture_asset(const std::filesystem::path &path)
 | 
					 | 
				
			||||||
    -> Ref<Assets::TextureAsset>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const auto key = std::filesystem::canonical(path).string();
 | 
					 | 
				
			||||||
	if (!m_texture_assets.contains(key))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		m_texture_assets.emplace(key, create_ref<Assets::TextureAsset>(path));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return m_texture_assets[key];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,78 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextAsset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextureAsset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Shader;
 | 
					 | 
				
			||||||
class Texture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Asset is the data on the disk.
 | 
					 | 
				
			||||||
 * Resource is the data on the gpu/cpu
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * eg. TextureAsset is the file on the disk
 | 
					 | 
				
			||||||
 * eg. Texture is the representation of it in the GPU
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
class AssetManager
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	static void load_shader(
 | 
					 | 
				
			||||||
	    const std::string &name,
 | 
					 | 
				
			||||||
	    const std::filesystem::path &vertex_path,
 | 
					 | 
				
			||||||
	    const std::filesystem::path &pixel_path
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		instance().load_shader_impl(name, vertex_path, pixel_path);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static void load_texture(const std::string &name, const std::filesystem::path &path)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		instance().load_texture_impl(name, path);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static auto get_shader(const std::string &name) -> Ref<Shader>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return instance().m_shaders[name];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static auto get_texture(const std::string &name) -> Ref<Texture>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return instance().m_textures[name];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	AssetManager() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static auto instance() -> AssetManager &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void load_shader_impl(
 | 
					 | 
				
			||||||
	    const std::string &name,
 | 
					 | 
				
			||||||
	    const std::filesystem::path &vertex_path,
 | 
					 | 
				
			||||||
	    const std::filesystem::path &pixel_path
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void load_texture_impl(const std::string &name, const std::filesystem::path &path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto get_or_load_text_asset(const std::filesystem::path &path) -> Ref<Assets::TextAsset>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto get_or_load_texture_asset(const std::filesystem::path &path) -> Ref<Assets::TextureAsset>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::unordered_map<std::string, Ref<Assets::TextAsset>> m_text_assets;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::unordered_map<std::string, Ref<Assets::TextureAsset>> m_texture_assets;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::unordered_map<std::string, Ref<Shader>> m_shaders;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::unordered_map<std::string, Ref<Texture>> m_textures;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,11 +0,0 @@
 | 
				
			||||||
add_library_module(asset_parser 
 | 
					 | 
				
			||||||
    parser.cpp
 | 
					 | 
				
			||||||
    assets/texture.cpp
 | 
					 | 
				
			||||||
    assets/text.cpp
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
target_link_libraries(
 | 
					 | 
				
			||||||
    asset_parser
 | 
					 | 
				
			||||||
    PRIVATE LZ4::lz4_static 
 | 
					 | 
				
			||||||
    PRIVATE logger
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,4 @@
 | 
				
			||||||
#include <asset_parser/assets/text.hpp>
 | 
					#include <asset_parser/assets/text.hpp>
 | 
				
			||||||
#include <lz4.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Assets {
 | 
					namespace Assets {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,165 +0,0 @@
 | 
				
			||||||
#include <asset_parser/assets/texture.hpp>
 | 
					 | 
				
			||||||
#include <lz4.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* static */ void TextureAsset::pack(const PackageData &data, const std::filesystem::path &out_path)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const auto &[metadata, texture_metadata, pixels] = data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto stream = std::ofstream { out_path, std::ios::binary | std::ios::trunc };
 | 
					 | 
				
			||||||
	if (!stream.is_open())
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format("Failed to open ofstream for packing texture at: {}", out_path.string())
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	stream.seekp(0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
 | 
					 | 
				
			||||||
	stream.write((char *)¤t_version, sizeof(current_version));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stream.write((char *)&metadata, sizeof(metadata));
 | 
					 | 
				
			||||||
	stream.write((char *)&texture_metadata, sizeof(texture_metadata));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	constexpr auto number_of_blobs = uint32_t { 1 };
 | 
					 | 
				
			||||||
	stream.write((char *)&number_of_blobs, sizeof(number_of_blobs));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto pixels_metadata = BlobMetadata {
 | 
					 | 
				
			||||||
		.tag = BlobMetadata::Tag::color,
 | 
					 | 
				
			||||||
		.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
 | 
					 | 
				
			||||||
		.compression_type = CompressionType::None,
 | 
					 | 
				
			||||||
		.compressed_size = pixels.size(),
 | 
					 | 
				
			||||||
		.uncompressed_size = pixels.size(),
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stream.write((char *)&pixels_metadata, sizeof(pixels_metadata));
 | 
					 | 
				
			||||||
	stream.write((char *)&pixels[0], static_cast<long>(pixels.size()));
 | 
					 | 
				
			||||||
	// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TextureAsset::TextureAsset(const std::filesystem::path &path)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_stream = std::ifstream { path, std::ios::binary };
 | 
					 | 
				
			||||||
	if (!m_stream.is_open())
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format("Failed to open ifstream for loading texture asset at: {}", path.string())
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
 | 
					 | 
				
			||||||
	m_stream.read((char *)&version, sizeof(version));
 | 
					 | 
				
			||||||
	m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
 | 
					 | 
				
			||||||
	m_stream.read((char *)&m_metadata, sizeof(m_metadata));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto num_blobs = uint32_t {};
 | 
					 | 
				
			||||||
	m_stream.read((char *)&num_blobs, sizeof(num_blobs));
 | 
					 | 
				
			||||||
	if (num_blobs != 1)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format("Failed to load texture asset: invalid number of blobs: {}", num_blobs)
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	m_stream.read((char *)&m_pixel_blob_metadata, sizeof(m_pixel_blob_metadata));
 | 
					 | 
				
			||||||
	if (m_pixel_blob_metadata.tag != BlobMetadata::Tag::color)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format(
 | 
					 | 
				
			||||||
			    "Failed to load texture asset: invalid blob tag, expected {}, got {}",
 | 
					 | 
				
			||||||
			    std::to_underlying(BlobMetadata::Tag::color),
 | 
					 | 
				
			||||||
			    std::to_underlying(m_pixel_blob_metadata.tag)
 | 
					 | 
				
			||||||
			),
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void TextureAsset::unpack_blob(
 | 
					 | 
				
			||||||
    BlobMetadata::Tag tag,
 | 
					 | 
				
			||||||
    std::byte *destination,
 | 
					 | 
				
			||||||
    size_t destination_capacity
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (tag != BlobMetadata::Tag::color)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format("Invalid tag for unpack_blob of TextureAsset: {}", std::to_underlying(tag))
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	m_stream.seekg(static_cast<long>(m_pixel_blob_metadata.offset));
 | 
					 | 
				
			||||||
	switch (m_pixel_blob_metadata.compression_type)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	case Assets::CompressionType::None:
 | 
					 | 
				
			||||||
		if (m_pixel_blob_metadata.uncompressed_size != m_pixel_blob_metadata.compressed_size)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			throw std::runtime_error(
 | 
					 | 
				
			||||||
			    "Failed to unpack blob from TextureAsset: "
 | 
					 | 
				
			||||||
			    "compressed/uncompressed size mismatch for no compression "
 | 
					 | 
				
			||||||
			    "type"
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (m_pixel_blob_metadata.uncompressed_size > destination_capacity)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			throw std::runtime_error(
 | 
					 | 
				
			||||||
			    "Failed to unpack blob from TextureAsset: "
 | 
					 | 
				
			||||||
			    "uncompressed_size > destination_capacity, unpacking "
 | 
					 | 
				
			||||||
			    "would result in segfault"
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!m_stream.is_open())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			throw std::runtime_error(
 | 
					 | 
				
			||||||
			    "Failed to unpack blob from TextureAsset: ifstream is "
 | 
					 | 
				
			||||||
			    "closed"
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_stream.read(
 | 
					 | 
				
			||||||
		    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
 | 
					 | 
				
			||||||
		    (char *)destination,
 | 
					 | 
				
			||||||
		    static_cast<long>(m_pixel_blob_metadata.uncompressed_size)
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		throw std::runtime_error(
 | 
					 | 
				
			||||||
		    std::format(
 | 
					 | 
				
			||||||
		        "Failed to unpack blob from TextureAsset: unsupported "
 | 
					 | 
				
			||||||
		        "compression type: {}",
 | 
					 | 
				
			||||||
		        std::to_underlying(m_pixel_blob_metadata.compression_type)
 | 
					 | 
				
			||||||
		    )
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[nodiscard]] auto TextureAsset::get_asset_metadata() const -> const Asset::Metadata &
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return m_asset_metadata;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[nodiscard]] auto TextureAsset::get_metadata() const -> const Metadata &
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return m_metadata;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[nodiscard]] auto TextureAsset::get_blob_metadata(BlobMetadata::Tag tag) const
 | 
					 | 
				
			||||||
    -> const BlobMetadata &
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (tag != BlobMetadata::Tag::color)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error { std::format(
 | 
					 | 
				
			||||||
			"Invalid tag for get_blob_metadata of TextureAsset: {}",
 | 
					 | 
				
			||||||
			std::to_underlying(tag)
 | 
					 | 
				
			||||||
		) };
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return m_pixel_blob_metadata;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,62 +0,0 @@
 | 
				
			||||||
#include <asset_parser/parser.hpp>
 | 
					 | 
				
			||||||
#include <format>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <utility>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// void Asset::unpack(std::byte *destination)
 | 
					 | 
				
			||||||
// {
 | 
					 | 
				
			||||||
// 	if (!m_stream.is_open())
 | 
					 | 
				
			||||||
// 	{
 | 
					 | 
				
			||||||
// 		throw std::logic_error {
 | 
					 | 
				
			||||||
// 			"Failed to unpack asset: "
 | 
					 | 
				
			||||||
// 			"ifstream is closed",
 | 
					 | 
				
			||||||
// 		};
 | 
					 | 
				
			||||||
// 	}
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// 	switch (m_metadata.blob_compression_type)
 | 
					 | 
				
			||||||
// 	{
 | 
					 | 
				
			||||||
// 	case CompressionType::None:
 | 
					 | 
				
			||||||
// 		if (m_metadata.packed_size != m_metadata.unpacked_size)
 | 
					 | 
				
			||||||
// 		{
 | 
					 | 
				
			||||||
// 			throw std::logic_error {
 | 
					 | 
				
			||||||
// 				"Failed to unpack asset: "
 | 
					 | 
				
			||||||
// 				"compression type set to none but packed/unpacked sizes differ",
 | 
					 | 
				
			||||||
// 			};
 | 
					 | 
				
			||||||
// 		}
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// 		m_stream.read(
 | 
					 | 
				
			||||||
// 		    std::bit_cast<char *>(destination),
 | 
					 | 
				
			||||||
// 		    static_cast<long>(m_metadata.packed_size)
 | 
					 | 
				
			||||||
// 		);
 | 
					 | 
				
			||||||
// 		m_stream.close();
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// 	case CompressionType::LZ4:
 | 
					 | 
				
			||||||
// 		m_stream.close();
 | 
					 | 
				
			||||||
// 		throw std::logic_error {
 | 
					 | 
				
			||||||
// 			"Failed to unpack asset: "
 | 
					 | 
				
			||||||
// 			"LZ4 compression is not implemented yet",
 | 
					 | 
				
			||||||
// 		};
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// 	case CompressionType::LZ4HC:
 | 
					 | 
				
			||||||
// 		m_stream.close();
 | 
					 | 
				
			||||||
// 		throw std::logic_error {
 | 
					 | 
				
			||||||
// 			"Failed to unpack asset: "
 | 
					 | 
				
			||||||
// 			"LZ4HC compression is not implemented yet",
 | 
					 | 
				
			||||||
// 		};
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// 	default:
 | 
					 | 
				
			||||||
// 		m_stream.close();
 | 
					 | 
				
			||||||
// 		throw std::logic_error {
 | 
					 | 
				
			||||||
// 			std::format(
 | 
					 | 
				
			||||||
// 			    "Failed to unpack asset: "
 | 
					 | 
				
			||||||
// 			    "Compression type was not recognized: {}",
 | 
					 | 
				
			||||||
// 			    std::to_underlying(m_metadata.blob_compression_type)
 | 
					 | 
				
			||||||
// 			),
 | 
					 | 
				
			||||||
// 		};
 | 
					 | 
				
			||||||
// 	}
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,58 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <asset_parser/compressors/compressors.hpp>
 | 
					 | 
				
			||||||
#include <asset_parser/parser.hpp>
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextAsset: public Asset
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	struct Metadata
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		uint32_t lines {};
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** Data required to pack a text asset */
 | 
					 | 
				
			||||||
	struct PackageData
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Asset::Metadata metadata;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Metadata text_metadata;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Blob text_blob;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static void pack(const PackageData &data, const std::filesystem::path &out_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	TextAsset(const std::filesystem::path &path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void unpack_blob(
 | 
					 | 
				
			||||||
	    BlobMetadata::Tag tag,
 | 
					 | 
				
			||||||
	    std::byte *destination,
 | 
					 | 
				
			||||||
	    size_t destination_capacity
 | 
					 | 
				
			||||||
	) const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_metadata() const -> const Metadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	uint32_t version {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Asset::Metadata m_asset_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Metadata m_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BlobMetadata m_text_blob_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutable std::ifstream m_stream;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,64 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <asset_parser/compressors/compressors.hpp>
 | 
					 | 
				
			||||||
#include <asset_parser/parser.hpp>
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextureAsset: public Asset
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	enum class Format : uint32_t // NOLINT(performance-enum-size)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		None = 0,
 | 
					 | 
				
			||||||
		RGBA8,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct Metadata
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Format format;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		uint32_t num_components;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::array<uint32_t, 3> pixel_size;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** Data required to pack a texture asset */
 | 
					 | 
				
			||||||
	struct PackageData
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Asset::Metadata metadata;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Metadata texture_metadata;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Blob pixels;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static void pack(const PackageData &data, const std::filesystem::path &out_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	TextureAsset(const std::filesystem::path &path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void unpack_blob(BlobMetadata::Tag tag, std::byte *destination, size_t destination_capacity);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_metadata() const -> const Metadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	uint32_t version {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Asset::Metadata m_asset_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Metadata m_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BlobMetadata m_pixel_blob_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::ifstream m_stream;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum class CompressionType : uint32_t // NOLINT(performance-enum-size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	None,
 | 
					 | 
				
			||||||
	LZ4,
 | 
					 | 
				
			||||||
	LZ4HC,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,68 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <asset_parser/compressors/compressors.hpp>
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
#include <utility>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
constexpr auto current_version = uint32_t { 1 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct BlobMetadata
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	enum class Tag : uint8_t
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		text,
 | 
					 | 
				
			||||||
		color,
 | 
					 | 
				
			||||||
		depth,
 | 
					 | 
				
			||||||
		vertices,
 | 
					 | 
				
			||||||
		indices,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Tag tag;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	size_t offset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	CompressionType compression_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	size_t compressed_size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	size_t uncompressed_size;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using Blob = std::vector<std::byte>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Asset
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	enum class Type : uint32_t // NOLINT(performance-enum-size)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		None,
 | 
					 | 
				
			||||||
		Texture,
 | 
					 | 
				
			||||||
		Text,
 | 
					 | 
				
			||||||
		Mesh,
 | 
					 | 
				
			||||||
		Material,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct Metadata
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Type type;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Asset() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** Directly unpacks from disk to the destination.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @note The destination MUST have at least blob_metadata.unpacked_size bytes available for
 | 
					 | 
				
			||||||
	 * writing, otherwise segfault could occur!
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	void unpack_blob(BlobMetadata::Tag blob_tag, std::byte *destination);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
							
								
								
									
										5
									
								
								modules/assets/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								modules/assets/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					add_library_module(assets shader.cpp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_link_libraries(assets PUBLIC logger lt_debug)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_test_module(assets shader.test.cpp)
 | 
				
			||||||
							
								
								
									
										148
									
								
								modules/assets/private/shader.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								modules/assets/private/shader.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,148 @@
 | 
				
			||||||
 | 
					#include <assets/shader.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::assets {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr auto total_metadata_size =         //
 | 
				
			||||||
 | 
					    sizeof(AssetMetadata::type)              //
 | 
				
			||||||
 | 
					    + sizeof(AssetMetadata::version)         //
 | 
				
			||||||
 | 
					    + sizeof(ShaderAsset::Metadata::type)    //
 | 
				
			||||||
 | 
					    + sizeof(BlobMetadata::tag)              //
 | 
				
			||||||
 | 
					    + sizeof(BlobMetadata::offset)           //
 | 
				
			||||||
 | 
					    + sizeof(BlobMetadata::compression_type) //
 | 
				
			||||||
 | 
					    + sizeof(BlobMetadata::compressed_size)  //
 | 
				
			||||||
 | 
					    + sizeof(BlobMetadata::uncompressed_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ensure(m_stream.is_open(), "Failed to open shader asset at: {}", path.string());
 | 
				
			||||||
 | 
						const auto read = [this](auto &field) {
 | 
				
			||||||
 | 
							m_stream.read(std::bit_cast<char *>(&field), sizeof(field));
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m_stream.seekg(0, std::ifstream::end);
 | 
				
			||||||
 | 
						const auto file_size = static_cast<size_t>(m_stream.tellg());
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    file_size > total_metadata_size,
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, file smaller than metadata: {} < {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    total_metadata_size,
 | 
				
			||||||
 | 
						    file_size
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m_stream.seekg(0, std::ifstream::beg);
 | 
				
			||||||
 | 
						read(m_asset_metadata.type);
 | 
				
			||||||
 | 
						read(m_asset_metadata.version);
 | 
				
			||||||
 | 
						read(m_metadata.type);
 | 
				
			||||||
 | 
						read(m_code_blob_metadata.tag);
 | 
				
			||||||
 | 
						read(m_code_blob_metadata.offset);
 | 
				
			||||||
 | 
						read(m_code_blob_metadata.compression_type);
 | 
				
			||||||
 | 
						read(m_code_blob_metadata.compressed_size);
 | 
				
			||||||
 | 
						read(m_code_blob_metadata.uncompressed_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    m_asset_metadata.type == asset_type_identifier,
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, incorrect asset type: {} != {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    m_asset_metadata.type,
 | 
				
			||||||
 | 
						    asset_type_identifier
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    m_asset_metadata.version == current_version,
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, version mismatch: {} != {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    m_asset_metadata.version,
 | 
				
			||||||
 | 
						    current_version
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    std::to_underlying(m_metadata.type) <= std::to_underlying(Type::compute),
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, invalid shader type: {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    std::to_underlying(m_metadata.type)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    m_code_blob_metadata.tag == std::to_underlying(BlobTag::code),
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, invalid blob tag: {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    m_code_blob_metadata.tag
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    m_code_blob_metadata.offset + m_code_blob_metadata.compressed_size <= file_size,
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, file smaller than blob: {} > {} + {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    file_size,
 | 
				
			||||||
 | 
						    m_code_blob_metadata.offset,
 | 
				
			||||||
 | 
						    m_code_blob_metadata.compressed_size
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* static */ void ShaderAsset::pack(
 | 
				
			||||||
 | 
					    const std::filesystem::path &destination,
 | 
				
			||||||
 | 
					    AssetMetadata asset_metadata,
 | 
				
			||||||
 | 
					    Metadata metadata,
 | 
				
			||||||
 | 
					    Blob code_blob
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						auto stream = std::ofstream {
 | 
				
			||||||
 | 
							destination,
 | 
				
			||||||
 | 
							std::ios::binary | std::ios::trunc,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const auto code_blob_metadata = BlobMetadata {
 | 
				
			||||||
 | 
							.tag = std::to_underlying(BlobTag::code),
 | 
				
			||||||
 | 
							.offset = total_metadata_size,
 | 
				
			||||||
 | 
							.compression_type = CompressionType::none,
 | 
				
			||||||
 | 
							.compressed_size = code_blob.size(),
 | 
				
			||||||
 | 
							.uncompressed_size = code_blob.size(),
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(stream.is_open(), "Failed to pack shader asset to {}", destination.string());
 | 
				
			||||||
 | 
						const auto write = [&stream](auto &field) {
 | 
				
			||||||
 | 
							stream.write(std::bit_cast<char *>(&field), sizeof(field));
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						write(asset_metadata.type);
 | 
				
			||||||
 | 
						write(asset_metadata.version);
 | 
				
			||||||
 | 
						write(metadata.type);
 | 
				
			||||||
 | 
						write(code_blob_metadata.tag);
 | 
				
			||||||
 | 
						write(code_blob_metadata.offset);
 | 
				
			||||||
 | 
						write(code_blob_metadata.compression_type);
 | 
				
			||||||
 | 
						write(code_blob_metadata.compressed_size);
 | 
				
			||||||
 | 
						write(code_blob_metadata.uncompressed_size);
 | 
				
			||||||
 | 
						stream.write(std::bit_cast<char *>(code_blob.data()), static_cast<long long>(code_blob.size()));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ShaderAsset::unpack_to(BlobTag tag, std::span<std::byte> destination) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ensure(tag == BlobTag::code, "Invalid blob tag for shader asset: {}", std::to_underlying(tag));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    destination.size() >= m_code_blob_metadata.uncompressed_size,
 | 
				
			||||||
 | 
						    "Failed to unpack shader blob {} to destination ({}) of size {} since it's smaller "
 | 
				
			||||||
 | 
						    "than the blobl's uncompressed size: {}",
 | 
				
			||||||
 | 
						    std::to_underlying(tag),
 | 
				
			||||||
 | 
						    std::bit_cast<size_t>(destination.data()),
 | 
				
			||||||
 | 
						    destination.size(),
 | 
				
			||||||
 | 
						    m_code_blob_metadata.uncompressed_size
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m_stream.seekg(static_cast<long long>(m_code_blob_metadata.offset));
 | 
				
			||||||
 | 
						m_stream.read(
 | 
				
			||||||
 | 
						    std::bit_cast<char *>(destination.data()),
 | 
				
			||||||
 | 
						    static_cast<long long>(m_code_blob_metadata.uncompressed_size)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[nodiscard]] auto ShaderAsset::unpack(BlobTag tag) const -> Blob
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ensure(tag == BlobTag::code, "Invalid blob tag for shader asset: {}", std::to_underlying(tag));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto blob = Blob(m_code_blob_metadata.uncompressed_size);
 | 
				
			||||||
 | 
						unpack_to(tag, blob);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return blob;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::assets
 | 
				
			||||||
							
								
								
									
										94
									
								
								modules/assets/private/shader.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								modules/assets/private/shader.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,94 @@
 | 
				
			||||||
 | 
					#include <assets/shader.hpp>
 | 
				
			||||||
 | 
					#include <ranges>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ::lt::assets::AssetMetadata;
 | 
				
			||||||
 | 
					using ::lt::assets::BlobMetadata;
 | 
				
			||||||
 | 
					using ::lt::assets::ShaderAsset;
 | 
				
			||||||
 | 
					using ::lt::test::Case;
 | 
				
			||||||
 | 
					using ::lt::test::expect_eq;
 | 
				
			||||||
 | 
					using ::lt::test::expect_throw;
 | 
				
			||||||
 | 
					using ::lt::test::expect_true;
 | 
				
			||||||
 | 
					using ::lt::test::Suite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const auto test_data_path = std::filesystem::path { "./data/test_assets" };
 | 
				
			||||||
 | 
					const auto tmp_path = std::filesystem::path { "/tmp/lt_assets_tests/" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite raii = "shader_raii"_suite = [] {
 | 
				
			||||||
 | 
						std::filesystem::current_path(test_data_path);
 | 
				
			||||||
 | 
						std::filesystem::create_directories(tmp_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "happy path won't throw" } = [] {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "many won't freeze/throw" } = [] {
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "unhappy path throws" } = [] {
 | 
				
			||||||
 | 
							expect_throw([] { ShaderAsset { "random_path" }; });
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOLINTNEXTLINE(cppcoreguidelines-interfaces-global-init)
 | 
				
			||||||
 | 
					Suite packing = "shader_pack"_suite = [] {
 | 
				
			||||||
 | 
						Case { "" } = [] {
 | 
				
			||||||
 | 
							const auto out_path = tmp_path / "shader_packing";
 | 
				
			||||||
 | 
							auto dummy_blob = lt::assets::Blob {};
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 255))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								dummy_blob.emplace_back(static_cast<std::byte>(idx));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const auto expected_size =                    //
 | 
				
			||||||
 | 
							    sizeof(AssetMetadata::type)               //
 | 
				
			||||||
 | 
							    + sizeof(AssetMetadata::version)          //
 | 
				
			||||||
 | 
							    + sizeof(ShaderAsset::Metadata::type)     //
 | 
				
			||||||
 | 
							    + sizeof(BlobMetadata::tag)               //
 | 
				
			||||||
 | 
							    + sizeof(BlobMetadata::offset)            //
 | 
				
			||||||
 | 
							    + sizeof(BlobMetadata::compression_type)  //
 | 
				
			||||||
 | 
							    + sizeof(BlobMetadata::compressed_size)   //
 | 
				
			||||||
 | 
							    + sizeof(BlobMetadata::uncompressed_size) //
 | 
				
			||||||
 | 
							    + dummy_blob.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ShaderAsset::pack(
 | 
				
			||||||
 | 
							    out_path,
 | 
				
			||||||
 | 
							    lt::assets::AssetMetadata {
 | 
				
			||||||
 | 
							        .version = lt::assets::current_version,
 | 
				
			||||||
 | 
							        .type = ShaderAsset::asset_type_identifier,
 | 
				
			||||||
 | 
							    },
 | 
				
			||||||
 | 
							    ShaderAsset::Metadata {
 | 
				
			||||||
 | 
							        .type = ShaderAsset::Type::vertex,
 | 
				
			||||||
 | 
							    },
 | 
				
			||||||
 | 
							    std::move(dummy_blob)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto stream = std::ifstream {
 | 
				
			||||||
 | 
								out_path,
 | 
				
			||||||
 | 
								std::ios::binary,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							expect_true(stream.is_open());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							stream.seekg(0, std::ios::end);
 | 
				
			||||||
 | 
							const auto file_size = static_cast<size_t>(stream.tellg());
 | 
				
			||||||
 | 
							expect_eq(file_size, expected_size);
 | 
				
			||||||
 | 
							stream.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto shader_asset = ShaderAsset { out_path };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const auto &asset_metadata = shader_asset.get_asset_metadata();
 | 
				
			||||||
 | 
							expect_eq(asset_metadata.type, ShaderAsset::asset_type_identifier);
 | 
				
			||||||
 | 
							expect_eq(asset_metadata.version, lt::assets::current_version);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const auto &metadata = shader_asset.get_metadata();
 | 
				
			||||||
 | 
							expect_eq(metadata.type, ShaderAsset::Type::vertex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto blob = shader_asset.unpack(ShaderAsset::BlobTag::code);
 | 
				
			||||||
 | 
							expect_eq(blob.size(), 255);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 255))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_eq(blob[idx], static_cast<std::byte>(idx));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										3
									
								
								modules/assets/public/compressors/lz4.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								modules/assets/public/compressors/lz4.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TO BE DOOO
 | 
				
			||||||
							
								
								
									
										42
									
								
								modules/assets/public/metadata.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								modules/assets/public/metadata.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::assets {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Type_T = std::array<const char, 16>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Tag_T = uint8_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Version = uint8_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Blob = std::vector<std::byte>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr auto current_version = Version { 1u };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class CompressionType : uint8_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						none,
 | 
				
			||||||
 | 
						lz4,
 | 
				
			||||||
 | 
						lz4_hc,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AssetMetadata
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Version version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Type_T type;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BlobMetadata
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Tag_T tag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CompressionType compression_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t compressed_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t uncompressed_size;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::assets
 | 
				
			||||||
							
								
								
									
										74
									
								
								modules/assets/public/shader.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								modules/assets/public/shader.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,74 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <assets/metadata.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::assets {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ShaderAsset
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static constexpr auto asset_type_identifier = Type_T { "SHADER_________" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum class BlobTag : Tag_T
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							code,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum class Type : uint8_t
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							vertex,
 | 
				
			||||||
 | 
							fragment,
 | 
				
			||||||
 | 
							geometry,
 | 
				
			||||||
 | 
							compute,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct Metadata
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Type type;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void pack(
 | 
				
			||||||
 | 
						    const std::filesystem::path &destination,
 | 
				
			||||||
 | 
						    AssetMetadata asset_metadata,
 | 
				
			||||||
 | 
						    Metadata metadata,
 | 
				
			||||||
 | 
						    Blob code_blob
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ShaderAsset(const std::filesystem::path &path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void unpack_to(BlobTag tag, std::span<std::byte> destination) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto unpack(BlobTag tag) const -> Blob;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_asset_metadata() const -> const AssetMetadata &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_asset_metadata;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_metadata() const -> const Metadata &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_metadata;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_blob_metadata(BlobTag tag) const -> const BlobMetadata &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ensure(
 | 
				
			||||||
 | 
							    tag == BlobTag::code,
 | 
				
			||||||
 | 
							    "Invalid blob tag for shader asset: {}",
 | 
				
			||||||
 | 
							    std::to_underlying(tag)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return m_code_blob_metadata;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						AssetMetadata m_asset_metadata {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Metadata m_metadata {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BlobMetadata m_code_blob_metadata {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutable std::ifstream m_stream;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::assets
 | 
				
			||||||
| 
						 | 
					@ -1,2 +0,0 @@
 | 
				
			||||||
add_library_module(base)
 | 
					 | 
				
			||||||
target_precompile_headers(base INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/private/pch.hpp)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,36 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <base/base.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* windows */
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
	#define NOMINMAX
 | 
					 | 
				
			||||||
	#include <Windows.h>
 | 
					 | 
				
			||||||
	#undef NOMINMAX
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Stdlib */
 | 
					 | 
				
			||||||
#include <algorithm>
 | 
					 | 
				
			||||||
#include <array>
 | 
					 | 
				
			||||||
#include <atomic>
 | 
					 | 
				
			||||||
#include <bitset>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
#include <list>
 | 
					 | 
				
			||||||
#include <map>
 | 
					 | 
				
			||||||
#include <math.h>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <set>
 | 
					 | 
				
			||||||
#include <span>
 | 
					 | 
				
			||||||
#include <sstream>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <string_view>
 | 
					 | 
				
			||||||
#include <thread>
 | 
					 | 
				
			||||||
#include <time.h>
 | 
					 | 
				
			||||||
#include <tuple>
 | 
					 | 
				
			||||||
#include <unordered_map>
 | 
					 | 
				
			||||||
#include <unordered_set>
 | 
					 | 
				
			||||||
#include <utility>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,91 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Ref (Ref)
 | 
					 | 
				
			||||||
template<typename t>
 | 
					 | 
				
			||||||
using Ref = std::shared_ptr<t>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<typename t, typename... Args>
 | 
					 | 
				
			||||||
constexpr Ref<t> create_ref(Args &&...args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return std::make_shared<t>(std::forward<Args>(args)...);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<typename t>
 | 
					 | 
				
			||||||
constexpr Ref<t> make_ref(t *rawPointer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return std::shared_ptr<t>(rawPointer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Scope (std::unique_ptr)
 | 
					 | 
				
			||||||
template<typename t>
 | 
					 | 
				
			||||||
using Scope = std::unique_ptr<t>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<typename t, typename... Args>
 | 
					 | 
				
			||||||
constexpr std::unique_ptr<t> create_scope(Args &&...args)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return std::make_unique<t>(std::forward<Args>(args)...);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<typename t>
 | 
					 | 
				
			||||||
constexpr std::unique_ptr<t> make_scope(t *rawPointer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return std::unique_ptr<t>(rawPointer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define lt_win(x) // windows
 | 
					 | 
				
			||||||
#define lt_lin(x) // linux
 | 
					 | 
				
			||||||
#define lt_mac(x) // mac
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum class Platform : uint8_t
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	windows,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** Named like so because "linux" is a built-in identifier. */
 | 
					 | 
				
			||||||
	gnu,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mac,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace constants {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(LIGHT_PLATFORM_WINDOWS)
 | 
					 | 
				
			||||||
	#define lt_win(x)
 | 
					 | 
				
			||||||
constexpr auto platform = Platform::windows;
 | 
					 | 
				
			||||||
constexpr auto platform_name = "windows";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	#undef LIGHT_PLATFORM_WINDOWS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#elif defined(LIGHT_PLATFORM_LINUX)
 | 
					 | 
				
			||||||
	#define lt_lin(x) x
 | 
					 | 
				
			||||||
constexpr auto platform = Platform::gnu;
 | 
					 | 
				
			||||||
constexpr auto platform_name = "linux";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#elif defined(LIGHT_PLATFORM_MAC)
 | 
					 | 
				
			||||||
	#define lt_mac(x) x
 | 
					 | 
				
			||||||
constexpr auto platform = Platform::mac;
 | 
					 | 
				
			||||||
constexpr auto platform_name = "mac";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	#error "Unsupported platform: Unknown"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace constants
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* bit-wise */
 | 
					 | 
				
			||||||
constexpr auto bit(auto x)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 1 << x;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* token */
 | 
					 | 
				
			||||||
#define lt_pair_token_value_to_name(token) { token, #token }
 | 
					 | 
				
			||||||
#define lt_pair_token_name_to_value(token) { #token, token }
 | 
					 | 
				
			||||||
#define lt_token_name(token)               #token
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								modules/bitwise/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								modules/bitwise/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					add_library_module(bitwise)
 | 
				
			||||||
							
								
								
									
										13
									
								
								modules/bitwise/public/operations.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								modules/bitwise/public/operations.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::bitwise {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* bit-wise */
 | 
				
			||||||
 | 
					constexpr auto bit(uint32_t x) -> uint32_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 1u << x;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::bitwise
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,3 @@
 | 
				
			||||||
add_library_module(camera camera.cpp scene.cpp)
 | 
					add_library_module(camera)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_link_libraries(camera PUBLIC math)
 | 
					target_link_libraries(camera INTERFACE math)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +0,0 @@
 | 
				
			||||||
#include <camera/camera.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,83 +0,0 @@
 | 
				
			||||||
#include <camera/scene.hpp>
 | 
					 | 
				
			||||||
#include <math/algebra.hpp>
 | 
					 | 
				
			||||||
#include <math/trig.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SceneCamera::SceneCamera()
 | 
					 | 
				
			||||||
    : m_orthographic_specification { .size = 1000.0f, .near_plane = -1.0f, .far_plane = 10000.0f }
 | 
					 | 
				
			||||||
    , m_perspective_specification { .vertical_fov = math::radians(45.0f),
 | 
					 | 
				
			||||||
	                                .near_plane = 0.01f,
 | 
					 | 
				
			||||||
	                                .far_plane = 10000.0f }
 | 
					 | 
				
			||||||
    , m_aspect_ratio(16.0f / 9.0f)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	calculate_projection();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneCamera::set_viewport_size(unsigned int width, unsigned int height)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_aspect_ratio = static_cast<float>(width) / static_cast<float>(height);
 | 
					 | 
				
			||||||
	calculate_projection();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneCamera::set_projection_type(ProjectionType projection_type)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_projection_type = projection_type;
 | 
					 | 
				
			||||||
	calculate_projection();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneCamera::set_orthographic_size(float size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_orthographic_specification.size = size;
 | 
					 | 
				
			||||||
	calculate_projection();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneCamera::set_orthographic_far_plane(float far_plane)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_orthographic_specification.far_plane = far_plane;
 | 
					 | 
				
			||||||
	calculate_projection();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneCamera::set_orthographic_near_plane(float near_plane)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_orthographic_specification.near_plane = near_plane;
 | 
					 | 
				
			||||||
	calculate_projection();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneCamera::set_perspective_vertical_fov(float vertical_fov)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_perspective_specification.vertical_fov = vertical_fov;
 | 
					 | 
				
			||||||
	calculate_projection();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneCamera::set_perspective_far_plane(float far_plane)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_perspective_specification.far_plane = far_plane;
 | 
					 | 
				
			||||||
	calculate_projection();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneCamera::set_perspective_near_plane(float near_plane)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_perspective_specification.near_plane = near_plane;
 | 
					 | 
				
			||||||
	calculate_projection();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneCamera::calculate_projection()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	// TODO(Light): implement ortho perspective
 | 
					 | 
				
			||||||
	if (m_projection_type == ProjectionType::Orthographic)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// throw std::runtime_error { "ortho perspective not supported yet" };
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// defaults to perspective for now...
 | 
					 | 
				
			||||||
	m_projection = math::perspective(
 | 
					 | 
				
			||||||
	    m_perspective_specification.vertical_fov,
 | 
					 | 
				
			||||||
	    m_aspect_ratio,
 | 
					 | 
				
			||||||
	    m_perspective_specification.near_plane,
 | 
					 | 
				
			||||||
	    m_perspective_specification.far_plane
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,35 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <math/mat4.hpp>
 | 
					 | 
				
			||||||
#include <math/vec4.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Camera
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	Camera() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_projection() const -> const math::mat4 &
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_projection;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_background_color() const -> const math::vec4 &
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_background_color;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void set_background_color(const math::vec4 &color)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		m_background_color = color;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
protected:
 | 
					 | 
				
			||||||
	math::mat4 m_projection;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	math::vec4 m_background_color = math::vec4(1.0f, 0.0f, 0.0f, 1.0f);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,29 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <camera/scene.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct CameraComponent
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	CameraComponent() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	CameraComponent(const CameraComponent &) = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	CameraComponent(SceneCamera _camera, bool _isPrimary = false)
 | 
					 | 
				
			||||||
	    : camera(_camera)
 | 
					 | 
				
			||||||
	    , isPrimary(_isPrimary)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	operator SceneCamera() const
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return camera;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SceneCamera camera;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool isPrimary {};
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
							
								
								
									
										22
									
								
								modules/camera/public/components.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								modules/camera/public/components.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <math/mat4.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::camera::components {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct PerspectiveCamera
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						float vertical_fov {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float near_plane {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float far_plane {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						float aspect_ratio {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						math::vec4 background_color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool is_primary {};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::camera::components
 | 
				
			||||||
| 
						 | 
					@ -1,100 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <camera/camera.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class SceneCamera: public Camera
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	enum class ProjectionType
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Orthographic = 0,
 | 
					 | 
				
			||||||
		Perspetcive = 1
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct OrthographicSpecification
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		float size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		float near_plane;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		float far_plane;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct PerspectiveSpecification
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		float vertical_fov;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		float near_plane;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		float far_plane;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SceneCamera();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void set_viewport_size(unsigned int width, unsigned int height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void set_projection_type(ProjectionType projection_type);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void set_orthographic_size(float size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void set_orthographic_far_plane(float far_plane);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void set_orthographic_near_plane(float near_plane);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void set_perspective_vertical_fov(float vertical_fov);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void set_perspective_far_plane(float far_plane);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void set_perspective_near_plane(float near_plane);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_orthographic_size() const -> float
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_orthographic_specification.size;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_orthographic_far_plane() const -> float
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_orthographic_specification.far_plane;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_orthographic_near_plane() const -> float
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_orthographic_specification.near_plane;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_perspective_vertical_fov() const -> float
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_perspective_specification.vertical_fov;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_perspective_far_plane() const -> float
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_perspective_specification.far_plane;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_perspective_near_plane() const -> float
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_perspective_specification.near_plane;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_projection_type() const -> ProjectionType
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_projection_type;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	OrthographicSpecification m_orthographic_specification;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	PerspectiveSpecification m_perspective_specification;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	float m_aspect_ratio;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ProjectionType m_projection_type { ProjectionType::Orthographic };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void calculate_projection();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
add_library_module(lt_debug instrumentor.cpp)
 | 
					add_library_module(lt_debug instrumentor.cpp)
 | 
				
			||||||
target_link_libraries(lt_debug PUBLIC logger)
 | 
					target_link_libraries(lt_debug PUBLIC logger)
 | 
				
			||||||
target_precompile_headers(lt_debug PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/private/pch.hpp)
 | 
					target_precompile_headers(lt_debug PUBLIC
 | 
				
			||||||
 | 
					                          ${CMAKE_CURRENT_SOURCE_DIR}/private/pch.hpp)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ void Instrumentor::end_session_impl()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (m_current_session_count == 0u)
 | 
						if (m_current_session_count == 0u)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		log_wrn("0 profiling for the ended session");
 | 
							log::warn("0 profiling for the ended session");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_current_session_count = 0u;
 | 
						m_current_session_count = 0u;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <format>
 | 
					#include <format>
 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
#include <source_location>
 | 
					#include <source_location>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt {
 | 
					namespace lt {
 | 
				
			||||||
| 
						 | 
					@ -10,7 +9,7 @@ template<typename Expression_T, typename... Args_T>
 | 
				
			||||||
struct ensure
 | 
					struct ensure
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ensure(
 | 
						ensure(
 | 
				
			||||||
	    Expression_T expression,
 | 
						    const Expression_T &expression,
 | 
				
			||||||
	    std::format_string<Args_T...> fmt,
 | 
						    std::format_string<Args_T...> fmt,
 | 
				
			||||||
	    Args_T &&...args,
 | 
						    Args_T &&...args,
 | 
				
			||||||
	    const std::source_location &location = std::source_location::current()
 | 
						    const std::source_location &location = std::source_location::current()
 | 
				
			||||||
| 
						 | 
					@ -28,7 +27,6 @@ struct ensure
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
template<typename Expression_T, typename... Args_T>
 | 
					template<typename Expression_T, typename... Args_T>
 | 
				
			||||||
ensure(Expression_T, std::format_string<Args_T...>, Args_T &&...)
 | 
					ensure(Expression_T, std::format_string<Args_T...>, Args_T &&...)
 | 
				
			||||||
    -> ensure<Expression_T, Args_T...>;
 | 
					    -> ensure<Expression_T, Args_T...>;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
add_library_module(ecs entity.cpp scene.cpp uuid.cpp )
 | 
					add_library_module(ecs sparse_set.cpp)
 | 
				
			||||||
target_link_libraries(ecs 
 | 
					target_link_libraries(ecs PUBLIC logger lt_debug memory)
 | 
				
			||||||
    PUBLIC logger lt_debug EnTT::EnTT camera math
 | 
					
 | 
				
			||||||
)
 | 
					add_test_module(ecs sparse_set.test.cpp registry.test.cpp)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +0,0 @@
 | 
				
			||||||
#include <ecs/entity.hpp>
 | 
					 | 
				
			||||||
#include <ecs/scene.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Entity::Entity(entt::entity handle, Scene *scene): m_handle(handle), m_scene(scene)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
							
								
								
									
										351
									
								
								modules/ecs/private/registry.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										351
									
								
								modules/ecs/private/registry.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,351 @@
 | 
				
			||||||
 | 
					#include <ecs/registry.hpp>
 | 
				
			||||||
 | 
					#include <ranges>
 | 
				
			||||||
 | 
					#include <test/expects.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using lt::test::Case;
 | 
				
			||||||
 | 
					using lt::test::expect_unreachable;
 | 
				
			||||||
 | 
					using lt::test::Suite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using lt::test::expect_eq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using lt::test::expect_false;
 | 
				
			||||||
 | 
					using lt::test::expect_true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using lt::ecs::EntityId;
 | 
				
			||||||
 | 
					using lt::ecs::Registry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Component
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int m_int {};
 | 
				
			||||||
 | 
						std::string m_string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] friend auto operator==(const Component &lhs, const Component &rhs) -> bool
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.m_int == rhs.m_int && lhs.m_string == rhs.m_string;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					template<>
 | 
				
			||||||
 | 
					struct std::formatter<Component>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						constexpr auto parse(std::format_parse_context &context)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return context.begin();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto format(const Component &val, std::format_context &context) const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return std::format_to(context.out(), "{}, {}", val.m_int, val.m_string);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Component_B
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						float m_float {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] friend auto operator==(const Component_B lhs, const Component_B &rhs) -> bool
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return lhs.m_float == rhs.m_float;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					template<>
 | 
				
			||||||
 | 
					struct std::formatter<Component_B>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						constexpr auto parse(std::format_parse_context &context)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return context.begin();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto format(const Component_B &val, std::format_context &context) const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return std::format_to(context.out(), "{}", val.m_float);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite raii = "raii"_suite = [] {
 | 
				
			||||||
 | 
						Case { "happy path won't throw" } = [] {
 | 
				
			||||||
 | 
							std::ignore = Registry {};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "many won't freeze/throw" } = [] {
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 100'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								std::ignore = Registry {};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "unhappy path throws" } = [] {
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "post construct has correct state" } = [] {
 | 
				
			||||||
 | 
							auto registry = Registry {};
 | 
				
			||||||
 | 
							expect_eq(registry.get_entity_count(), 0);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite entity_raii = "entity_raii"_suite = [] {
 | 
				
			||||||
 | 
						Case { "create_entity returns unique values" } = [] {
 | 
				
			||||||
 | 
							auto registry = Registry {};
 | 
				
			||||||
 | 
							auto set = std::unordered_set<EntityId> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								auto entity = registry.create_entity();
 | 
				
			||||||
 | 
								expect_false(set.contains(entity));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								set.insert(entity);
 | 
				
			||||||
 | 
								expect_eq(set.size(), idx + 1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "post create/destroy_entity has correct state" } = [] {
 | 
				
			||||||
 | 
							auto registry = Registry {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto entities = std::vector<EntityId> {};
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								entities.emplace_back(registry.create_entity());
 | 
				
			||||||
 | 
								expect_eq(registry.get_entity_count(), idx + 1);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								auto entity = entities.back();
 | 
				
			||||||
 | 
								registry.destroy_entity(entity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								entities.pop_back();
 | 
				
			||||||
 | 
								expect_eq(registry.get_entity_count(), 10'000 - (idx + 1));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite component_raii = "component_raii"_suite = [] {
 | 
				
			||||||
 | 
						Case { "add has correct state" } = [] {
 | 
				
			||||||
 | 
							auto registry = Registry {};
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 100'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								auto entity = registry.create_entity();
 | 
				
			||||||
 | 
								auto &component = registry.add<Component>(
 | 
				
			||||||
 | 
								    entity,
 | 
				
			||||||
 | 
								    { .m_int = idx, .m_string = std::to_string(idx) }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								expect_eq(component.m_int, idx);
 | 
				
			||||||
 | 
								expect_eq(component.m_string, std::to_string(idx));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "remove has correct state" } = [] {
 | 
				
			||||||
 | 
							auto registry = Registry {};
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 100'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								auto entity = registry.create_entity();
 | 
				
			||||||
 | 
								auto &component = registry.add<Component>(
 | 
				
			||||||
 | 
								    entity,
 | 
				
			||||||
 | 
								    { .m_int = idx, .m_string = std::to_string(idx) }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								expect_eq(component.m_int, idx);
 | 
				
			||||||
 | 
								expect_eq(component.m_string, std::to_string(idx));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite callbacks = "callbacks"_suite = [] {
 | 
				
			||||||
 | 
						Case { "connecting on_construct/on_destruct won't throw" } = [] {
 | 
				
			||||||
 | 
							auto registry = Registry {};
 | 
				
			||||||
 | 
							registry.connect_on_construct<Component>([&](Registry &, EntityId) {});
 | 
				
			||||||
 | 
							registry.connect_on_destruct<Component>([&](Registry &, EntityId) {});
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "on_construct/on_destruct won't get called on unrelated component" } = [] {
 | 
				
			||||||
 | 
							auto registry = Registry {};
 | 
				
			||||||
 | 
							registry.connect_on_construct<Component>([&](Registry &, EntityId) {
 | 
				
			||||||
 | 
								expect_unreachable();
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							registry.connect_on_destruct<Component>([&](Registry &, EntityId) {
 | 
				
			||||||
 | 
								expect_unreachable();
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 100'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								registry.add<Component_B>(registry.create_entity(), {});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "on_construct/on_destruct gets called" } = [] {
 | 
				
			||||||
 | 
							auto registry = Registry {};
 | 
				
			||||||
 | 
							auto all_entities = std::vector<EntityId> {};
 | 
				
			||||||
 | 
							auto on_construct_called = std::vector<EntityId> {};
 | 
				
			||||||
 | 
							auto on_destruct_called = std::vector<EntityId> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							registry.connect_on_construct<Component>([&](Registry &, EntityId entity) {
 | 
				
			||||||
 | 
								on_construct_called.emplace_back(entity);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							registry.connect_on_destruct<Component>([&](Registry &, EntityId entity) {
 | 
				
			||||||
 | 
								on_destruct_called.emplace_back(entity);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_true(on_construct_called.empty());
 | 
				
			||||||
 | 
							expect_true(on_destruct_called.empty());
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 100'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								auto entity = all_entities.emplace_back(registry.create_entity());
 | 
				
			||||||
 | 
								registry.add<Component>(entity, {});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							expect_eq(on_construct_called, all_entities);
 | 
				
			||||||
 | 
							expect_true(on_destruct_called.empty());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &entity : all_entities)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								registry.remove<Component>(entity);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							expect_eq(on_construct_called, all_entities);
 | 
				
			||||||
 | 
							expect_eq(on_destruct_called, all_entities);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite each = "each"_suite = [] {
 | 
				
			||||||
 | 
						auto registry = Registry {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto shared_entity_counter = 0u;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto component_map_a = std::unordered_map<EntityId, Component> {};
 | 
				
			||||||
 | 
						auto entities_a = std::vector<EntityId> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto entity = entities_a.emplace_back(registry.create_entity());
 | 
				
			||||||
 | 
							auto &component = registry.add<Component>(
 | 
				
			||||||
 | 
							    entity,
 | 
				
			||||||
 | 
							    { .m_int = idx, .m_string = std::to_string(idx) }
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							component_map_a[entity] = component;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto component_map_b = std::unordered_map<lt::ecs::EntityId, Component_B> {};
 | 
				
			||||||
 | 
						for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto entity = EntityId {};
 | 
				
			||||||
 | 
							if (idx % 3 == 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								entity = entities_a[idx];
 | 
				
			||||||
 | 
								++shared_entity_counter;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								entity = registry.create_entity();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							auto &component = registry.add<Component_B>(
 | 
				
			||||||
 | 
							    entity,
 | 
				
			||||||
 | 
							    { .m_float = static_cast<float>(idx) / 2.0f }
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							component_map_b[entity] = component;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "each one element" } = [&] {
 | 
				
			||||||
 | 
							auto counter = 0u;
 | 
				
			||||||
 | 
							registry.each<Component>([&](EntityId entity, Component &component) {
 | 
				
			||||||
 | 
								++counter;
 | 
				
			||||||
 | 
								expect_eq(component_map_a[entity], component);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_eq(component_map_a.size(), counter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							counter = 0u;
 | 
				
			||||||
 | 
							registry.each<Component_B>([&](EntityId entity, Component_B &component) {
 | 
				
			||||||
 | 
								++counter;
 | 
				
			||||||
 | 
								expect_eq(component_map_b[entity], component);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							expect_eq(component_map_b.size(), counter);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "each two element" } = [&] {
 | 
				
			||||||
 | 
							auto counter = 0u;
 | 
				
			||||||
 | 
							registry.each<Component, Component_B>(
 | 
				
			||||||
 | 
							    [&](EntityId entity, Component &component_a, Component_B &component_b) {
 | 
				
			||||||
 | 
								    expect_eq(component_map_a[entity], component_a);
 | 
				
			||||||
 | 
								    expect_eq(component_map_b[entity], component_b);
 | 
				
			||||||
 | 
								    ++counter;
 | 
				
			||||||
 | 
							    }
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_eq(counter, shared_entity_counter);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite views = "views"_suite = [] {
 | 
				
			||||||
 | 
						auto registry = Registry {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto shared_entity_counter = 0u;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto component_map_a = std::unordered_map<EntityId, Component> {};
 | 
				
			||||||
 | 
						auto entities_a = std::vector<EntityId> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto entity = entities_a.emplace_back(registry.create_entity());
 | 
				
			||||||
 | 
							auto &component = registry.add<Component>(
 | 
				
			||||||
 | 
							    entity,
 | 
				
			||||||
 | 
							    { .m_int = idx, .m_string = std::to_string(idx) }
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							component_map_a[entity] = component;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto component_map_b = std::unordered_map<EntityId, Component_B> {};
 | 
				
			||||||
 | 
						for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto entity = EntityId {};
 | 
				
			||||||
 | 
							if (idx % 3 == 0)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								entity = entities_a[idx];
 | 
				
			||||||
 | 
								++shared_entity_counter;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								entity = registry.create_entity();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							auto &component = registry.add<Component_B>(
 | 
				
			||||||
 | 
							    entity,
 | 
				
			||||||
 | 
							    { .m_float = static_cast<float>(idx) / 2.0f }
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							component_map_b[entity] = component;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "view one component" } = [&] {
 | 
				
			||||||
 | 
							for (const auto &[entity, component] : registry.view<Component>())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_eq(component_map_a[entity], component);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (const auto &[entity, component] : registry.view<Component_B>())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_eq(component_map_b[entity], component);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "view two component" } = [&] {
 | 
				
			||||||
 | 
							auto counter = 0u;
 | 
				
			||||||
 | 
							for (const auto &[entity, component, component_b] : registry.view<Component, Component_B>())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_eq(component_map_a[entity], component);
 | 
				
			||||||
 | 
								expect_eq(component_map_b[entity], component_b);
 | 
				
			||||||
 | 
								++counter;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							expect_eq(counter, shared_entity_counter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							counter = 0u;
 | 
				
			||||||
 | 
							for (const auto &[entity, component_b, component] : registry.view<Component_B, Component>())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_eq(component_map_b[entity], component_b);
 | 
				
			||||||
 | 
								expect_eq(component_map_a[entity], component);
 | 
				
			||||||
 | 
								++counter;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							expect_eq(counter, shared_entity_counter);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1,31 +0,0 @@
 | 
				
			||||||
#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
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,325 +0,0 @@
 | 
				
			||||||
#include <asset_manager/asset_manager.hpp>
 | 
					 | 
				
			||||||
#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<lt::math::vec3>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static auto encode(const lt::math::vec3 &rhs) -> Node
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		auto node = Node {};
 | 
					 | 
				
			||||||
		node.push_back(rhs.x);
 | 
					 | 
				
			||||||
		node.push_back(rhs.y);
 | 
					 | 
				
			||||||
		node.push_back(rhs.z);
 | 
					 | 
				
			||||||
		return node;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static auto decode(const Node &node, lt::math::vec3 &rhs) -> bool
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (!node.IsSequence() || node.size() != 3)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rhs.x = node[0].as<float>();
 | 
					 | 
				
			||||||
		rhs.y = node[1].as<float>();
 | 
					 | 
				
			||||||
		rhs.z = node[2].as<float>();
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct convert<lt::math::vec4>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static auto encode(const lt::math::vec4 &rhs) -> Node
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		auto node = Node {};
 | 
					 | 
				
			||||||
		node.push_back(rhs.x);
 | 
					 | 
				
			||||||
		node.push_back(rhs.y);
 | 
					 | 
				
			||||||
		node.push_back(rhs.z);
 | 
					 | 
				
			||||||
		node.push_back(rhs.w);
 | 
					 | 
				
			||||||
		return node;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static auto decode(const Node &node, lt::math::vec4 &rhs) -> bool
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (!node.IsSequence() || node.size() != 4)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rhs.x = node[0].as<float>();
 | 
					 | 
				
			||||||
		rhs.y = node[1].as<float>();
 | 
					 | 
				
			||||||
		rhs.z = node[2].as<float>();
 | 
					 | 
				
			||||||
		rhs.w = node[3].as<float>();
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
} // namespace YAML
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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 math::vec4 &v) -> YAML::Emitter &
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	out << YAML::Flow;
 | 
					 | 
				
			||||||
	out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq;
 | 
					 | 
				
			||||||
	return out;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SceneSerializer::SceneSerializer(const Ref<Scene> &scene): m_scene(scene)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneSerializer::serialize(const std::string &filePath)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	auto out = YAML::Emitter {};
 | 
					 | 
				
			||||||
	out << YAML::BeginMap; // Scene
 | 
					 | 
				
			||||||
	out << YAML::Key << "Scene" << YAML::Value << "Untitled";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	out << YAML::Key << "Entities" << YAML::Value << YAML::BeginSeq;
 | 
					 | 
				
			||||||
	for (auto [entityID, storage] : m_scene->m_registry.storage())
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		auto entity = Entity { static_cast<entt::entity>(entityID), m_scene.get() };
 | 
					 | 
				
			||||||
		if (!entity.is_valid())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		serialize_entity(out, entity);
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	out << YAML::EndSeq;
 | 
					 | 
				
			||||||
	out << YAML::EndMap;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::filesystem::create_directories(filePath.substr(0ull, filePath.find_last_of('\\')));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto fout = std::ofstream { filePath };
 | 
					 | 
				
			||||||
	if (!fout.is_open())
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_trc("Failed to create fout at: {}", filePath);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fout << out.c_str();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto SceneSerializer::deserialize(const std::string &file_path) -> bool
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	auto stream = std::ifstream { file_path };
 | 
					 | 
				
			||||||
	auto ss = std::stringstream {};
 | 
					 | 
				
			||||||
	ss << stream.rdbuf();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto data = YAML::Load(ss.str());
 | 
					 | 
				
			||||||
	if (!data["Scene"])
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return false;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto sceneName = data["Scene"].as<std::string>();
 | 
					 | 
				
			||||||
	log_trc("Deserializing scene: '{}'", sceneName);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto entities = data["Entities"];
 | 
					 | 
				
			||||||
	if (entities)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		auto texturePaths = std::unordered_set<std::string> {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (auto entity : entities)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			auto uuid = entity["entity"].as<uint64_t>(); // #todo
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			auto name = std::string {};
 | 
					 | 
				
			||||||
			auto tagComponent = entity["TagComponent"];
 | 
					 | 
				
			||||||
			if (tagComponent)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				name = tagComponent["Tag"].as<std::string>();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			log_trc("Deserialized entity '{}' : '{}'", uuid, name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			auto deserializedEntity = m_scene->create_entity_with_uuid(name, uuid);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			auto gg = deserializedEntity.get_component<TagComponent>();
 | 
					 | 
				
			||||||
			log_trc("tag: {}", gg.tag);
 | 
					 | 
				
			||||||
			auto transformComponent = entity["TransformComponent"];
 | 
					 | 
				
			||||||
			if (transformComponent)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				auto &entityTransforomComponent = deserializedEntity
 | 
					 | 
				
			||||||
				                                      .get_component<TransformComponent>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				entityTransforomComponent.translation = transformComponent["Translation"]
 | 
					 | 
				
			||||||
				                                            .as<math::vec3>();
 | 
					 | 
				
			||||||
				entityTransforomComponent.rotation = transformComponent["Rotation"]
 | 
					 | 
				
			||||||
				                                         .as<math::vec3>();
 | 
					 | 
				
			||||||
				entityTransforomComponent.scale = transformComponent["Scale"].as<math::vec3>();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* #TEMPORARY SOLUTION# */
 | 
					 | 
				
			||||||
			auto spriteRendererComponent = entity["SpriteRendererComponent"];
 | 
					 | 
				
			||||||
			if (spriteRendererComponent)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				auto &entitySpriteRendererComponent = deserializedEntity
 | 
					 | 
				
			||||||
				                                          .add_component<SpriteRendererComponent>();
 | 
					 | 
				
			||||||
				entitySpriteRendererComponent.tint = spriteRendererComponent["Tint"]
 | 
					 | 
				
			||||||
				                                         .as<math::vec4>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				auto texturePath = spriteRendererComponent["Texture"].as<std::string>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (!texturePaths.contains(texturePath))
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					AssetManager::load_texture(texturePath, texturePath);
 | 
					 | 
				
			||||||
					texturePaths.insert(texturePath);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				entitySpriteRendererComponent.texture = AssetManager::get_texture(texturePath);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			/* #TEMPORARY SOLUTION# */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			auto cameraComponent = entity["CameraComponent"];
 | 
					 | 
				
			||||||
			if (cameraComponent)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				auto &entityCameraComponent = deserializedEntity.add_component<CameraComponent>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				const auto &cameraSpecifications = cameraComponent["Camera"];
 | 
					 | 
				
			||||||
				entityCameraComponent.camera.set_projection_type(
 | 
					 | 
				
			||||||
				    (SceneCamera::ProjectionType)cameraSpecifications["ProjectionType"].as<int>()
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				entityCameraComponent.camera.set_orthographic_size(
 | 
					 | 
				
			||||||
				    cameraSpecifications["OrthographicSize"].as<float>()
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
				entityCameraComponent.camera.set_orthographic_near_plane(
 | 
					 | 
				
			||||||
				    cameraSpecifications["OrthographicNearPlane"].as<float>()
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
				entityCameraComponent.camera.set_orthographic_far_plane(
 | 
					 | 
				
			||||||
				    cameraSpecifications["OrthographicFarPlane"].as<float>()
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				entityCameraComponent.camera.set_perspective_vertical_fov(
 | 
					 | 
				
			||||||
				    cameraSpecifications["PerspectiveVerticalFOV"].as<float>()
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
				entityCameraComponent.camera.set_perspective_near_plane(
 | 
					 | 
				
			||||||
				    cameraSpecifications["PerspectiveNearPlane"].as<float>()
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
				entityCameraComponent.camera.set_perspective_far_plane(
 | 
					 | 
				
			||||||
				    cameraSpecifications["PerspectiveFarPlane"].as<float>()
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				entityCameraComponent.camera.set_background_color(
 | 
					 | 
				
			||||||
				    cameraSpecifications["BackgroundColor"].as<math::vec4>()
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				entityCameraComponent.isPrimary = cameraComponent["IsPrimary"].as<bool>();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return true;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneSerializer::serialize_binary(const std::string & /*filePath*/)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	log_err("NO_IMPLEMENT");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto SceneSerializer::deserialize_binary(const std::string & /*filePath*/) -> bool
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	log_err("NO_IMPLEMENT");
 | 
					 | 
				
			||||||
	return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void SceneSerializer::serialize_entity(YAML::Emitter &out, Entity entity)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	out << YAML::BeginMap;                                            // entity
 | 
					 | 
				
			||||||
	out << YAML::Key << "entity" << YAML::Value << entity.get_uuid(); // dummy uuid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (entity.has_component<TagComponent>())
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		out << YAML::Key << "TagComponent";
 | 
					 | 
				
			||||||
		out << YAML::BeginMap; // tag component
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto &tagComponent = entity.get_component<TagComponent>().tag;
 | 
					 | 
				
			||||||
		out << YAML::Key << "Tag" << YAML::Value << tagComponent;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		out << YAML::EndMap; // tag component
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (entity.has_component<TransformComponent>())
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		out << YAML::Key << "TransformComponent";
 | 
					 | 
				
			||||||
		out << YAML::BeginMap; // transform component
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto &transformComponent = entity.get_component<TransformComponent>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		out << YAML::Key << "Translation" << YAML::Value << transformComponent.translation;
 | 
					 | 
				
			||||||
		out << YAML::Key << "Rotation" << YAML::Value << transformComponent.rotation;
 | 
					 | 
				
			||||||
		out << YAML::Key << "Scale" << YAML::Value << transformComponent.scale;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		out << YAML::EndMap; // transform component;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (entity.has_component<SpriteRendererComponent>())
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// TODO(Light): get scene serialization/de-serialization working.
 | 
					 | 
				
			||||||
		// out << YAML::Key << "SpriteRendererComponent";
 | 
					 | 
				
			||||||
		// out << YAML::BeginMap; // sprite renderer component;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// auto &spriteRendererComponent = entity.get_component<SpriteRendererComponent>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// out << YAML::Key << "Texture" << YAML::Value
 | 
					 | 
				
			||||||
		//     << spriteRendererComponent.texture->GetFilePath();
 | 
					 | 
				
			||||||
		// out << YAML::Key << "Tint" << YAML::Value << spriteRendererComponent.tint;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// out << YAML::EndMap; // sprite renderer component
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// #todo:
 | 
					 | 
				
			||||||
	// if(entity.has_component<NativeScriptComponent>())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (entity.has_component<CameraComponent>())
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		out << YAML::Key << "CameraComponent";
 | 
					 | 
				
			||||||
		out << YAML::BeginMap; // camera component
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto &cameraComponent = entity.get_component<CameraComponent>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		out << YAML::Key << "Camera" << YAML::Value;
 | 
					 | 
				
			||||||
		out << YAML::BeginMap; // camera
 | 
					 | 
				
			||||||
		out << YAML::Key << "OrthographicSize" << YAML::Value
 | 
					 | 
				
			||||||
		    << cameraComponent.camera.get_orthographic_size();
 | 
					 | 
				
			||||||
		out << YAML::Key << "OrthographicFarPlane" << YAML::Value
 | 
					 | 
				
			||||||
		    << cameraComponent.camera.get_orthographic_far_plane();
 | 
					 | 
				
			||||||
		out << YAML::Key << "OrthographicNearPlane" << YAML::Value
 | 
					 | 
				
			||||||
		    << cameraComponent.camera.get_orthographic_near_plane();
 | 
					 | 
				
			||||||
		out << YAML::Key << "PerspectiveVerticalFOV" << YAML::Value
 | 
					 | 
				
			||||||
		    << cameraComponent.camera.get_perspective_vertical_fov();
 | 
					 | 
				
			||||||
		out << YAML::Key << "PerspectiveFarPlane" << YAML::Value
 | 
					 | 
				
			||||||
		    << cameraComponent.camera.get_perspective_far_plane();
 | 
					 | 
				
			||||||
		out << YAML::Key << "PerspectiveNearPlane" << YAML::Value
 | 
					 | 
				
			||||||
		    << cameraComponent.camera.get_perspective_near_plane();
 | 
					 | 
				
			||||||
		out << YAML::Key << "ProjectionType" << YAML::Value
 | 
					 | 
				
			||||||
		    << (int)cameraComponent.camera.get_projection_type();
 | 
					 | 
				
			||||||
		out << YAML::Key << "BackgroundColor" << YAML::Value
 | 
					 | 
				
			||||||
		    << cameraComponent.camera.get_background_color();
 | 
					 | 
				
			||||||
		out << YAML::EndMap; // camera
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		out << YAML::Key << "IsPrimary" << YAML::Value << cameraComponent.isPrimary;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		out << YAML::EndMap; // camera component
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	out << YAML::EndMap; // entity
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
							
								
								
									
										163
									
								
								modules/ecs/private/sparse_set.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								modules/ecs/private/sparse_set.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,163 @@
 | 
				
			||||||
 | 
					#include <ecs/sparse_set.hpp>
 | 
				
			||||||
 | 
					#include <ranges>
 | 
				
			||||||
 | 
					#include <test/expects.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using lt::test::Case;
 | 
				
			||||||
 | 
					using lt::test::Suite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using lt::test::expect_eq;
 | 
				
			||||||
 | 
					using lt::test::expect_false;
 | 
				
			||||||
 | 
					using lt::test::expect_ne;
 | 
				
			||||||
 | 
					using lt::test::expect_throw;
 | 
				
			||||||
 | 
					using lt::test::expect_true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Set = lt::ecs::SparseSet<int>;
 | 
				
			||||||
 | 
					constexpr auto capacity = 100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite raii = "raii"_suite = [] {
 | 
				
			||||||
 | 
						Case { "happy path won't throw" } = [] {
 | 
				
			||||||
 | 
							std::ignore = Set {};
 | 
				
			||||||
 | 
							std::ignore = Set { Set::max_capacity };
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "unhappy path throws" } = [] {
 | 
				
			||||||
 | 
							expect_throw([] { std::ignore = Set { Set::max_capacity + 1 }; });
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "post construct has correct state" } = [&] {
 | 
				
			||||||
 | 
							auto set = Set { capacity };
 | 
				
			||||||
 | 
							expect_eq(set.get_size(), 0);
 | 
				
			||||||
 | 
							expect_eq(set.get_capacity(), capacity);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite element_raii = "element_raii"_suite = [] {
 | 
				
			||||||
 | 
						Case { "many inserts/removes won't freeze/throw" } = [] {
 | 
				
			||||||
 | 
							auto set = Set {};
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								set.insert(idx, {});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								set.remove(idx);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "insert returns reference to inserted value" } = [] {
 | 
				
			||||||
 | 
							auto set = Set {};
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								const auto val = Set::Dense_T { idx, {} };
 | 
				
			||||||
 | 
								expect_eq(set.insert(val.first, val.second), val);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "post insert/remove has correct state" } = [] {
 | 
				
			||||||
 | 
							auto set = Set {};
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								set.insert(idx, idx * 2);
 | 
				
			||||||
 | 
								expect_eq(set.get_size(), idx + 1);
 | 
				
			||||||
 | 
								expect_eq(set.at(idx), Set::Dense_T { idx, idx * 2 });
 | 
				
			||||||
 | 
								expect_true(set.contains(idx));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_eq(set.at(idx), Set::Dense_T { idx, idx * 2 });
 | 
				
			||||||
 | 
								expect_true(set.contains(idx));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								set.remove(idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								expect_eq(set.get_size(), 10'000 - (idx + 1));
 | 
				
			||||||
 | 
								expect_false(set.contains(idx));
 | 
				
			||||||
 | 
								expect_throw([&] { std::ignore = set.at(idx); });
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "removed elements won't be iterated again" } = [] {
 | 
				
			||||||
 | 
							auto set = Set {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								set.insert(idx, idx);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							set.remove(0);
 | 
				
			||||||
 | 
							set.remove(32);
 | 
				
			||||||
 | 
							set.remove(69);
 | 
				
			||||||
 | 
							set.remove(420);
 | 
				
			||||||
 | 
							set.remove(9'999);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &[identifier, value] : set)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_eq(identifier, value);
 | 
				
			||||||
 | 
								expect_ne(value, 0);
 | 
				
			||||||
 | 
								expect_ne(value, 32);
 | 
				
			||||||
 | 
								expect_ne(value, 69);
 | 
				
			||||||
 | 
								expect_ne(value, 420);
 | 
				
			||||||
 | 
								expect_ne(value, 9'999);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite getters = "getters"_suite = [] {
 | 
				
			||||||
 | 
						Case { "get_size returns correct values" } = [] {
 | 
				
			||||||
 | 
							auto set = Set {};
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_eq(set.get_size(), idx);
 | 
				
			||||||
 | 
								set.insert(idx, {});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_eq(set.get_size(), 10'000);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "get_capacity returns correct values" } = [] {
 | 
				
			||||||
 | 
							auto set = Set { 10'000 };
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_eq(set.get_capacity(), 10'000); // are we testing std::vector's implementation?
 | 
				
			||||||
 | 
								set.insert(idx, {});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_eq(set.get_capacity(), 10'000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							set.insert(set.get_size(), {});
 | 
				
			||||||
 | 
							expect_ne(set.get_capacity(), 10'000);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "at throws with out of bound access" } = [] {
 | 
				
			||||||
 | 
							auto set = Set {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 50))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_throw([&] {
 | 
				
			||||||
 | 
									set.insert(idx, {});
 | 
				
			||||||
 | 
									std::ignore = set.at(50);
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							set.insert(50, {});
 | 
				
			||||||
 | 
							std::ignore = set.at(50); // should not throw
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite clear = "clear"_suite = [] {
 | 
				
			||||||
 | 
						Case { "post clear has correct state" } = [] {
 | 
				
			||||||
 | 
							auto set = Set { 0 };
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10'000))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								set.insert(idx, {});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							set.clear();
 | 
				
			||||||
 | 
							expect_eq(set.get_size(), 0);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
#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
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,6 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <ecs/components/native_script.hpp>
 | 
					 | 
				
			||||||
#include <ecs/components/sprite_renderer.hpp>
 | 
					 | 
				
			||||||
#include <ecs/components/tag.hpp>
 | 
					 | 
				
			||||||
#include <ecs/components/transform.hpp>
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,28 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <ecs/components/scriptable_entity.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct NativeScriptComponent
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	NativeScript *(*CreateInstance)();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void (*DestroyInstance)(NativeScriptComponent *);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	template<typename t>
 | 
					 | 
				
			||||||
	void bind()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		CreateInstance = []() {
 | 
					 | 
				
			||||||
			return static_cast<NativeScript *>(new t());
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		DestroyInstance = [](NativeScriptComponent *nsc) {
 | 
					 | 
				
			||||||
			delete (t *)(nsc->instance);
 | 
					 | 
				
			||||||
			nsc->instance = nullptr;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	NativeScript *instance;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,46 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <ecs/entity.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class NativeScript
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	friend class Scene;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	NativeScript() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	virtual ~NativeScript() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_uid() const -> unsigned int
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_unique_identifier;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	template<typename t>
 | 
					 | 
				
			||||||
	auto GetComponent() -> t &
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_entity.get_component<t>();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
protected:
 | 
					 | 
				
			||||||
	virtual void on_create()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	virtual void on_destroy()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	virtual void on_update(float ts)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	Entity m_entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	unsigned int m_unique_identifier = 0; // :#todo
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,35 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <math/vec4.hpp>
 | 
					 | 
				
			||||||
#include <utility>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Texture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct SpriteRendererComponent
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	SpriteRendererComponent() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SpriteRendererComponent(const SpriteRendererComponent &) = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SpriteRendererComponent(
 | 
					 | 
				
			||||||
	    Ref<Texture> _texture,
 | 
					 | 
				
			||||||
	    const math::vec4 &_tint = math::vec4 { 1.0f, 1.0f, 1.0f, 1.0f }
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	    : texture(std::move(std::move(_texture)))
 | 
					 | 
				
			||||||
	    , tint(_tint)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	operator Ref<Texture>() const
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return texture;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Ref<Texture> texture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	math::vec4 tint {};
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,30 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <utility>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct TagComponent
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	TagComponent() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	TagComponent(const TagComponent &) = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	TagComponent(std::string _tag): tag(std::move(_tag))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	operator std::string() const
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return tag;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	operator const std::string &() const
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return tag;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::string tag = "Unnamed";
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,43 +0,0 @@
 | 
				
			||||||
#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
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,18 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <ecs/uuid.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct UUIDComponent
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	UUIDComponent(UUID _uuid): uuid(_uuid)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	UUIDComponent(const UUIDComponent &) = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	UUID uuid;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,59 +1,54 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ecs/components/uuid.hpp>
 | 
					#include <ecs/registry.hpp>
 | 
				
			||||||
#include <ecs/scene.hpp>
 | 
					#include <memory/reference.hpp>
 | 
				
			||||||
#include <entt/entt.hpp>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt {
 | 
					namespace lt::ecs {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** High-level entity convenience wrapper */
 | 
				
			||||||
class Entity
 | 
					class Entity
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Entity(entt::entity handle = entt::null, Scene *scene = nullptr);
 | 
						Entity(memory::Ref<Registry> registry, EntityId identifier)
 | 
				
			||||||
 | 
						    : m_registry(std::move(registry))
 | 
				
			||||||
	template<typename t, typename... Args>
 | 
						    , m_identifier(identifier)
 | 
				
			||||||
	auto add_component(Args &&...args) -> t &
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return m_scene->m_registry.emplace<t>(m_handle, std::forward<Args>(args)...);
 | 
							ensure(m_registry, "Failed to create Entity ({}): null registry", m_identifier);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template<typename t>
 | 
						template<typename Component_T>
 | 
				
			||||||
	auto get_component() -> t &
 | 
						auto add(Component_T component) -> Component_T &
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return m_scene->m_registry.get<t>(m_handle);
 | 
							return m_registry->add(m_identifier, component);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template<typename t>
 | 
						template<typename Component_T>
 | 
				
			||||||
	auto has_component() -> bool
 | 
						auto get() -> Component_T &
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return m_scene->m_registry.any_of<t>(m_handle);
 | 
							return m_registry->get<Component_T>(m_identifier);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template<typename t>
 | 
						template<typename Component_T>
 | 
				
			||||||
	void remove_component()
 | 
						auto get() const -> const Component_T &
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		m_scene->m_registry.remove<t>(m_handle);
 | 
							return m_registry->get<Component_T>(m_identifier);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto get_uuid() -> uint64_t
 | 
						auto get_registry() -> memory::Ref<Registry>
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return get_component<UUIDComponent>().uuid;
 | 
							return m_registry;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] auto is_valid() const -> bool
 | 
						[[nodiscard]] auto id() const -> EntityId
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return m_handle != entt::null && m_scene != nullptr;
 | 
							return m_identifier;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	operator uint32_t()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return (uint32_t)m_handle;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	entt::entity m_handle;
 | 
						memory::Ref<Registry> m_registry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Scene *m_scene;
 | 
						EntityId m_identifier;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace lt
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::ecs
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										260
									
								
								modules/ecs/public/registry.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								modules/ecs/public/registry.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,260 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ecs/sparse_set.hpp>
 | 
				
			||||||
 | 
					#include <memory/scope.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::ecs {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using EntityId = uint32_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr auto null_entity = std::numeric_limits<EntityId>::max();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** A registry of components, the heart of an ECS architecture.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @todo(Light): Implement grouping
 | 
				
			||||||
 | 
					 * @todo(Light): Implement identifier recycling
 | 
				
			||||||
 | 
					 * @todo(Light): Optimize views/each
 | 
				
			||||||
 | 
					 * @todo(Light): Support >2 component views
 | 
				
			||||||
 | 
					 * @todo(Light): Handle more edge cases or specify the undefined behaviors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @ref https://skypjack.github.io/
 | 
				
			||||||
 | 
					 * @ref https://github.com/alecthomas/entityx
 | 
				
			||||||
 | 
					 * @ref https://github.com/skypjack/entt
 | 
				
			||||||
 | 
					 * @ref https://github.com/SanderMertens/flecs
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class Registry
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						using UnderlyingSparseSet_T = TypeErasedSparseSet<EntityId>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						using Callback_T = std::function<void(Registry &, EntityId)>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename Component_T>
 | 
				
			||||||
 | 
						void connect_on_construct(Callback_T callback)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_on_construct_hooks[get_type_id<Component_T>()] = callback;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename Component_T>
 | 
				
			||||||
 | 
						void connect_on_destruct(Callback_T callback)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_on_destruct_hooks[get_type_id<Component_T>()] = callback;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename Component_T>
 | 
				
			||||||
 | 
						void disconnect_on_construct()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_on_construct_hooks.erase(get_type_id<Component_T>());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename Component_T>
 | 
				
			||||||
 | 
						void disconnect_on_destruct()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_on_destruct_hooks.erase(get_type_id<Component_T>());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto create_entity() -> EntityId
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							++m_entity_count;
 | 
				
			||||||
 | 
							return m_current++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void destroy_entity(EntityId entity)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							for (const auto &[key, set] : m_sparsed_sets)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								set->remove(entity);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							--m_entity_count;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename Component_T>
 | 
				
			||||||
 | 
						auto get(EntityId entity) const -> const Component_T &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto &derived_set = get_derived_set<Component_T>();
 | 
				
			||||||
 | 
							return derived_set.at(entity).second;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename Component_T>
 | 
				
			||||||
 | 
						auto get(EntityId entity) -> Component_T &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto &derived_set = get_derived_set<Component_T>();
 | 
				
			||||||
 | 
							return derived_set.at(entity).second;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename Component_T>
 | 
				
			||||||
 | 
						auto add(EntityId entity, Component_T component) -> Component_T &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto &derived_set = get_derived_set<Component_T>();
 | 
				
			||||||
 | 
							auto &added_component = derived_set.insert(entity, std::move(component)).second;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (m_on_construct_hooks.contains(get_type_id<Component_T>()))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								m_on_construct_hooks[get_type_id<Component_T>()](*this, entity);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return added_component;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename Component_T>
 | 
				
			||||||
 | 
						void remove(EntityId entity)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (m_on_destruct_hooks.contains(get_type_id<Component_T>()))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								m_on_destruct_hooks[get_type_id<Component_T>()](*this, entity);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto &derived_set = get_derived_set<Component_T>();
 | 
				
			||||||
 | 
							derived_set.remove(entity);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename Component_T>
 | 
				
			||||||
 | 
						auto view() -> SparseSet<Component_T, EntityId> &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return get_derived_set<Component_T>();
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename ComponentA_T, typename ComponentB_T>
 | 
				
			||||||
 | 
						    requires(!std::is_same_v<ComponentA_T, ComponentB_T>)
 | 
				
			||||||
 | 
						auto view() -> std::vector<std::tuple<EntityId, ComponentA_T &, ComponentB_T &>>
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto &set_a = get_derived_set<ComponentA_T>();
 | 
				
			||||||
 | 
							auto &set_b = get_derived_set<ComponentB_T>();
 | 
				
			||||||
 | 
							auto view = std::vector<std::tuple<EntityId, ComponentA_T &, ComponentB_T &>> {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* iterate over the "smaller" component-set, and check if its entities have the other
 | 
				
			||||||
 | 
							 * component */
 | 
				
			||||||
 | 
							if (set_a.get_size() > set_b.get_size())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								for (auto &[entity, component_b] : set_b)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (set_a.contains(entity))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										view.emplace_back(std::tie(entity, set_a.at(entity).second, component_b));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								for (auto &[entity, component_a] : set_a)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (set_b.contains(entity))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										view.emplace_back(std::tie(entity, component_a, set_b.at(entity).second));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return view;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename Component_T>
 | 
				
			||||||
 | 
						void each(std::function<void(EntityId, Component_T &)> functor)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							for (auto &[entity, component] : get_derived_set<Component_T>())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								functor(entity, component);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename ComponentA_T, typename ComponentB_T>
 | 
				
			||||||
 | 
						    requires(!std::is_same_v<ComponentA_T, ComponentB_T>)
 | 
				
			||||||
 | 
						void each(std::function<void(EntityId, ComponentA_T &, ComponentB_T &)> functor)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto &set_a = get_derived_set<ComponentA_T>();
 | 
				
			||||||
 | 
							auto &set_b = get_derived_set<ComponentB_T>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* iterate over the "smaller" component-set, and check if its entities have the other
 | 
				
			||||||
 | 
							 * component */
 | 
				
			||||||
 | 
							if (set_a.get_size() > set_b.get_size())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								for (auto &[entity, component_b] : set_b)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (set_a.contains(entity))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										functor(entity, set_a.at(entity).second, component_b);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &[entity, component_a] : set_a)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (set_b.contains(entity))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									functor(entity, component_a, set_b.at(entity).second);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_entity_count() const -> size_t
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return static_cast<size_t>(m_entity_count);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						using TypeId = size_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static consteval auto hash_cstr(const char *str) -> TypeId
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							constexpr auto fnv_offset_basis = size_t { 14695981039346656037ull };
 | 
				
			||||||
 | 
							constexpr auto fnv_prime = size_t { 1099511628211ull };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto hash = fnv_offset_basis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (const auto &ch : std::string_view { str })
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								hash *= fnv_prime;
 | 
				
			||||||
 | 
								hash ^= static_cast<uint8_t>(ch);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return hash;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename T>
 | 
				
			||||||
 | 
						static consteval auto get_type_id() -> TypeId
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
					#if defined _MSC_VER
 | 
				
			||||||
 | 
						#define GENERATOR_PRETTY_FUNCTION __FUNCSIG__
 | 
				
			||||||
 | 
					#elif defined __clang__ || (defined __GNUC__)
 | 
				
			||||||
 | 
						#define GENERATOR_PRETTY_FUNCTION __PRETTY_FUNCTION__
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						#error "Compiler not supported"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							constexpr auto value = hash_cstr(GENERATOR_PRETTY_FUNCTION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef GENERATOR_PRETTY_FUNCTION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return value;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template<typename T>
 | 
				
			||||||
 | 
						auto get_derived_set() -> SparseSet<T, EntityId> &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							constexpr auto type_id = get_type_id<T>();
 | 
				
			||||||
 | 
							if (!m_sparsed_sets.contains(type_id))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								m_sparsed_sets[type_id] = memory::create_scope<SparseSet<T, EntityId>>();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto *base_set = m_sparsed_sets[type_id].get();
 | 
				
			||||||
 | 
							auto *derived_set = dynamic_cast<SparseSet<T, EntityId> *>(base_set);
 | 
				
			||||||
 | 
							ensure(derived_set, "Failed to downcast to derived set");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return *derived_set;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EntityId m_current;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TypeId m_entity_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::flat_map<TypeId, memory::Scope<UnderlyingSparseSet_T>> m_sparsed_sets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::flat_map<TypeId, Callback_T> m_on_construct_hooks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::flat_map<TypeId, Callback_T> m_on_destruct_hooks;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::ecs
 | 
				
			||||||
| 
						 | 
					@ -1,65 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <ecs/components/transform.hpp>
 | 
					 | 
				
			||||||
#include <ecs/uuid.hpp>
 | 
					 | 
				
			||||||
#include <entt/entt.hpp>
 | 
					 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Entity;
 | 
					 | 
				
			||||||
class Framebuffer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Scene
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	template<typename... T>
 | 
					 | 
				
			||||||
	auto group()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_registry.group(entt::get<T...>);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	template<typename T>
 | 
					 | 
				
			||||||
	auto view()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_registry.view<T>();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto create_entity(
 | 
					 | 
				
			||||||
	    const std::string &name,
 | 
					 | 
				
			||||||
	    const TransformComponent &transform = TransformComponent()
 | 
					 | 
				
			||||||
	) -> Entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto get_entity_by_tag(const std::string &tag) -> Entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto get_entt_registry() -> entt::registry &
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_registry;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	friend class Entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	friend class SceneSerializer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	friend class SceneHierarchyPanel;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	entt::registry m_registry;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto create_entity_with_uuid(
 | 
					 | 
				
			||||||
	    const std::string &name,
 | 
					 | 
				
			||||||
	    UUID uuid,
 | 
					 | 
				
			||||||
	    const TransformComponent &transform = TransformComponent()
 | 
					 | 
				
			||||||
	) -> Entity;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace ecs {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using Registry = Scene;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using Entity = ::lt::Entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace ecs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,34 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <ecs/entity.hpp>
 | 
					 | 
				
			||||||
#include <ecs/scene.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace YAML {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Emitter;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class SceneSerializer
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	SceneSerializer(const Ref<Scene> &scene);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void serialize(const std::string &filePath);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto deserialize(const std::string &file_path) -> bool;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void serialize_binary(const std::string &file_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto deserialize_binary(const std::string &file_path) -> bool;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	Ref<Scene> m_scene;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void serialize_entity(YAML::Emitter &out, Entity entity);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
							
								
								
									
										173
									
								
								modules/ecs/public/sparse_set.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								modules/ecs/public/sparse_set.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,173 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::ecs {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @ref https://programmingpraxis.com/2012/03/09/sparse-sets/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					template<typename Identifier_T = uint32_t>
 | 
				
			||||||
 | 
					class TypeErasedSparseSet
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						TypeErasedSparseSet() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TypeErasedSparseSet(TypeErasedSparseSet &&) = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						TypeErasedSparseSet(const TypeErasedSparseSet &) = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto operator=(TypeErasedSparseSet &&) -> TypeErasedSparseSet & = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto operator=(const TypeErasedSparseSet &) -> TypeErasedSparseSet & = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual ~TypeErasedSparseSet() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void remove(Identifier_T identifier) = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename Value_T, typename Identifier_T = uint32_t>
 | 
				
			||||||
 | 
					class SparseSet: public TypeErasedSparseSet<Identifier_T>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						using Dense_T = std::pair<Identifier_T, Value_T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static constexpr auto max_capacity = size_t { 1'000'000 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static constexpr auto null_identifier = std::numeric_limits<Identifier_T>().max();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						explicit SparseSet(size_t initial_capacity = 1)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ensure(
 | 
				
			||||||
 | 
							    initial_capacity <= max_capacity,
 | 
				
			||||||
 | 
							    "Failed to create SparseSet: capacity too large ({} > {})",
 | 
				
			||||||
 | 
							    initial_capacity,
 | 
				
			||||||
 | 
							    max_capacity
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m_dense.reserve(initial_capacity);
 | 
				
			||||||
 | 
							m_sparse.resize(initial_capacity, null_identifier);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto insert(Identifier_T identifier, Value_T value) -> Dense_T &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (m_sparse.size() < identifier + 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								auto new_capacity = std::max(static_cast<size_t>(identifier + 1), m_sparse.size() * 2);
 | 
				
			||||||
 | 
								new_capacity = std::min(new_capacity, max_capacity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// log::debug("Increasing sparse vector size:", m_dead_count);
 | 
				
			||||||
 | 
								// log::debug("\tdead_count: {}", m_dead_count);
 | 
				
			||||||
 | 
								// log::debug("\talive_count: {}", m_alive_count);
 | 
				
			||||||
 | 
								// log::debug("\tsparse.size: {} -> {}", m_sparse.size(), new_capacity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								m_sparse.resize(new_capacity, null_identifier);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							++m_alive_count;
 | 
				
			||||||
 | 
							m_sparse[identifier] = m_dense.size();
 | 
				
			||||||
 | 
							return m_dense.emplace_back(identifier, std::move(value));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** @warn invalidates begin/end iterators
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @todo(Light): make it not invalidate the iterators >:c
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void remove(Identifier_T identifier) override
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto &idx = m_sparse[identifier];
 | 
				
			||||||
 | 
							auto &[entity, component] = m_dense[idx];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto &[last_entity, last_component] = m_dense.back();
 | 
				
			||||||
 | 
							auto &last_idx = m_sparse[last_entity];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// removed entity is in dense's back, just pop and invalidate sparse[identifier]
 | 
				
			||||||
 | 
							if (entity == last_entity)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								idx = null_identifier;
 | 
				
			||||||
 | 
								m_dense.pop_back();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// swap dense's 'back' to 'removed'
 | 
				
			||||||
 | 
								std::swap(component, last_component);
 | 
				
			||||||
 | 
								entity = last_entity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// make sparse point to new idx
 | 
				
			||||||
 | 
								last_idx = idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// pop dense and invalidate sparse[identifier]
 | 
				
			||||||
 | 
								idx = null_identifier;
 | 
				
			||||||
 | 
								m_dense.pop_back();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							++m_dead_count;
 | 
				
			||||||
 | 
							--m_alive_count;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void clear()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_dense.clear();
 | 
				
			||||||
 | 
							m_sparse.clear();
 | 
				
			||||||
 | 
							m_alive_count = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto contains(Identifier_T identifier) const -> bool
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_sparse.size() > identifier               //
 | 
				
			||||||
 | 
							       && m_sparse[identifier] != null_identifier //
 | 
				
			||||||
 | 
							       && m_dense[m_sparse[identifier]].first == identifier;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto begin() -> std::vector<Dense_T>::iterator
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_dense.begin();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto end() -> std::vector<Dense_T>::iterator
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_dense.end();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto at(Identifier_T identifier) const -> const Dense_T &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_dense.at(m_sparse.at(identifier));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto at(Identifier_T identifier) -> Dense_T &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_dense.at(m_sparse.at(identifier));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** @warn unsafe, for bound-checked access: use `.at` */
 | 
				
			||||||
 | 
						[[nodiscard]] auto &&operator[](this auto &&self, Identifier_T identifier)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							using Self_T = decltype(self);
 | 
				
			||||||
 | 
							return std::forward<Self_T>(self).m_dense[std::forward<Self_T>(self).m_sparse[identifier]];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_size() const noexcept -> size_t
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_alive_count;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_capacity() const noexcept -> size_t
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_sparse.capacity();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto is_empty() const noexcept -> bool
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_dense.empty();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						std::vector<Dense_T> m_dense;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::vector<Identifier_T> m_sparse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t m_alive_count {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t m_dead_count {};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::ecs
 | 
				
			||||||
| 
						 | 
					@ -1,38 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <random>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class UUID
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	UUID(uint64_t uuid = -1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	operator uint64_t() const
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return m_uuid;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	static std::mt19937_64 s_engine;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static std::uniform_int_distribution<uint64_t> s_distribution;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint64_t m_uuid;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace std {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template<>
 | 
					 | 
				
			||||||
struct hash<lt::UUID>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	std::size_t operator()(const lt::UUID &uuid) const
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return hash<uint64_t>()(static_cast<uint64_t>(uuid));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace std
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								modules/env/CMakeLists.txt
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								modules/env/CMakeLists.txt
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					add_library_module(env)
 | 
				
			||||||
							
								
								
									
										68
									
								
								modules/env/public/constants.hpp
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								modules/env/public/constants.hpp
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,68 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class Platform : uint8_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/** The GNU/Linux platform.
 | 
				
			||||||
 | 
						 * Tested on the following distros: arch-x86_64
 | 
				
			||||||
 | 
						 * @note: Named like so because `linux` is a built-in identifier.
 | 
				
			||||||
 | 
						 * */
 | 
				
			||||||
 | 
						gnu_linux,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * The Microsoft Windows(tm) platform.
 | 
				
			||||||
 | 
						 * Tested on the following architectures: x86_64
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						windows,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * The apple's macOS platform.
 | 
				
			||||||
 | 
						 * Currently not supported.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						mac,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** The compiler that was used for compiling the project. */
 | 
				
			||||||
 | 
					enum class Compiler : uint8_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						clang,
 | 
				
			||||||
 | 
						gcc,
 | 
				
			||||||
 | 
						msvc,
 | 
				
			||||||
 | 
						apple_clang,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace constants {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(LIGHT_PLATFORM_WINDOWS)
 | 
				
			||||||
 | 
						#define lt_win(x)
 | 
				
			||||||
 | 
					constexpr auto platform = Platform::windows;
 | 
				
			||||||
 | 
					constexpr auto platform_name = "windows";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#undef LIGHT_PLATFORM_WINDOWS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(LIGHT_PLATFORM_LINUX)
 | 
				
			||||||
 | 
					constexpr auto platform = Platform::gnu_linux;
 | 
				
			||||||
 | 
					constexpr auto platform_name = "gnu_linux";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(LIGHT_PLATFORM_MAC)
 | 
				
			||||||
 | 
						#define lt_mac(x) x
 | 
				
			||||||
 | 
					constexpr auto platform = Platform::mac;
 | 
				
			||||||
 | 
					constexpr auto platform_name = "mac";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						#error "Unsupported platform: Unknown"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __clang__
 | 
				
			||||||
 | 
					constexpr auto compiler = Compiler::clang;
 | 
				
			||||||
 | 
					constexpr auto compiler_name = "clang";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** @todo(Light): insert the full identifier, including version information and such */
 | 
				
			||||||
 | 
					constexpr auto full_compiler_identifier = "clang";
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace constants
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
add_library_module(input system.cpp)
 | 
					add_library_module(input system.cpp)
 | 
				
			||||||
target_link_libraries(input PUBLIC surface math  logger)
 | 
					target_link_libraries(input PUBLIC surface math logger tbb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_test_module(input system.test.cpp)
 | 
					add_test_module(input system.test.cpp)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#include <input/components.hpp>
 | 
					#include <input/components.hpp>
 | 
				
			||||||
#include <input/system.hpp>
 | 
					#include <input/system.hpp>
 | 
				
			||||||
 | 
					#include <memory/reference.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::input {
 | 
					namespace lt::input {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,22 +10,23 @@ struct overloads: Ts...
 | 
				
			||||||
	using Ts::operator()...;
 | 
						using Ts::operator()...;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
System::System(Ref<ecs::Registry> registry): m_registry(std::move(registry))
 | 
					System::System(memory::Ref<ecs::Registry> registry): m_registry(std::move(registry))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ensure(m_registry, "Failed to initialize input system: null registry");
 | 
						ensure(m_registry, "Failed to initialize input system: null registry");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto System::tick() -> bool
 | 
					void System::tick(app::TickInfo tick)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						for (auto &[entity, surface] : m_registry->view<surface::SurfaceComponent>())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	m_registry->view<surface::SurfaceComponent>().each([&](const entt::entity,
 | 
					 | 
				
			||||||
	                                                       surface::SurfaceComponent &surface) {
 | 
					 | 
				
			||||||
		for (const auto &event : surface.peek_events())
 | 
							for (const auto &event : surface.peek_events())
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			handle_event(event);
 | 
								handle_event(event);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	});
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_registry->view<InputComponent>().each([&](const entt::entity, InputComponent &input) {
 | 
						for (auto &[entity, input] : m_registry->view<InputComponent>())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
		// TODO(Light): instead of iterating over all actions each frame,
 | 
							// TODO(Light): instead of iterating over all actions each frame,
 | 
				
			||||||
		// make a list of "dirty" actions to reset
 | 
							// make a list of "dirty" actions to reset
 | 
				
			||||||
		// and a surface_input->input_action mapping to get to action through input
 | 
							// and a surface_input->input_action mapping to get to action through input
 | 
				
			||||||
| 
						 | 
					@ -48,9 +50,14 @@ auto System::tick() -> bool
 | 
				
			||||||
				action.state = InputAction::State::inactive;
 | 
									action.state = InputAction::State::inactive;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	});
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return false;
 | 
						const auto now = std::chrono::steady_clock::now();
 | 
				
			||||||
 | 
						m_last_tick_result = app::TickResult {
 | 
				
			||||||
 | 
							.info = tick,
 | 
				
			||||||
 | 
							.duration = now - tick.start_time,
 | 
				
			||||||
 | 
							.end_time = now,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void System::on_register()
 | 
					void System::on_register()
 | 
				
			||||||
| 
						 | 
					@ -94,7 +101,7 @@ void System::on_key_press(const lt::surface::KeyPressedEvent &event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (event.get_key() > m_keys.size())
 | 
						if (event.get_key() > m_keys.size())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		log_dbg(
 | 
							log::debug(
 | 
				
			||||||
		    "Key code larger than key container size, implement platform-dependant "
 | 
							    "Key code larger than key container size, implement platform-dependant "
 | 
				
			||||||
		    "key-code-mapping!"
 | 
							    "key-code-mapping!"
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
| 
						 | 
					@ -109,7 +116,7 @@ void System::on_key_release(const lt::surface::KeyReleasedEvent &event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (event.get_key() > m_keys.size())
 | 
						if (event.get_key() > m_keys.size())
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		log_dbg(
 | 
							log::debug(
 | 
				
			||||||
		    "Key code larger than key container size, implement platform-dependant "
 | 
							    "Key code larger than key container size, implement platform-dependant "
 | 
				
			||||||
		    "key-code-mapping!"
 | 
							    "key-code-mapping!"
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		
		Reference in a new issue